]> Pileus Git - ~andy/gtk/blob - gtk/gtkfilechooserdefault.c
GtkFileChooser search fixes and recent files support. (#435342)
[~andy/gtk] / gtk / gtkfilechooserdefault.c
1 /* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */
2 /* GTK - The GIMP Toolkit
3  * gtkfilechooserdefault.c: Default implementation of GtkFileChooser
4  * Copyright (C) 2003, Red Hat, Inc.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #include <config.h>
23 #include "gdk/gdkkeysyms.h"
24 #include "gtkalignment.h"
25 #include "gtkbindings.h"
26 #include "gtkbutton.h"
27 #include "gtkcelllayout.h"
28 #include "gtkcellrendererpixbuf.h"
29 #include "gtkcellrenderertext.h"
30 #include "gtkcheckmenuitem.h"
31 #include "gtkclipboard.h"
32 #include "gtkcombobox.h"
33 #include "gtkentry.h"
34 #include "gtkeventbox.h"
35 #include "gtkexpander.h"
36 #include "gtkfilechooserprivate.h"
37 #include "gtkfilechooserdefault.h"
38 #include "gtkfilechooserembed.h"
39 #include "gtkfilechooserentry.h"
40 #include "gtkfilechoosersettings.h"
41 #include "gtkfilechooserutils.h"
42 #include "gtkfilechooser.h"
43 #include "gtkfilesystemmodel.h"
44 #include "gtkframe.h"
45 #include "gtkhbox.h"
46 #include "gtkhpaned.h"
47 #include "gtkiconfactory.h"
48 #include "gtkicontheme.h"
49 #include "gtkimage.h"
50 #include "gtkimagemenuitem.h"
51 #include "gtkintl.h"
52 #include "gtklabel.h"
53 #include "gtkmarshalers.h"
54 #include "gtkmenuitem.h"
55 #include "gtkmessagedialog.h"
56 #include "gtkpathbar.h"
57 #include "gtkprivate.h"
58 #include "gtkradiobutton.h"
59 #include "gtkrecentfilter.h"
60 #include "gtkrecentmanager.h"
61 #include "gtkscrolledwindow.h"
62 #include "gtkseparatormenuitem.h"
63 #include "gtksizegroup.h"
64 #include "gtkstock.h"
65 #include "gtktable.h"
66 #include "gtktreednd.h"
67 #include "gtktreeprivate.h"
68 #include "gtktreeselection.h"
69 #include "gtktypebuiltins.h"
70 #include "gtkvbox.h"
71
72 #if defined (G_OS_UNIX)
73 #include "gtkfilesystemunix.h"
74 #elif defined (G_OS_WIN32)
75 #include "gtkfilesystemwin32.h"
76 #endif
77
78 #include "gtkalias.h"
79
80 #include <errno.h>
81 #include <string.h>
82 #include <time.h>
83 #include <sys/stat.h>
84 #include <sys/types.h>
85
86
87 #ifdef HAVE_UNISTD_H
88 #include <unistd.h>
89 #endif
90 #ifdef G_OS_WIN32
91 #include <io.h>
92 #endif
93
94 /* Profiling stuff */
95 #undef PROFILE_FILE_CHOOSER
96 #ifdef PROFILE_FILE_CHOOSER
97
98
99 #ifndef F_OK 
100 #define F_OK 0
101 #endif
102
103 #define PROFILE_INDENT 4
104 static int profile_indent;
105
106 static void
107 profile_add_indent (int indent)
108 {
109   profile_indent += indent;
110   if (profile_indent < 0)
111     g_error ("You screwed up your indentation");
112 }
113
114 void
115 _gtk_file_chooser_profile_log (const char *func, int indent, const char *msg1, const char *msg2)
116 {
117   char *str;
118
119   if (indent < 0)
120     profile_add_indent (indent);
121
122   if (profile_indent == 0)
123     str = g_strdup_printf ("MARK: %s %s %s", func ? func : "", msg1 ? msg1 : "", msg2 ? msg2 : "");
124   else
125     str = g_strdup_printf ("MARK: %*c %s %s %s", profile_indent - 1, ' ', func ? func : "", msg1 ? msg1 : "", msg2 ? msg2 : "");
126
127   access (str, F_OK);
128   g_free (str);
129
130   if (indent > 0)
131     profile_add_indent (indent);
132 }
133
134 #define profile_start(x, y) _gtk_file_chooser_profile_log (G_STRFUNC, PROFILE_INDENT, x, y)
135 #define profile_end(x, y) _gtk_file_chooser_profile_log (G_STRFUNC, -PROFILE_INDENT, x, y)
136 #define profile_msg(x, y) _gtk_file_chooser_profile_log (NULL, 0, x, y)
137 #else
138 #define profile_start(x, y)
139 #define profile_end(x, y)
140 #define profile_msg(x, y)
141 #endif
142
143
144
145 typedef struct _GtkFileChooserDefaultClass GtkFileChooserDefaultClass;
146
147 #define GTK_FILE_CHOOSER_DEFAULT_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_FILE_CHOOSER_DEFAULT, GtkFileChooserDefaultClass))
148 #define GTK_IS_FILE_CHOOSER_DEFAULT_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_FILE_CHOOSER_DEFAULT))
149 #define GTK_FILE_CHOOSER_DEFAULT_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_FILE_CHOOSER_DEFAULT, GtkFileChooserDefaultClass))
150
151 #define MAX_LOADING_TIME 500
152
153 struct _GtkFileChooserDefaultClass
154 {
155   GtkVBoxClass parent_class;
156 };
157
158 /* Signal IDs */
159 enum {
160   LOCATION_POPUP,
161   LOCATION_POPUP_ON_PASTE,
162   UP_FOLDER,
163   DOWN_FOLDER,
164   HOME_FOLDER,
165   DESKTOP_FOLDER,
166   QUICK_BOOKMARK,
167   LOCATION_TOGGLE_POPUP,
168   SHOW_HIDDEN,
169   SEARCH_SHORTCUT,
170   RECENT_SHORTCUT,
171
172   LAST_SIGNAL
173 };
174
175 static guint signals[LAST_SIGNAL] = { 0 };
176
177 /* Column numbers for the shortcuts tree.  Keep these in sync with shortcuts_model_create() */
178 enum {
179   SHORTCUTS_COL_PIXBUF,
180   SHORTCUTS_COL_NAME,
181   SHORTCUTS_COL_DATA,
182   SHORTCUTS_COL_TYPE,
183   SHORTCUTS_COL_REMOVABLE,
184   SHORTCUTS_COL_PIXBUF_VISIBLE,
185   SHORTCUTS_COL_HANDLE,
186   SHORTCUTS_COL_NUM_COLUMNS
187 };
188
189 typedef enum {
190   SHORTCUT_TYPE_PATH,
191   SHORTCUT_TYPE_VOLUME,
192   SHORTCUT_TYPE_SEPARATOR,
193   SHORTCUT_TYPE_SEARCH,
194   SHORTCUT_TYPE_RECENT
195 } ShortcutType;
196
197 /* Column numbers for the file list */
198 enum {
199   FILE_LIST_COL_NAME,
200   FILE_LIST_COL_SIZE,
201   FILE_LIST_COL_MTIME,
202   FILE_LIST_COL_NUM_COLUMNS
203 };
204
205 /* Column numbers for the search model.  
206  * Keep this in sync with search_setup_model() 
207  */
208 enum {
209   SEARCH_MODEL_COL_PATH,
210   SEARCH_MODEL_COL_DISPLAY_NAME,
211   SEARCH_MODEL_COL_COLLATION_KEY,
212   SEARCH_MODEL_COL_STAT,
213   SEARCH_MODEL_COL_HANDLE,
214   SEARCH_MODEL_COL_PIXBUF,
215   SEARCH_MODEL_COL_MIME_TYPE,
216   SEARCH_MODEL_COL_IS_FOLDER,
217   SEARCH_MODEL_COL_NUM_COLUMNS
218 };
219
220 enum {
221   RECENT_MODEL_COL_PATH,
222   RECENT_MODEL_COL_DISPLAY_NAME,
223   RECENT_MODEL_COL_INFO,
224   RECENT_MODEL_COL_IS_FOLDER,
225   RECENT_MODEL_COL_HANDLE,
226   RECENT_MODEL_COL_NUM_COLUMNS
227 };
228
229 /* Identifiers for target types */
230 enum {
231   GTK_TREE_MODEL_ROW,
232   TEXT_URI_LIST
233 };
234
235 /* Target types for dragging from the shortcuts list */
236 static const GtkTargetEntry shortcuts_source_targets[] = {
237   { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, GTK_TREE_MODEL_ROW }
238 };
239
240 static const int num_shortcuts_source_targets = G_N_ELEMENTS (shortcuts_source_targets); 
241
242 /* Target types for dropping into the shortcuts list */
243 static const GtkTargetEntry shortcuts_dest_targets[] = {
244   { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, GTK_TREE_MODEL_ROW },
245   { "text/uri-list", 0, TEXT_URI_LIST }
246 };
247
248 static const int num_shortcuts_dest_targets = G_N_ELEMENTS (shortcuts_dest_targets); 
249
250 /* Target types for DnD from the file list */
251 static const GtkTargetEntry file_list_source_targets[] = {
252   { "text/uri-list", 0, TEXT_URI_LIST }
253 };
254
255 static const int num_file_list_source_targets = G_N_ELEMENTS (file_list_source_targets); 
256
257 /* Target types for dropping into the file list */
258 static const GtkTargetEntry file_list_dest_targets[] = {
259   { "text/uri-list", 0, TEXT_URI_LIST }
260 };
261
262 static const int num_file_list_dest_targets = G_N_ELEMENTS (file_list_dest_targets); 
263
264 static gboolean
265 search_is_possible (GtkFileChooserDefault *impl)
266 {
267   if (impl->search_engine == NULL)
268     impl->search_engine = _gtk_search_engine_new ();
269   
270   return impl->search_engine != NULL;
271 }
272
273 /* Interesting places in the shortcuts bar */
274 typedef enum {
275   SHORTCUTS_SEARCH,
276   SHORTCUTS_SEARCH_SEPARATOR,
277   SHORTCUTS_RECENT,
278   SHORTCUTS_RECENT_SEPARATOR,
279   SHORTCUTS_HOME,
280   SHORTCUTS_DESKTOP,
281   SHORTCUTS_VOLUMES,
282   SHORTCUTS_SHORTCUTS,
283   SHORTCUTS_BOOKMARKS_SEPARATOR,
284   SHORTCUTS_BOOKMARKS,
285   SHORTCUTS_CURRENT_FOLDER_SEPARATOR,
286   SHORTCUTS_CURRENT_FOLDER
287 } ShortcutsIndex;
288
289 /* Icon size for if we can't get it from the theme */
290 #define FALLBACK_ICON_SIZE 16
291
292 #define PREVIEW_HBOX_SPACING 12
293 #define NUM_LINES 45
294 #define NUM_CHARS 60
295
296 static void gtk_file_chooser_default_iface_init       (GtkFileChooserIface        *iface);
297 static void gtk_file_chooser_embed_default_iface_init (GtkFileChooserEmbedIface   *iface);
298
299 static GObject* gtk_file_chooser_default_constructor  (GType                  type,
300                                                        guint                  n_construct_properties,
301                                                        GObjectConstructParam *construct_params);
302 static void     gtk_file_chooser_default_finalize     (GObject               *object);
303 static void     gtk_file_chooser_default_set_property (GObject               *object,
304                                                        guint                  prop_id,
305                                                        const GValue          *value,
306                                                        GParamSpec            *pspec);
307 static void     gtk_file_chooser_default_get_property (GObject               *object,
308                                                        guint                  prop_id,
309                                                        GValue                *value,
310                                                        GParamSpec            *pspec);
311 static void     gtk_file_chooser_default_dispose      (GObject               *object);
312 static void     gtk_file_chooser_default_show_all       (GtkWidget             *widget);
313 static void     gtk_file_chooser_default_map            (GtkWidget             *widget);
314 static void     gtk_file_chooser_default_unmap          (GtkWidget             *widget);
315 static void     gtk_file_chooser_default_hierarchy_changed (GtkWidget          *widget,
316                                                             GtkWidget          *previous_toplevel);
317 static void     gtk_file_chooser_default_style_set      (GtkWidget             *widget,
318                                                          GtkStyle              *previous_style);
319 static void     gtk_file_chooser_default_screen_changed (GtkWidget             *widget,
320                                                          GdkScreen             *previous_screen);
321
322 static gboolean       gtk_file_chooser_default_set_current_folder          (GtkFileChooser    *chooser,
323                                                                             const GtkFilePath *path,
324                                                                             GError           **error);
325 static gboolean       gtk_file_chooser_default_update_current_folder       (GtkFileChooser    *chooser,
326                                                                             const GtkFilePath *path,
327                                                                             gboolean           keep_trail,
328                                                                             gboolean           clear_entry,
329                                                                             GError           **error);
330 static GtkFilePath *  gtk_file_chooser_default_get_current_folder          (GtkFileChooser    *chooser);
331 static void           gtk_file_chooser_default_set_current_name            (GtkFileChooser    *chooser,
332                                                                             const gchar       *name);
333 static gboolean       gtk_file_chooser_default_select_path                 (GtkFileChooser    *chooser,
334                                                                             const GtkFilePath *path,
335                                                                             GError           **error);
336 static void           gtk_file_chooser_default_unselect_path               (GtkFileChooser    *chooser,
337                                                                             const GtkFilePath *path);
338 static void           gtk_file_chooser_default_select_all                  (GtkFileChooser    *chooser);
339 static void           gtk_file_chooser_default_unselect_all                (GtkFileChooser    *chooser);
340 static GSList *       gtk_file_chooser_default_get_paths                   (GtkFileChooser    *chooser);
341 static GtkFilePath *  gtk_file_chooser_default_get_preview_path            (GtkFileChooser    *chooser);
342 static GtkFileSystem *gtk_file_chooser_default_get_file_system             (GtkFileChooser    *chooser);
343 static void           gtk_file_chooser_default_add_filter                  (GtkFileChooser    *chooser,
344                                                                             GtkFileFilter     *filter);
345 static void           gtk_file_chooser_default_remove_filter               (GtkFileChooser    *chooser,
346                                                                             GtkFileFilter     *filter);
347 static GSList *       gtk_file_chooser_default_list_filters                (GtkFileChooser    *chooser);
348 static gboolean       gtk_file_chooser_default_add_shortcut_folder    (GtkFileChooser    *chooser,
349                                                                        const GtkFilePath *path,
350                                                                        GError           **error);
351 static gboolean       gtk_file_chooser_default_remove_shortcut_folder (GtkFileChooser    *chooser,
352                                                                        const GtkFilePath *path,
353                                                                        GError           **error);
354 static GSList *       gtk_file_chooser_default_list_shortcut_folders  (GtkFileChooser    *chooser);
355
356 static void           gtk_file_chooser_default_get_default_size       (GtkFileChooserEmbed *chooser_embed,
357                                                                        gint                *default_width,
358                                                                        gint                *default_height);
359 static void           gtk_file_chooser_default_get_resizable_hints    (GtkFileChooserEmbed *chooser_embed,
360                                                                        gboolean            *resize_horizontally,
361                                                                        gboolean            *resize_vertically);
362 static gboolean       gtk_file_chooser_default_should_respond         (GtkFileChooserEmbed *chooser_embed);
363 static void           gtk_file_chooser_default_initial_focus          (GtkFileChooserEmbed *chooser_embed);
364
365 static void location_popup_handler  (GtkFileChooserDefault *impl,
366                                      const gchar           *path);
367 static void location_popup_on_paste_handler (GtkFileChooserDefault *impl);
368 static void location_toggle_popup_handler   (GtkFileChooserDefault *impl);
369 static void up_folder_handler       (GtkFileChooserDefault *impl);
370 static void down_folder_handler     (GtkFileChooserDefault *impl);
371 static void home_folder_handler     (GtkFileChooserDefault *impl);
372 static void desktop_folder_handler  (GtkFileChooserDefault *impl);
373 static void quick_bookmark_handler  (GtkFileChooserDefault *impl,
374                                      gint                   bookmark_index);
375 static void show_hidden_handler     (GtkFileChooserDefault *impl);
376 static void search_shortcut_handler (GtkFileChooserDefault *impl);
377 static void recent_shortcut_handler (GtkFileChooserDefault *impl);
378 static void update_appearance       (GtkFileChooserDefault *impl);
379
380 static void set_current_filter   (GtkFileChooserDefault *impl,
381                                   GtkFileFilter         *filter);
382 static void check_preview_change (GtkFileChooserDefault *impl);
383
384 static void filter_combo_changed       (GtkComboBox           *combo_box,
385                                         GtkFileChooserDefault *impl);
386 static void     shortcuts_row_activated_cb (GtkTreeView           *tree_view,
387                                             GtkTreePath           *path,
388                                             GtkTreeViewColumn     *column,
389                                             GtkFileChooserDefault *impl);
390
391 static gboolean shortcuts_key_press_event_cb (GtkWidget             *widget,
392                                               GdkEventKey           *event,
393                                               GtkFileChooserDefault *impl);
394
395 static gboolean shortcuts_select_func   (GtkTreeSelection      *selection,
396                                          GtkTreeModel          *model,
397                                          GtkTreePath           *path,
398                                          gboolean               path_currently_selected,
399                                          gpointer               data);
400 static gboolean shortcuts_get_selected  (GtkFileChooserDefault *impl,
401                                          GtkTreeIter           *iter);
402 static void shortcuts_activate_iter (GtkFileChooserDefault *impl,
403                                      GtkTreeIter           *iter);
404 static int shortcuts_get_index (GtkFileChooserDefault *impl,
405                                 ShortcutsIndex         where);
406 static int shortcut_find_position (GtkFileChooserDefault *impl,
407                                    const GtkFilePath     *path);
408
409 static void bookmarks_check_add_sensitivity (GtkFileChooserDefault *impl);
410
411 static gboolean list_select_func   (GtkTreeSelection      *selection,
412                                     GtkTreeModel          *model,
413                                     GtkTreePath           *path,
414                                     gboolean               path_currently_selected,
415                                     gpointer               data);
416
417 static void list_selection_changed     (GtkTreeSelection      *tree_selection,
418                                         GtkFileChooserDefault *impl);
419 static void list_row_activated         (GtkTreeView           *tree_view,
420                                         GtkTreePath           *path,
421                                         GtkTreeViewColumn     *column,
422                                         GtkFileChooserDefault *impl);
423
424 static void select_func (GtkFileSystemModel *model,
425                          GtkTreePath        *path,
426                          GtkTreeIter        *iter,
427                          gpointer            user_data);
428
429 static void path_bar_clicked (GtkPathBar            *path_bar,
430                               GtkFilePath           *file_path,
431                               GtkFilePath           *child_path,
432                               gboolean               child_is_hidden,
433                               GtkFileChooserDefault *impl);
434
435 static void add_bookmark_button_clicked_cb    (GtkButton             *button,
436                                                GtkFileChooserDefault *impl);
437 static void remove_bookmark_button_clicked_cb (GtkButton             *button,
438                                                GtkFileChooserDefault *impl);
439 static void save_folder_combo_changed_cb      (GtkComboBox           *combo,
440                                                GtkFileChooserDefault *impl);
441
442 static void list_icon_data_func (GtkTreeViewColumn *tree_column,
443                                  GtkCellRenderer   *cell,
444                                  GtkTreeModel      *tree_model,
445                                  GtkTreeIter       *iter,
446                                  gpointer           data);
447 static void list_name_data_func (GtkTreeViewColumn *tree_column,
448                                  GtkCellRenderer   *cell,
449                                  GtkTreeModel      *tree_model,
450                                  GtkTreeIter       *iter,
451                                  gpointer           data);
452 #if 0
453 static void list_size_data_func (GtkTreeViewColumn *tree_column,
454                                  GtkCellRenderer   *cell,
455                                  GtkTreeModel      *tree_model,
456                                  GtkTreeIter       *iter,
457                                  gpointer           data);
458 #endif
459 static void list_mtime_data_func (GtkTreeViewColumn *tree_column,
460                                   GtkCellRenderer   *cell,
461                                   GtkTreeModel      *tree_model,
462                                   GtkTreeIter       *iter,
463                                   gpointer           data);
464
465 static const GtkFileInfo *get_list_file_info (GtkFileChooserDefault *impl,
466                                               GtkTreeIter           *iter);
467
468 static void load_remove_timer (GtkFileChooserDefault *impl);
469 static void browse_files_center_selected_row (GtkFileChooserDefault *impl);
470
471 static void location_button_toggled_cb (GtkToggleButton *toggle,
472                                         GtkFileChooserDefault *impl);
473 static void location_switch_to_path_bar (GtkFileChooserDefault *impl);
474
475 static void     search_stop_searching        (GtkFileChooserDefault *impl,
476                                               gboolean               remove_query);
477 static void     search_clear_model           (GtkFileChooserDefault *impl, 
478                                               gboolean               remove_from_treeview);
479 static gboolean search_should_respond        (GtkFileChooserDefault *impl);
480 static void     search_switch_to_browse_mode (GtkFileChooserDefault *impl);
481 static GSList  *search_get_selected_paths    (GtkFileChooserDefault *impl);
482 static void     search_entry_activate_cb     (GtkEntry              *entry, 
483                                               gpointer               data);
484
485 static void     recent_manager_update        (GtkFileChooserDefault *impl);
486 static void     recent_stop_loading          (GtkFileChooserDefault *impl);
487 static void     recent_clear_model           (GtkFileChooserDefault *impl,
488                                               gboolean               remove_from_treeview);
489 static gboolean recent_should_respond        (GtkFileChooserDefault *impl);
490 static void     recent_switch_to_browse_mode (GtkFileChooserDefault *impl);
491 static GSList * recent_get_selected_paths    (GtkFileChooserDefault *impl);
492
493 \f
494
495 /* Drag and drop interface declarations */
496
497 typedef struct {
498   GtkTreeModelFilter parent;
499
500   GtkFileChooserDefault *impl;
501 } ShortcutsPaneModelFilter;
502
503 typedef struct {
504   GtkTreeModelFilterClass parent_class;
505 } ShortcutsPaneModelFilterClass;
506
507 #define SHORTCUTS_PANE_MODEL_FILTER_TYPE (_shortcuts_pane_model_filter_get_type ())
508 #define SHORTCUTS_PANE_MODEL_FILTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SHORTCUTS_PANE_MODEL_FILTER_TYPE, ShortcutsPaneModelFilter))
509
510 static void shortcuts_pane_model_filter_drag_source_iface_init (GtkTreeDragSourceIface *iface);
511
512 G_DEFINE_TYPE_WITH_CODE (ShortcutsPaneModelFilter,
513                          _shortcuts_pane_model_filter,
514                          GTK_TYPE_TREE_MODEL_FILTER,
515                          G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_SOURCE,
516                                                 shortcuts_pane_model_filter_drag_source_iface_init))
517
518 static GtkTreeModel *shortcuts_pane_model_filter_new (GtkFileChooserDefault *impl,
519                                                       GtkTreeModel          *child_model,
520                                                       GtkTreePath           *root);
521
522
523
524 G_DEFINE_TYPE_WITH_CODE (GtkFileChooserDefault, _gtk_file_chooser_default, GTK_TYPE_VBOX,
525                          G_IMPLEMENT_INTERFACE (GTK_TYPE_FILE_CHOOSER,
526                                                 gtk_file_chooser_default_iface_init)
527                          G_IMPLEMENT_INTERFACE (GTK_TYPE_FILE_CHOOSER_EMBED,
528                                                 gtk_file_chooser_embed_default_iface_init));                                            
529
530 static void
531 _gtk_file_chooser_default_class_init (GtkFileChooserDefaultClass *class)
532 {
533   static const guint quick_bookmark_keyvals[10] = {
534     GDK_1, GDK_2, GDK_3, GDK_4, GDK_5, GDK_6, GDK_7, GDK_8, GDK_9, GDK_0
535   };
536   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
537   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
538   GtkBindingSet *binding_set;
539   int i;
540
541   gobject_class->finalize = gtk_file_chooser_default_finalize;
542   gobject_class->constructor = gtk_file_chooser_default_constructor;
543   gobject_class->set_property = gtk_file_chooser_default_set_property;
544   gobject_class->get_property = gtk_file_chooser_default_get_property;
545   gobject_class->dispose = gtk_file_chooser_default_dispose;
546
547   widget_class->show_all = gtk_file_chooser_default_show_all;
548   widget_class->map = gtk_file_chooser_default_map;
549   widget_class->unmap = gtk_file_chooser_default_unmap;
550   widget_class->hierarchy_changed = gtk_file_chooser_default_hierarchy_changed;
551   widget_class->style_set = gtk_file_chooser_default_style_set;
552   widget_class->screen_changed = gtk_file_chooser_default_screen_changed;
553
554   signals[LOCATION_POPUP] =
555     _gtk_binding_signal_new (I_("location-popup"),
556                              G_OBJECT_CLASS_TYPE (class),
557                              G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
558                              G_CALLBACK (location_popup_handler),
559                              NULL, NULL,
560                              _gtk_marshal_VOID__STRING,
561                              G_TYPE_NONE, 1, G_TYPE_STRING);
562   signals[LOCATION_POPUP_ON_PASTE] =
563     _gtk_binding_signal_new ("location-popup-on-paste",
564                              G_OBJECT_CLASS_TYPE (class),
565                              G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
566                              G_CALLBACK (location_popup_on_paste_handler),
567                              NULL, NULL,
568                              _gtk_marshal_VOID__VOID,
569                              G_TYPE_NONE, 0);
570   signals[LOCATION_TOGGLE_POPUP] =
571     _gtk_binding_signal_new (I_("location-toggle-popup"),
572                              G_OBJECT_CLASS_TYPE (class),
573                              G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
574                              G_CALLBACK (location_toggle_popup_handler),
575                              NULL, NULL,
576                              _gtk_marshal_VOID__VOID,
577                              G_TYPE_NONE, 0);
578   signals[UP_FOLDER] =
579     _gtk_binding_signal_new (I_("up-folder"),
580                              G_OBJECT_CLASS_TYPE (class),
581                              G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
582                              G_CALLBACK (up_folder_handler),
583                              NULL, NULL,
584                              _gtk_marshal_VOID__VOID,
585                              G_TYPE_NONE, 0);
586   signals[DOWN_FOLDER] =
587     _gtk_binding_signal_new (I_("down-folder"),
588                              G_OBJECT_CLASS_TYPE (class),
589                              G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
590                              G_CALLBACK (down_folder_handler),
591                              NULL, NULL,
592                              _gtk_marshal_VOID__VOID,
593                              G_TYPE_NONE, 0);
594   signals[HOME_FOLDER] =
595     _gtk_binding_signal_new (I_("home-folder"),
596                              G_OBJECT_CLASS_TYPE (class),
597                              G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
598                              G_CALLBACK (home_folder_handler),
599                              NULL, NULL,
600                              _gtk_marshal_VOID__VOID,
601                              G_TYPE_NONE, 0);
602   signals[DESKTOP_FOLDER] =
603     _gtk_binding_signal_new (I_("desktop-folder"),
604                              G_OBJECT_CLASS_TYPE (class),
605                              G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
606                              G_CALLBACK (desktop_folder_handler),
607                              NULL, NULL,
608                              _gtk_marshal_VOID__VOID,
609                              G_TYPE_NONE, 0);
610   signals[QUICK_BOOKMARK] =
611     _gtk_binding_signal_new (I_("quick-bookmark"),
612                              G_OBJECT_CLASS_TYPE (class),
613                              G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
614                              G_CALLBACK (quick_bookmark_handler),
615                              NULL, NULL,
616                              _gtk_marshal_VOID__INT,
617                              G_TYPE_NONE, 1, G_TYPE_INT);
618   signals[SHOW_HIDDEN] =
619     _gtk_binding_signal_new ("show-hidden",
620                              G_OBJECT_CLASS_TYPE (class),
621                              G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
622                              G_CALLBACK (show_hidden_handler),
623                              NULL, NULL,
624                              _gtk_marshal_VOID__VOID,
625                              G_TYPE_NONE, 0);
626   signals[SEARCH_SHORTCUT] =
627     _gtk_binding_signal_new ("search-shortcut",
628                              G_OBJECT_CLASS_TYPE (class),
629                              G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
630                              G_CALLBACK (search_shortcut_handler),
631                              NULL, NULL,
632                              _gtk_marshal_VOID__VOID,
633                              G_TYPE_NONE, 0);
634   signals[RECENT_SHORTCUT] =
635     _gtk_binding_signal_new ("recent-shortcut",
636                              G_OBJECT_CLASS_TYPE (class),
637                              G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
638                              G_CALLBACK (recent_shortcut_handler),
639                              NULL, NULL,
640                              _gtk_marshal_VOID__VOID,
641                              G_TYPE_NONE, 0);
642
643   binding_set = gtk_binding_set_by_class (class);
644
645   gtk_binding_entry_add_signal (binding_set,
646                                 GDK_l, GDK_CONTROL_MASK,
647                                 "location-toggle-popup",
648                                 0);
649
650   gtk_binding_entry_add_signal (binding_set,
651                                 GDK_slash, 0,
652                                 "location-popup",
653                                 1, G_TYPE_STRING, "/");
654   gtk_binding_entry_add_signal (binding_set,
655                                 GDK_KP_Divide, 0,
656                                 "location-popup",
657                                 1, G_TYPE_STRING, "/");
658
659 #ifdef G_OS_UNIX
660   gtk_binding_entry_add_signal (binding_set,
661                                 GDK_asciitilde, 0,
662                                 "location-popup",
663                                 1, G_TYPE_STRING, "~");
664 #endif
665
666   gtk_binding_entry_add_signal (binding_set,
667                                 GDK_v, GDK_CONTROL_MASK,
668                                 "location-popup-on-paste",
669                                 0);
670   gtk_binding_entry_add_signal (binding_set,
671                                 GDK_Up, GDK_MOD1_MASK,
672                                 "up-folder",
673                                 0);
674   gtk_binding_entry_add_signal (binding_set,
675                                 GDK_BackSpace, 0,
676                                 "up-folder",
677                                 0);
678   gtk_binding_entry_add_signal (binding_set,
679                                 GDK_KP_Up, GDK_MOD1_MASK,
680                                 "up-folder",
681                                 0);
682
683   gtk_binding_entry_add_signal (binding_set,
684                                 GDK_Down, GDK_MOD1_MASK,
685                                 "down-folder",
686                                 0);
687   gtk_binding_entry_add_signal (binding_set,
688                                 GDK_KP_Down, GDK_MOD1_MASK,
689                                 "down-folder",
690                                 0);
691
692   gtk_binding_entry_add_signal (binding_set,
693                                 GDK_Home, GDK_MOD1_MASK,
694                                 "home-folder",
695                                 0);
696   gtk_binding_entry_add_signal (binding_set,
697                                 GDK_KP_Home, GDK_MOD1_MASK,
698                                 "home-folder",
699                                 0);
700   gtk_binding_entry_add_signal (binding_set,
701                                 GDK_d, GDK_MOD1_MASK,
702                                 "desktop-folder",
703                                 0);
704   gtk_binding_entry_add_signal (binding_set,
705                                 GDK_h, GDK_CONTROL_MASK,
706                                 "show-hidden",
707                                 0);
708   gtk_binding_entry_add_signal (binding_set,
709                                 GDK_s, GDK_MOD1_MASK,
710                                 "search-shortcut",
711                                 0);
712   gtk_binding_entry_add_signal (binding_set,
713                                 GDK_r, GDK_MOD1_MASK,
714                                 "recent-shortcut",
715                                 0);
716
717   for (i = 0; i < 10; i++)
718     gtk_binding_entry_add_signal (binding_set,
719                                   quick_bookmark_keyvals[i], GDK_MOD1_MASK,
720                                   "quick-bookmark",
721                                   1, G_TYPE_INT, i);
722
723   _gtk_file_chooser_install_properties (gobject_class);
724 }
725
726 static void
727 gtk_file_chooser_default_iface_init (GtkFileChooserIface *iface)
728 {
729   iface->select_path = gtk_file_chooser_default_select_path;
730   iface->unselect_path = gtk_file_chooser_default_unselect_path;
731   iface->select_all = gtk_file_chooser_default_select_all;
732   iface->unselect_all = gtk_file_chooser_default_unselect_all;
733   iface->get_paths = gtk_file_chooser_default_get_paths;
734   iface->get_preview_path = gtk_file_chooser_default_get_preview_path;
735   iface->get_file_system = gtk_file_chooser_default_get_file_system;
736   iface->set_current_folder = gtk_file_chooser_default_set_current_folder;
737   iface->get_current_folder = gtk_file_chooser_default_get_current_folder;
738   iface->set_current_name = gtk_file_chooser_default_set_current_name;
739   iface->add_filter = gtk_file_chooser_default_add_filter;
740   iface->remove_filter = gtk_file_chooser_default_remove_filter;
741   iface->list_filters = gtk_file_chooser_default_list_filters;
742   iface->add_shortcut_folder = gtk_file_chooser_default_add_shortcut_folder;
743   iface->remove_shortcut_folder = gtk_file_chooser_default_remove_shortcut_folder;
744   iface->list_shortcut_folders = gtk_file_chooser_default_list_shortcut_folders;
745 }
746
747 static void
748 gtk_file_chooser_embed_default_iface_init (GtkFileChooserEmbedIface *iface)
749 {
750   iface->get_default_size = gtk_file_chooser_default_get_default_size;
751   iface->get_resizable_hints = gtk_file_chooser_default_get_resizable_hints;
752   iface->should_respond = gtk_file_chooser_default_should_respond;
753   iface->initial_focus = gtk_file_chooser_default_initial_focus;
754 }
755
756 static void
757 _gtk_file_chooser_default_init (GtkFileChooserDefault *impl)
758 {
759   profile_start ("start", NULL);
760 #ifdef PROFILE_FILE_CHOOSER
761   access ("MARK: *** CREATE FILE CHOOSER", F_OK);
762 #endif
763   impl->local_only = TRUE;
764   impl->preview_widget_active = TRUE;
765   impl->use_preview_label = TRUE;
766   impl->select_multiple = FALSE;
767   impl->show_hidden = FALSE;
768   impl->icon_size = FALLBACK_ICON_SIZE;
769   impl->load_state = LOAD_EMPTY;
770   impl->reload_state = RELOAD_EMPTY;
771   impl->pending_select_paths = NULL;
772   impl->location_mode = LOCATION_MODE_PATH_BAR;
773   impl->operation_mode = OPERATION_MODE_BROWSE;
774
775   gtk_box_set_spacing (GTK_BOX (impl), 12);
776
777   impl->tooltips = gtk_tooltips_new ();
778   g_object_ref_sink (impl->tooltips);
779
780   profile_end ("end", NULL);
781 }
782
783 /* Frees the data columns for the specified iter in the shortcuts model*/
784 static void
785 shortcuts_free_row_data (GtkFileChooserDefault *impl,
786                          GtkTreeIter           *iter)
787 {
788   gpointer col_data;
789   ShortcutType shortcut_type;
790   GtkFileSystemHandle *handle;
791
792   gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), iter,
793                       SHORTCUTS_COL_DATA, &col_data,
794                       SHORTCUTS_COL_TYPE, &shortcut_type,
795                       SHORTCUTS_COL_HANDLE, &handle,
796                       -1);
797
798   if (handle)
799     gtk_file_system_cancel_operation (handle);
800
801   if (!(shortcut_type == SHORTCUT_TYPE_PATH || 
802         shortcut_type == SHORTCUT_TYPE_VOLUME) ||
803       !col_data)
804     return;
805
806   if (shortcut_type == SHORTCUT_TYPE_VOLUME)
807     {
808       GtkFileSystemVolume *volume;
809
810       volume = col_data;
811       gtk_file_system_volume_free (impl->file_system, volume);
812     }
813   else
814     {
815       GtkFilePath *path;
816
817       g_assert (shortcut_type == SHORTCUT_TYPE_PATH);
818
819       path = col_data;
820       gtk_file_path_free (path);
821     }
822 }
823
824 /* Frees all the data columns in the shortcuts model */
825 static void
826 shortcuts_free (GtkFileChooserDefault *impl)
827 {
828   GtkTreeIter iter;
829
830   if (!impl->shortcuts_model)
831     return;
832
833   if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (impl->shortcuts_model), &iter))
834     do
835       {
836         shortcuts_free_row_data (impl, &iter);
837       }
838     while (gtk_tree_model_iter_next (GTK_TREE_MODEL (impl->shortcuts_model), &iter));
839
840   g_object_unref (impl->shortcuts_model);
841   impl->shortcuts_model = NULL;
842 }
843
844 static void
845 pending_select_paths_free (GtkFileChooserDefault *impl)
846 {
847   GSList *l;
848
849   for (l = impl->pending_select_paths; l; l = l->next)
850     {
851       GtkFilePath *path;
852
853       path = l->data;
854       gtk_file_path_free (path);
855     }
856
857   g_slist_free (impl->pending_select_paths);
858   impl->pending_select_paths = NULL;
859 }
860
861 static void
862 pending_select_paths_add (GtkFileChooserDefault *impl,
863                           const GtkFilePath     *path)
864 {
865   impl->pending_select_paths =
866     g_slist_prepend (impl->pending_select_paths, gtk_file_path_copy (path));
867 }
868
869 /* Used from gtk_tree_selection_selected_foreach() */
870 static void
871 store_selection_foreach (GtkTreeModel *model,
872                          GtkTreePath  *path,
873                          GtkTreeIter  *iter,
874                          gpointer      data)
875 {
876   GtkFileChooserDefault *impl;
877   GtkTreeIter child_iter;
878   const GtkFilePath *file_path;
879
880   impl = GTK_FILE_CHOOSER_DEFAULT (data);
881
882   gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model, &child_iter, iter);
883
884   file_path = _gtk_file_system_model_get_path (impl->browse_files_model, &child_iter);
885   pending_select_paths_add (impl, file_path);
886 }
887
888 /* Stores the current selection in the list of paths to select; this is used to
889  * preserve the selection when reloading the current folder.
890  */
891 static void
892 pending_select_paths_store_selection (GtkFileChooserDefault *impl)
893 {
894   GtkTreeSelection *selection;
895
896   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
897   gtk_tree_selection_selected_foreach (selection, store_selection_foreach, impl);
898 }
899
900 static void
901 gtk_file_chooser_default_finalize (GObject *object)
902 {
903   GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (object);
904   GSList *l;
905
906   if (impl->shortcuts_pane_filter_model)
907     g_object_unref (impl->shortcuts_pane_filter_model);
908
909   if (impl->shortcuts_combo_filter_model)
910     g_object_unref (impl->shortcuts_combo_filter_model);
911
912   shortcuts_free (impl);
913
914   g_object_unref (impl->file_system);
915
916   g_free (impl->browse_files_last_selected_name);
917
918   for (l = impl->filters; l; l = l->next)
919     {
920       GtkFileFilter *filter;
921
922       filter = GTK_FILE_FILTER (l->data);
923       g_object_unref (filter);
924     }
925   g_slist_free (impl->filters);
926
927   if (impl->current_filter)
928     g_object_unref (impl->current_filter);
929
930   if (impl->current_volume_path)
931     gtk_file_path_free (impl->current_volume_path);
932
933   if (impl->current_folder)
934     gtk_file_path_free (impl->current_folder);
935
936   if (impl->preview_path)
937     gtk_file_path_free (impl->preview_path);
938
939   load_remove_timer (impl);
940
941   /* Free all the Models we have */
942   if (impl->browse_files_model)
943     g_object_unref (impl->browse_files_model);
944
945   if (impl->sort_model)
946     g_object_unref (impl->sort_model);
947
948   search_clear_model (impl, FALSE);
949   recent_clear_model (impl, FALSE);
950
951   g_free (impl->preview_display_name);
952
953   g_free (impl->edited_new_text);
954
955   g_object_unref (impl->tooltips);
956
957   G_OBJECT_CLASS (_gtk_file_chooser_default_parent_class)->finalize (object);
958 }
959
960 /* Shows an error dialog set as transient for the specified window */
961 static void
962 error_message_with_parent (GtkWindow  *parent,
963                            const char *msg,
964                            const char *detail)
965 {
966   GtkWidget *dialog;
967
968   dialog = gtk_message_dialog_new (parent,
969                                    GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
970                                    GTK_MESSAGE_ERROR,
971                                    GTK_BUTTONS_OK,
972                                    "%s",
973                                    msg);
974   gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
975                                             "%s", detail);
976
977   if (parent->group)
978     gtk_window_group_add_window (parent->group, GTK_WINDOW (dialog));
979
980   gtk_dialog_run (GTK_DIALOG (dialog));
981   gtk_widget_destroy (dialog);
982 }
983
984 /* Returns a toplevel GtkWindow, or NULL if none */
985 static GtkWindow *
986 get_toplevel (GtkWidget *widget)
987 {
988   GtkWidget *toplevel;
989
990   toplevel = gtk_widget_get_toplevel (widget);
991   if (!GTK_WIDGET_TOPLEVEL (toplevel))
992     return NULL;
993   else
994     return GTK_WINDOW (toplevel);
995 }
996
997 /* Shows an error dialog for the file chooser */
998 static void
999 error_message (GtkFileChooserDefault *impl,
1000                const char            *msg,
1001                const char            *detail)
1002 {
1003   error_message_with_parent (get_toplevel (GTK_WIDGET (impl)), msg, detail);
1004 }
1005
1006 /* Shows a simple error dialog relative to a path.  Frees the GError as well. */
1007 static void
1008 error_dialog (GtkFileChooserDefault *impl,
1009               const char            *msg,
1010               const GtkFilePath     *path,
1011               GError                *error)
1012 {
1013   if (G_LIKELY (error))
1014     {
1015       char *uri = NULL;
1016       char *text;
1017
1018       if (path)
1019         uri = gtk_file_system_path_to_uri (impl->file_system, path);
1020       text = g_strdup_printf (msg, uri);
1021       error_message (impl, text, error->message);
1022       g_free (text);
1023       g_free (uri);
1024       g_error_free (error);
1025     }
1026 }
1027
1028 /* Displays an error message about not being able to get information for a file.
1029  * Frees the GError as well.
1030  */
1031 static void
1032 error_getting_info_dialog (GtkFileChooserDefault *impl,
1033                            const GtkFilePath     *path,
1034                            GError                *error)
1035 {
1036   error_dialog (impl,
1037                 _("Could not retrieve information about the file"),
1038                 path, error);
1039 }
1040
1041 /* Shows an error dialog about not being able to add a bookmark */
1042 static void
1043 error_adding_bookmark_dialog (GtkFileChooserDefault *impl,
1044                               const GtkFilePath     *path,
1045                               GError                *error)
1046 {
1047   error_dialog (impl,
1048                 _("Could not add a bookmark"),
1049                 path, error);
1050 }
1051
1052 /* Shows an error dialog about not being able to remove a bookmark */
1053 static void
1054 error_removing_bookmark_dialog (GtkFileChooserDefault *impl,
1055                                 const GtkFilePath     *path,
1056                                 GError                *error)
1057 {
1058   error_dialog (impl,
1059                 _("Could not remove bookmark"),
1060                 path, error);
1061 }
1062
1063 /* Shows an error dialog about not being able to create a folder */
1064 static void
1065 error_creating_folder_dialog (GtkFileChooserDefault *impl,
1066                               const GtkFilePath     *path,
1067                               GError                *error)
1068 {
1069   error_dialog (impl, 
1070                 _("The folder could not be created"), 
1071                 path, error);
1072 }
1073
1074 /* Shows an error about not being able to create a folder because a file with
1075  * the same name is already there.
1076  */
1077 static void
1078 error_creating_folder_over_existing_file_dialog (GtkFileChooserDefault *impl,
1079                                                  const GtkFilePath     *path,
1080                                                  GError                *error)
1081 {
1082   error_dialog (impl,
1083                 _("The folder could not be created, as a file with the same "
1084                   "name already exists.  Try using a different name for the "
1085                   "folder, or rename the file first."),
1086                 path, error);
1087 }
1088
1089 /* Shows an error dialog about not being able to create a filename */
1090 static void
1091 error_building_filename_dialog (GtkFileChooserDefault *impl,
1092                                 const GtkFilePath     *folder_part,
1093                                 const char            *file_part,
1094                                 GError                *error)
1095 {
1096   error_dialog (impl, _("Invalid file name"), 
1097                 NULL, error);
1098 }
1099
1100 /* Shows an error dialog when we cannot switch to a folder */
1101 static void
1102 error_changing_folder_dialog (GtkFileChooserDefault *impl,
1103                               const GtkFilePath     *path,
1104                               GError                *error)
1105 {
1106   error_dialog (impl, _("The folder contents could not be displayed"),
1107                 path, error);
1108 }
1109
1110 /* Changes folders, displaying an error dialog if this fails */
1111 static gboolean
1112 change_folder_and_display_error (GtkFileChooserDefault *impl,
1113                                  const GtkFilePath     *path,
1114                                  gboolean               clear_entry)
1115 {
1116   GError *error;
1117   gboolean result;
1118   GtkFilePath *path_copy;
1119
1120   g_return_val_if_fail (path != NULL, FALSE);
1121
1122   profile_start ("start", (char *) path);
1123
1124   /* We copy the path because of this case:
1125    *
1126    * list_row_activated()
1127    *   fetches path from model; path belongs to the model (*)
1128    *   calls change_folder_and_display_error()
1129    *     calls _gtk_file_chooser_set_current_folder_path()
1130    *       changing folders fails, sets model to NULL, thus freeing the path in (*)
1131    */
1132
1133   path_copy = gtk_file_path_copy (path);
1134
1135   error = NULL;
1136   result = gtk_file_chooser_default_update_current_folder (GTK_FILE_CHOOSER (impl), path_copy, TRUE, clear_entry, &error);
1137
1138   if (!result)
1139     error_changing_folder_dialog (impl, path_copy, error);
1140
1141   gtk_file_path_free (path_copy);
1142
1143   profile_end ("end", (char *) path);
1144
1145   return result;
1146 }
1147
1148 static void
1149 update_preview_widget_visibility (GtkFileChooserDefault *impl)
1150 {
1151   if (impl->use_preview_label)
1152     {
1153       if (!impl->preview_label)
1154         {
1155           impl->preview_label = gtk_label_new (impl->preview_display_name);
1156           gtk_box_pack_start (GTK_BOX (impl->preview_box), impl->preview_label, FALSE, FALSE, 0);
1157           gtk_box_reorder_child (GTK_BOX (impl->preview_box), impl->preview_label, 0);
1158           gtk_label_set_ellipsize (GTK_LABEL (impl->preview_label), PANGO_ELLIPSIZE_MIDDLE);
1159           gtk_widget_show (impl->preview_label);
1160         }
1161     }
1162   else
1163     {
1164       if (impl->preview_label)
1165         {
1166           gtk_widget_destroy (impl->preview_label);
1167           impl->preview_label = NULL;
1168         }
1169     }
1170
1171   if (impl->preview_widget_active && impl->preview_widget)
1172     gtk_widget_show (impl->preview_box);
1173   else
1174     gtk_widget_hide (impl->preview_box);
1175
1176   g_signal_emit_by_name (impl, "default-size-changed");
1177 }
1178
1179 static void
1180 set_preview_widget (GtkFileChooserDefault *impl,
1181                     GtkWidget             *preview_widget)
1182 {
1183   if (preview_widget == impl->preview_widget)
1184     return;
1185
1186   if (impl->preview_widget)
1187     gtk_container_remove (GTK_CONTAINER (impl->preview_box),
1188                           impl->preview_widget);
1189
1190   impl->preview_widget = preview_widget;
1191   if (impl->preview_widget)
1192     {
1193       gtk_widget_show (impl->preview_widget);
1194       gtk_box_pack_start (GTK_BOX (impl->preview_box), impl->preview_widget, TRUE, TRUE, 0);
1195       gtk_box_reorder_child (GTK_BOX (impl->preview_box),
1196                              impl->preview_widget,
1197                              (impl->use_preview_label && impl->preview_label) ? 1 : 0);
1198     }
1199
1200   update_preview_widget_visibility (impl);
1201 }
1202
1203 /* Renders a "Search" icon at an appropriate size for a tree view */
1204 static GdkPixbuf *
1205 render_search_icon (GtkFileChooserDefault *impl)
1206 {
1207   return gtk_widget_render_icon (GTK_WIDGET (impl), GTK_STOCK_FIND, GTK_ICON_SIZE_MENU, NULL);
1208 }
1209
1210 static GdkPixbuf *
1211 render_recent_icon (GtkFileChooserDefault *impl)
1212 {
1213   return gtk_widget_render_icon (GTK_WIDGET (impl), GTK_STOCK_FILE, GTK_ICON_SIZE_MENU, NULL);
1214 }
1215
1216
1217 /* Re-reads all the icons for the shortcuts, used when the theme changes */
1218 struct ReloadIconsData
1219 {
1220   GtkFileChooserDefault *impl;
1221   GtkTreeRowReference *row_ref;
1222 };
1223
1224 static void
1225 shortcuts_reload_icons_get_info_cb (GtkFileSystemHandle *handle,
1226                                     const GtkFileInfo   *info,
1227                                     const GError        *error,
1228                                     gpointer             user_data)
1229 {
1230   GdkPixbuf *pixbuf;
1231   GtkTreeIter iter;
1232   GtkTreePath *path;
1233   gboolean cancelled = handle->cancelled;
1234   struct ReloadIconsData *data = user_data;
1235
1236   if (!g_slist_find (data->impl->reload_icon_handles, handle))
1237     goto out;
1238
1239   data->impl->reload_icon_handles = g_slist_remove (data->impl->reload_icon_handles, handle);
1240
1241   if (cancelled || error)
1242     goto out;
1243
1244   pixbuf = gtk_file_info_render_icon (info, GTK_WIDGET (data->impl),
1245                                       data->impl->icon_size, NULL);
1246
1247   path = gtk_tree_row_reference_get_path (data->row_ref);
1248   gtk_tree_model_get_iter (GTK_TREE_MODEL (data->impl->shortcuts_model), &iter, path);
1249   gtk_list_store_set (data->impl->shortcuts_model, &iter,
1250                       SHORTCUTS_COL_PIXBUF, pixbuf,
1251                       -1);
1252   gtk_tree_path_free (path);
1253
1254   if (pixbuf)
1255     g_object_unref (pixbuf);
1256
1257 out:
1258   gtk_tree_row_reference_free (data->row_ref);
1259   g_object_unref (data->impl);
1260   g_free (data);
1261
1262   g_object_unref (handle);
1263 }
1264
1265 static void
1266 shortcuts_reload_icons (GtkFileChooserDefault *impl)
1267 {
1268   GSList *l;
1269   GtkTreeIter iter;
1270
1271   profile_start ("start", NULL);
1272
1273   if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (impl->shortcuts_model), &iter))
1274     goto out;
1275
1276   for (l = impl->reload_icon_handles; l; l = l->next)
1277     {
1278       GtkFileSystemHandle *handle = GTK_FILE_SYSTEM_HANDLE (l->data);
1279       gtk_file_system_cancel_operation (handle);
1280     }
1281   g_slist_free (impl->reload_icon_handles);
1282   impl->reload_icon_handles = NULL;
1283
1284   do
1285     {
1286       gpointer data;
1287       ShortcutType shortcut_type;
1288       gboolean pixbuf_visible;
1289       GdkPixbuf *pixbuf;
1290
1291       gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter,
1292                           SHORTCUTS_COL_DATA, &data,
1293                           SHORTCUTS_COL_TYPE, &shortcut_type,
1294                           SHORTCUTS_COL_PIXBUF_VISIBLE, &pixbuf_visible,
1295                           -1);
1296
1297       pixbuf = NULL;
1298       if (pixbuf_visible)
1299         {
1300           if (shortcut_type == SHORTCUT_TYPE_VOLUME)
1301             {
1302               GtkFileSystemVolume *volume;
1303
1304               volume = data;
1305               pixbuf = gtk_file_system_volume_render_icon (impl->file_system, volume, GTK_WIDGET (impl),
1306                                                            impl->icon_size, NULL);
1307
1308               gtk_list_store_set (impl->shortcuts_model, &iter,
1309                                   SHORTCUTS_COL_PIXBUF, pixbuf,
1310                                   -1);
1311
1312               if (pixbuf)
1313                 g_object_unref (pixbuf);
1314             }
1315           else if (shortcut_type == SHORTCUT_TYPE_PATH)
1316             {
1317               if (gtk_file_system_path_is_local (impl->file_system, (GtkFilePath *)data))
1318                 {
1319                   const GtkFilePath *path;
1320                   struct ReloadIconsData *info;
1321                   GtkTreePath *tree_path;
1322                   GtkFileSystemHandle *handle;
1323
1324                   path = data;
1325
1326                   info = g_new0 (struct ReloadIconsData, 1);
1327                   info->impl = g_object_ref (impl);
1328                   tree_path = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->shortcuts_model), &iter);
1329                   info->row_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (impl->shortcuts_model), tree_path);
1330                   gtk_tree_path_free (tree_path);
1331
1332                   handle = gtk_file_system_get_info (impl->file_system, path,
1333                                                      GTK_FILE_INFO_ICON,
1334                                                      shortcuts_reload_icons_get_info_cb,
1335                                                      info);
1336                   impl->reload_icon_handles = g_slist_append (impl->reload_icon_handles, handle);
1337                 }
1338               else
1339                 {
1340                   GtkIconTheme *icon_theme;
1341
1342                   /* Don't call get_info for remote paths to avoid latency and
1343                    * auth dialogs.
1344                    * If we switch to a better bookmarks file format (XBEL), we
1345                    * should use mime info to get a better icon.
1346                    */
1347                   icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (impl)));
1348                   pixbuf = gtk_icon_theme_load_icon (icon_theme, "gnome-fs-directory", 
1349                                                      impl->icon_size, 0, NULL);
1350
1351                   gtk_list_store_set (impl->shortcuts_model, &iter,
1352                                       SHORTCUTS_COL_PIXBUF, pixbuf,
1353                                       -1);
1354
1355                   if (pixbuf)
1356                     g_object_unref (pixbuf);
1357                 }
1358             }
1359           else if (shortcut_type == SHORTCUT_TYPE_SEARCH)
1360             {
1361               pixbuf = render_search_icon (impl);
1362             }
1363           else if (shortcut_type == SHORTCUT_TYPE_RECENT)
1364             {
1365               pixbuf = render_recent_icon (impl);
1366             }
1367         }
1368     }
1369   while (gtk_tree_model_iter_next (GTK_TREE_MODEL (impl->shortcuts_model),&iter));
1370
1371  out:
1372
1373   profile_end ("end", NULL);
1374 }
1375
1376 static void 
1377 shortcuts_find_folder (GtkFileChooserDefault *impl,
1378                        GtkFilePath           *folder)
1379 {
1380   GtkTreeSelection *selection;
1381   int pos;
1382   GtkTreePath *path;
1383
1384   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view));
1385
1386   g_assert (folder != NULL);
1387   pos = shortcut_find_position (impl, folder);
1388   if (pos == -1)
1389     {
1390       gtk_tree_selection_unselect_all (selection);
1391       return;
1392     }
1393
1394   path = gtk_tree_path_new_from_indices (pos, -1);
1395   gtk_tree_selection_select_path (selection, path);
1396   gtk_tree_path_free (path);
1397 }
1398
1399 /* If a shortcut corresponds to the current folder, selects it */
1400 static void
1401 shortcuts_find_current_folder (GtkFileChooserDefault *impl)
1402 {
1403   shortcuts_find_folder (impl, impl->current_folder);
1404 }
1405
1406 /* Removes the specified number of rows from the shortcuts list */
1407 static void
1408 shortcuts_remove_rows (GtkFileChooserDefault *impl,
1409                        int                    start_row,
1410                        int                    n_rows)
1411 {
1412   GtkTreePath *path;
1413
1414   path = gtk_tree_path_new_from_indices (start_row, -1);
1415
1416   for (; n_rows; n_rows--)
1417     {
1418       GtkTreeIter iter;
1419
1420       if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->shortcuts_model), &iter, path))
1421         g_assert_not_reached ();
1422
1423       shortcuts_free_row_data (impl, &iter);
1424       gtk_list_store_remove (impl->shortcuts_model, &iter);
1425     }
1426
1427   gtk_tree_path_free (path);
1428 }
1429
1430 static void
1431 shortcuts_update_count (GtkFileChooserDefault *impl,
1432                         ShortcutsIndex         type,
1433                         gint                   value)
1434 {
1435   switch (type)
1436     {
1437       case SHORTCUTS_HOME:
1438         if (value < 0)
1439           impl->has_home = FALSE;
1440         else
1441           impl->has_home = TRUE;
1442         break;
1443
1444       case SHORTCUTS_DESKTOP:
1445         if (value < 0)
1446           impl->has_desktop = FALSE;
1447         else
1448           impl->has_desktop = TRUE;
1449         break;
1450
1451       case SHORTCUTS_VOLUMES:
1452         impl->num_volumes += value;
1453         break;
1454
1455       case SHORTCUTS_SHORTCUTS:
1456         impl->num_shortcuts += value;
1457         break;
1458
1459       case SHORTCUTS_BOOKMARKS:
1460         impl->num_bookmarks += value;
1461         break;
1462
1463       case SHORTCUTS_CURRENT_FOLDER:
1464         if (value < 0)
1465           impl->shortcuts_current_folder_active = FALSE;
1466         else
1467           impl->shortcuts_current_folder_active = TRUE;
1468         break;
1469
1470       default:
1471         /* nothing */
1472         break;
1473     }
1474 }
1475
1476 struct ShortcutsInsertRequest
1477 {
1478   GtkFileChooserDefault *impl;
1479   GtkFilePath *parent_path;
1480   GtkFilePath *path;
1481   int pos;
1482   char *label_copy;
1483   GtkTreeRowReference *row_ref;
1484   ShortcutsIndex type;
1485   gboolean name_only;
1486   gboolean removable;
1487 };
1488
1489 static void
1490 get_file_info_finished (GtkFileSystemHandle *handle,
1491                         const GtkFileInfo   *info,
1492                         const GError        *error,
1493                         gpointer             data)
1494 {
1495   gint pos = -1;
1496   gboolean cancelled = handle->cancelled;
1497   GdkPixbuf *pixbuf;
1498   GtkTreePath *path;
1499   GtkTreeIter iter;
1500   GtkFileSystemHandle *model_handle;
1501   struct ShortcutsInsertRequest *request = data;
1502
1503   path = gtk_tree_row_reference_get_path (request->row_ref);
1504   if (!path)
1505     /* Handle doesn't exist anymore in the model */
1506     goto out;
1507
1508   pos = gtk_tree_path_get_indices (path)[0];
1509   gtk_tree_model_get_iter (GTK_TREE_MODEL (request->impl->shortcuts_model),
1510                            &iter, path);
1511   gtk_tree_path_free (path);
1512
1513   /* validate handle, else goto out */
1514   gtk_tree_model_get (GTK_TREE_MODEL (request->impl->shortcuts_model), &iter,
1515                       SHORTCUTS_COL_HANDLE, &model_handle,
1516                       -1);
1517   if (handle != model_handle)
1518     goto out;
1519
1520   /* set the handle to NULL in the model (we unref later on) */
1521   gtk_list_store_set (request->impl->shortcuts_model, &iter,
1522                       SHORTCUTS_COL_HANDLE, NULL,
1523                       -1);
1524
1525   if (cancelled)
1526     goto out;
1527
1528   if (!info)
1529     {
1530       gtk_list_store_remove (request->impl->shortcuts_model, &iter);
1531       shortcuts_update_count (request->impl, request->type, -1);
1532
1533       if (request->type == SHORTCUTS_HOME)
1534         {
1535           const char *home = g_get_home_dir ();
1536           GtkFilePath *home_path;
1537
1538           home_path = gtk_file_system_filename_to_path (request->impl->file_system, home);
1539           error_getting_info_dialog (request->impl, home_path, g_error_copy (error));
1540           gtk_file_path_free (home_path);
1541         }
1542       else if (request->type == SHORTCUTS_CURRENT_FOLDER)
1543         {
1544           /* Remove the current folder separator */
1545           gint separator_pos = shortcuts_get_index (request->impl, SHORTCUTS_CURRENT_FOLDER_SEPARATOR);
1546           shortcuts_remove_rows (request->impl, separator_pos, 1);
1547         }
1548
1549       goto out;
1550     }
1551   
1552   if (!request->label_copy)
1553     request->label_copy = g_strdup (gtk_file_info_get_display_name (info));
1554   pixbuf = gtk_file_info_render_icon (info, GTK_WIDGET (request->impl),
1555                                       request->impl->icon_size, NULL);
1556
1557   gtk_list_store_set (request->impl->shortcuts_model, &iter,
1558                       SHORTCUTS_COL_PIXBUF, pixbuf,
1559                       SHORTCUTS_COL_PIXBUF_VISIBLE, TRUE,
1560                       SHORTCUTS_COL_NAME, request->label_copy,
1561                       SHORTCUTS_COL_TYPE, SHORTCUT_TYPE_PATH,
1562                       SHORTCUTS_COL_REMOVABLE, request->removable,
1563                       -1);
1564
1565   if (request->impl->shortcuts_pane_filter_model)
1566     gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (request->impl->shortcuts_pane_filter_model));
1567
1568   if (request->impl->shortcuts_combo_filter_model)
1569     gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (request->impl->shortcuts_combo_filter_model));
1570
1571   if (request->type == SHORTCUTS_CURRENT_FOLDER
1572       && request->impl->save_folder_combo != NULL)
1573     {
1574       /* The current folder is updated via _activate_iter(), don't
1575        * have save_folder_combo_changed_cb() call _activate_iter()
1576        * again.
1577        */
1578       g_signal_handlers_block_by_func (request->impl->save_folder_combo,
1579                                        G_CALLBACK (save_folder_combo_changed_cb),
1580                                        request->impl);
1581       gtk_combo_box_set_active (GTK_COMBO_BOX (request->impl->save_folder_combo), request->impl->has_search ? pos - 2 : pos);
1582       g_signal_handlers_unblock_by_func (request->impl->save_folder_combo,
1583                                          G_CALLBACK (save_folder_combo_changed_cb),
1584                                          request->impl);
1585     }
1586
1587   if (pixbuf)
1588     g_object_unref (pixbuf);
1589
1590 out:
1591   g_object_unref (request->impl);
1592   gtk_file_path_free (request->parent_path);
1593   gtk_file_path_free (request->path);
1594   gtk_tree_row_reference_free (request->row_ref);
1595   g_free (request->label_copy);
1596   g_free (request);
1597
1598   g_object_unref (handle);
1599 }
1600
1601 /* FIXME: GtkFileSystem needs a function to split a remote path
1602  * into hostname and path components, or maybe just have a 
1603  * gtk_file_system_path_get_display_name().
1604  *
1605  * This function is also used in gtkfilechooserbutton.c
1606  */
1607 gchar *
1608 _gtk_file_chooser_label_for_uri (const gchar *uri)
1609 {
1610   const gchar *path, *start, *end, *p;
1611   gchar *host, *label;
1612   
1613   start = strstr (uri, "://");
1614   start += 3;
1615   path = strchr (start, '/');
1616   
1617   if (path)
1618     end = path;
1619   else
1620     {
1621       end = uri + strlen (uri);
1622       path = "/";
1623     }
1624
1625   /* strip username */
1626   p = strchr (start, '@');
1627   if (p && p < end)
1628     {
1629       start = p + 1;
1630     }
1631   
1632   p = strchr (start, ':');
1633   if (p && p < end)
1634     end = p;
1635   
1636   host = g_strndup (start, end - start);
1637
1638   /* Translators: the first string is a path and the second string 
1639    * is a hostname. Nautilus and the panel contain the same string 
1640    * to translate. 
1641    */
1642   label = g_strdup_printf (_("%1$s on %2$s"), path, host);
1643   
1644   g_free (host);
1645
1646   return label;
1647 }
1648
1649 /* Inserts a path in the shortcuts tree, making a copy of it; alternatively,
1650  * inserts a volume.  A position of -1 indicates the end of the tree.
1651  */
1652 static void
1653 shortcuts_insert_path (GtkFileChooserDefault *impl,
1654                        int                    pos,
1655                        ShortcutType           shortcut_type,
1656                        GtkFileSystemVolume   *volume,
1657                        const GtkFilePath     *path,
1658                        const char            *label,
1659                        gboolean               removable,
1660                        ShortcutsIndex         type)
1661 {
1662   char *label_copy;
1663   GdkPixbuf *pixbuf = NULL;
1664   gpointer data = NULL;
1665   GtkTreeIter iter;
1666   GtkIconTheme *icon_theme;      
1667
1668   profile_start ("start", (shortcut_type == SHORTCUT_TYPE_VOLUME) ? "volume" 
1669                          : ((shortcut_type == SHORTCUT_TYPE_PATH) ? (char *) path : NULL));
1670
1671   if (shortcut_type == SHORTCUT_TYPE_VOLUME)
1672     {
1673       data = volume;
1674       label_copy = gtk_file_system_volume_get_display_name (impl->file_system, volume);
1675       pixbuf = gtk_file_system_volume_render_icon (impl->file_system, volume, GTK_WIDGET (impl),
1676                                                    impl->icon_size, NULL);
1677     }
1678   else if (shortcut_type == SHORTCUT_TYPE_PATH)
1679     {
1680       if (gtk_file_system_path_is_local (impl->file_system, path))
1681         {
1682           struct ShortcutsInsertRequest *request;
1683           GtkFileSystemHandle *handle;
1684           GtkTreePath *p;
1685
1686           request = g_new0 (struct ShortcutsInsertRequest, 1);
1687           request->impl = g_object_ref (impl);
1688           request->path = gtk_file_path_copy (path);
1689           request->name_only = TRUE;
1690           request->removable = removable;
1691           request->pos = pos;
1692           request->type = type;
1693           if (label)
1694             request->label_copy = g_strdup (label);
1695
1696           if (pos == -1)
1697             gtk_list_store_append (impl->shortcuts_model, &iter);
1698           else
1699             gtk_list_store_insert (impl->shortcuts_model, &iter, pos);
1700
1701           p = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->shortcuts_model), &iter);
1702           request->row_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (impl->shortcuts_model), p);
1703           gtk_tree_path_free (p);
1704
1705           handle = gtk_file_system_get_info (request->impl->file_system, request->path,
1706                                              GTK_FILE_INFO_DISPLAY_NAME | GTK_FILE_INFO_IS_HIDDEN | GTK_FILE_INFO_ICON,
1707                                              get_file_info_finished, request);
1708
1709           gtk_list_store_set (impl->shortcuts_model, &iter,
1710                               SHORTCUTS_COL_DATA, gtk_file_path_copy (path),
1711                               SHORTCUTS_COL_TYPE, SHORTCUT_TYPE_PATH,
1712                               SHORTCUTS_COL_HANDLE, handle,
1713                               -1);
1714
1715           shortcuts_update_count (impl, type, 1);
1716
1717           return;
1718         }
1719       else
1720         {
1721           /* Don't call get_info for remote paths to avoid latency and
1722            * auth dialogs.
1723            */
1724           data = gtk_file_path_copy (path);
1725           if (label)
1726             label_copy = g_strdup (label);
1727           else
1728             {
1729               gchar *uri;
1730
1731               uri = gtk_file_system_path_to_uri (impl->file_system, path);
1732
1733               label_copy = _gtk_file_chooser_label_for_uri (uri);
1734
1735               g_free (uri);
1736             }
1737     
1738           /* If we switch to a better bookmarks file format (XBEL), we
1739            * should use mime info to get a better icon.
1740            */
1741           icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (impl)));
1742           pixbuf = gtk_icon_theme_load_icon (icon_theme, "gnome-fs-directory", 
1743                                              impl->icon_size, 0, NULL);
1744         }
1745     }
1746    else
1747     {
1748       g_assert_not_reached ();
1749
1750       return;
1751     }
1752
1753   if (pos == -1)
1754     gtk_list_store_append (impl->shortcuts_model, &iter);
1755   else
1756     gtk_list_store_insert (impl->shortcuts_model, &iter, pos);
1757
1758   shortcuts_update_count (impl, type, 1);
1759
1760   gtk_list_store_set (impl->shortcuts_model, &iter,
1761                       SHORTCUTS_COL_PIXBUF, pixbuf,
1762                       SHORTCUTS_COL_PIXBUF_VISIBLE, TRUE,
1763                       SHORTCUTS_COL_NAME, label_copy,
1764                       SHORTCUTS_COL_DATA, data,
1765                       SHORTCUTS_COL_TYPE, shortcut_type,
1766                       SHORTCUTS_COL_REMOVABLE, removable,
1767                       SHORTCUTS_COL_HANDLE, NULL,
1768                       -1);
1769
1770   if (impl->shortcuts_pane_filter_model)
1771     gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_pane_filter_model));
1772
1773   if (impl->shortcuts_combo_filter_model)
1774     gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_combo_filter_model));
1775
1776   if (type == SHORTCUTS_CURRENT_FOLDER && impl->save_folder_combo != NULL)
1777     {
1778       /* The current folder is updated via _activate_iter(), don't
1779        * have save_folder_combo_changed_cb() call _activate_iter()
1780        * again.
1781        */
1782       gint combo_pos = shortcuts_get_index (impl, SHORTCUTS_CURRENT_FOLDER);
1783       g_signal_handlers_block_by_func (impl->save_folder_combo,
1784                                        G_CALLBACK (save_folder_combo_changed_cb),
1785                                        impl);
1786       gtk_combo_box_set_active (GTK_COMBO_BOX (impl->save_folder_combo), 
1787                                 impl->has_search ? combo_pos - 2 : combo_pos);
1788       g_signal_handlers_unblock_by_func (impl->save_folder_combo,
1789                                          G_CALLBACK (save_folder_combo_changed_cb),
1790                                          impl);
1791     }
1792
1793   g_free (label_copy);
1794
1795   if (pixbuf)
1796     g_object_unref (pixbuf);
1797
1798   profile_end ("end", NULL);
1799 }
1800
1801 static void
1802 shortcuts_append_search (GtkFileChooserDefault *impl)
1803 {
1804   GdkPixbuf *pixbuf;
1805   GtkTreeIter iter;
1806
1807   pixbuf = render_search_icon (impl);
1808
1809   gtk_list_store_append (impl->shortcuts_model, &iter);
1810   gtk_list_store_set (impl->shortcuts_model, &iter,
1811                       SHORTCUTS_COL_PIXBUF, pixbuf,
1812                       SHORTCUTS_COL_PIXBUF_VISIBLE, TRUE,
1813                       SHORTCUTS_COL_NAME, _("Search"),
1814                       SHORTCUTS_COL_DATA, NULL,
1815                       SHORTCUTS_COL_TYPE, SHORTCUT_TYPE_SEARCH,
1816                       SHORTCUTS_COL_REMOVABLE, FALSE,
1817                       -1);
1818
1819   if (pixbuf)
1820     g_object_unref (pixbuf);
1821
1822   impl->has_search = TRUE;
1823 }
1824
1825 static void
1826 shortcuts_append_recent (GtkFileChooserDefault *impl)
1827 {
1828   GdkPixbuf *pixbuf;
1829   GtkTreeIter iter;
1830
1831   pixbuf = render_recent_icon (impl);
1832
1833   gtk_list_store_append (impl->shortcuts_model, &iter);
1834   gtk_list_store_set (impl->shortcuts_model, &iter,
1835                       SHORTCUTS_COL_PIXBUF, pixbuf,
1836                       SHORTCUTS_COL_PIXBUF_VISIBLE, TRUE,
1837                       SHORTCUTS_COL_NAME, _("Recently Used"),
1838                       SHORTCUTS_COL_DATA, NULL,
1839                       SHORTCUTS_COL_TYPE, SHORTCUT_TYPE_RECENT,
1840                       SHORTCUTS_COL_REMOVABLE, FALSE,
1841                       -1);
1842   
1843   if (pixbuf)
1844     g_object_unref (pixbuf);
1845
1846   impl->has_recent = TRUE;
1847 }
1848
1849 /* Appends an item for the user's home directory to the shortcuts model */
1850 static void
1851 shortcuts_append_home (GtkFileChooserDefault *impl)
1852 {
1853   const char *home;
1854   GtkFilePath *home_path;
1855
1856   profile_start ("start", NULL);
1857
1858   home = g_get_home_dir ();
1859   if (home == NULL)
1860     {
1861       profile_end ("end - no home directory!?", NULL);
1862       return;
1863     }
1864
1865   home_path = gtk_file_system_filename_to_path (impl->file_system, home);
1866
1867   shortcuts_insert_path (impl, -1, SHORTCUT_TYPE_PATH, NULL, home_path, NULL, FALSE, SHORTCUTS_HOME);
1868   impl->has_home = TRUE;
1869
1870   gtk_file_path_free (home_path);
1871
1872   profile_end ("end", NULL);
1873 }
1874
1875 /* Appends the ~/Desktop directory to the shortcuts model */
1876 static void
1877 shortcuts_append_desktop (GtkFileChooserDefault *impl)
1878 {
1879   char *name;
1880   const char *home;
1881   GtkFilePath *path;
1882
1883   profile_start ("start", NULL);
1884
1885 #ifdef G_OS_WIN32
1886   name = _gtk_file_system_win32_get_desktop ();
1887 #else
1888   home = g_get_home_dir ();
1889   if (home == NULL)
1890     {
1891       profile_end ("end - no home directory!?", NULL);
1892       return;
1893     }
1894
1895   name = g_build_filename (home, "Desktop", NULL);
1896 #endif
1897
1898   path = gtk_file_system_filename_to_path (impl->file_system, name);
1899   g_free (name);
1900
1901   shortcuts_insert_path (impl, -1, SHORTCUT_TYPE_PATH, NULL, path, _("Desktop"), FALSE, SHORTCUTS_DESKTOP);
1902   impl->has_desktop = TRUE;
1903
1904   /* We do not actually pop up an error dialog if there is no desktop directory
1905    * because some people may really not want to have one.
1906    */
1907
1908   gtk_file_path_free (path);
1909
1910   profile_end ("end", NULL);
1911 }
1912
1913 /* Appends a list of GtkFilePath to the shortcuts model; returns how many were inserted */
1914 static int
1915 shortcuts_append_paths (GtkFileChooserDefault *impl,
1916                         GSList                *paths)
1917 {
1918   int start_row;
1919   int num_inserted;
1920   gchar *label;
1921
1922   profile_start ("start", NULL);
1923
1924   /* As there is no separator now, we want to start there.
1925    */
1926   start_row = shortcuts_get_index (impl, SHORTCUTS_BOOKMARKS_SEPARATOR);
1927   num_inserted = 0;
1928
1929   for (; paths; paths = paths->next)
1930     {
1931       GtkFilePath *path;
1932
1933       path = paths->data;
1934
1935       if (impl->local_only &&
1936           !gtk_file_system_path_is_local (impl->file_system, path))
1937         continue;
1938
1939       label = gtk_file_system_get_bookmark_label (impl->file_system, path);
1940
1941       /* NULL GError, but we don't really want to show error boxes here */
1942       shortcuts_insert_path (impl, start_row + num_inserted, SHORTCUT_TYPE_PATH, NULL, path, label, TRUE, SHORTCUTS_BOOKMARKS);
1943       num_inserted++;
1944
1945       g_free (label);
1946     }
1947
1948   profile_end ("end", NULL);
1949
1950   return num_inserted;
1951 }
1952
1953 /* Returns the index for the corresponding item in the shortcuts bar */
1954 static int
1955 shortcuts_get_index (GtkFileChooserDefault *impl,
1956                      ShortcutsIndex         where)
1957 {
1958   int n;
1959
1960   n = 0;
1961   
1962   if (where == SHORTCUTS_SEARCH)
1963     goto out;
1964
1965   n += impl->has_search ? 1 : 0;
1966
1967   if (where == SHORTCUTS_SEARCH_SEPARATOR)
1968     goto out;
1969
1970   n += impl->has_search ? 1 : 0;
1971
1972   if (where == SHORTCUTS_RECENT)
1973     goto out;
1974
1975   n += impl->has_recent ? 1 : 0;
1976
1977   if (where == SHORTCUTS_RECENT_SEPARATOR)
1978     goto out;
1979
1980   n += impl->has_recent ? 1 : 0;
1981
1982   if (where == SHORTCUTS_HOME)
1983     goto out;
1984
1985   n += impl->has_home ? 1 : 0;
1986
1987   if (where == SHORTCUTS_DESKTOP)
1988     goto out;
1989
1990   n += impl->has_desktop ? 1 : 0;
1991
1992   if (where == SHORTCUTS_VOLUMES)
1993     goto out;
1994
1995   n += impl->num_volumes;
1996
1997   if (where == SHORTCUTS_SHORTCUTS)
1998     goto out;
1999
2000   n += impl->num_shortcuts;
2001
2002   if (where == SHORTCUTS_BOOKMARKS_SEPARATOR)
2003     goto out;
2004
2005   /* If there are no bookmarks there won't be a separator */
2006   n += (impl->num_bookmarks > 0) ? 1 : 0;
2007
2008   if (where == SHORTCUTS_BOOKMARKS)
2009     goto out;
2010
2011   n += impl->num_bookmarks;
2012
2013   if (where == SHORTCUTS_CURRENT_FOLDER_SEPARATOR)
2014     goto out;
2015
2016   n += 1;
2017
2018   if (where == SHORTCUTS_CURRENT_FOLDER)
2019     goto out;
2020
2021   g_assert_not_reached ();
2022
2023  out:
2024
2025   return n;
2026 }
2027
2028 /* Adds all the file system volumes to the shortcuts model */
2029 static void
2030 shortcuts_add_volumes (GtkFileChooserDefault *impl)
2031 {
2032   int start_row;
2033   GSList *list, *l;
2034   int n;
2035   gboolean old_changing_folders;
2036
2037   profile_start ("start", NULL);
2038
2039
2040   old_changing_folders = impl->changing_folder;
2041   impl->changing_folder = TRUE;
2042
2043   start_row = shortcuts_get_index (impl, SHORTCUTS_VOLUMES);
2044   shortcuts_remove_rows (impl, start_row, impl->num_volumes);
2045   impl->num_volumes = 0;
2046
2047   list = gtk_file_system_list_volumes (impl->file_system);
2048
2049   n = 0;
2050
2051   for (l = list; l; l = l->next)
2052     {
2053       GtkFileSystemVolume *volume;
2054
2055       volume = l->data;
2056
2057       if (impl->local_only)
2058         {
2059           if (gtk_file_system_volume_get_is_mounted (impl->file_system, volume))
2060             {
2061               GtkFilePath *base_path;
2062
2063               base_path = gtk_file_system_volume_get_base_path (impl->file_system, volume);
2064               if (base_path != NULL)
2065                 {
2066                   gboolean is_local = gtk_file_system_path_is_local (impl->file_system, base_path);
2067                   gtk_file_path_free (base_path);
2068
2069                   if (!is_local)
2070                     {
2071                       gtk_file_system_volume_free (impl->file_system, volume);
2072                       continue;
2073                     }
2074                 }
2075             }
2076         }
2077
2078       shortcuts_insert_path (impl, start_row + n, SHORTCUT_TYPE_VOLUME, volume, NULL, NULL, FALSE, SHORTCUTS_VOLUMES);
2079       n++;
2080     }
2081
2082   impl->num_volumes = n;
2083   g_slist_free (list);
2084
2085   if (impl->shortcuts_pane_filter_model)
2086     gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_pane_filter_model));
2087
2088   if (impl->shortcuts_combo_filter_model)
2089     gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_combo_filter_model));
2090
2091   impl->changing_folder = old_changing_folders;
2092
2093   profile_end ("end", NULL);
2094 }
2095
2096 /* Inserts a separator node in the shortcuts list */
2097 static void
2098 shortcuts_insert_separator (GtkFileChooserDefault *impl,
2099                             ShortcutsIndex         where)
2100 {
2101   GtkTreeIter iter;
2102
2103   g_assert (where == SHORTCUTS_SEARCH_SEPARATOR || 
2104             where == SHORTCUTS_RECENT_SEPARATOR ||
2105             where == SHORTCUTS_BOOKMARKS_SEPARATOR || 
2106             where == SHORTCUTS_CURRENT_FOLDER_SEPARATOR);
2107
2108   gtk_list_store_insert (impl->shortcuts_model, &iter,
2109                          shortcuts_get_index (impl, where));
2110   gtk_list_store_set (impl->shortcuts_model, &iter,
2111                       SHORTCUTS_COL_PIXBUF, NULL,
2112                       SHORTCUTS_COL_PIXBUF_VISIBLE, FALSE,
2113                       SHORTCUTS_COL_NAME, NULL,
2114                       SHORTCUTS_COL_DATA, NULL,
2115                       SHORTCUTS_COL_TYPE, SHORTCUT_TYPE_SEPARATOR,
2116                       -1);
2117 }
2118
2119 /* Updates the list of bookmarks */
2120 static void
2121 shortcuts_add_bookmarks (GtkFileChooserDefault *impl)
2122 {
2123   GSList *bookmarks;
2124   gboolean old_changing_folders;
2125   GtkTreeIter iter;
2126   GtkFilePath *list_selected = NULL;
2127   GtkFilePath *combo_selected = NULL;
2128   ShortcutType shortcut_type;
2129   gpointer col_data;
2130
2131   profile_start ("start", NULL);
2132         
2133   old_changing_folders = impl->changing_folder;
2134   impl->changing_folder = TRUE;
2135
2136   if (shortcuts_get_selected (impl, &iter))
2137     {
2138       gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), 
2139                           &iter, 
2140                           SHORTCUTS_COL_DATA, &col_data,
2141                           SHORTCUTS_COL_TYPE, &shortcut_type,
2142                           -1);
2143
2144       if (col_data && shortcut_type == SHORTCUT_TYPE_PATH)
2145         list_selected = gtk_file_path_copy (col_data);
2146     }
2147
2148   if (impl->save_folder_combo &&
2149       gtk_combo_box_get_active_iter (GTK_COMBO_BOX (impl->save_folder_combo), 
2150                                      &iter))
2151     {
2152       GtkTreeIter child_iter;
2153
2154       gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER  (impl->shortcuts_combo_filter_model),
2155                                                         &child_iter,
2156                                                         &iter);
2157       gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), 
2158                           &child_iter, 
2159                           SHORTCUTS_COL_DATA, &col_data,
2160                           SHORTCUTS_COL_TYPE, &shortcut_type,
2161                           -1);
2162       
2163       if (col_data && shortcut_type == SHORTCUT_TYPE_PATH)
2164         combo_selected = gtk_file_path_copy (col_data);
2165     }
2166
2167   if (impl->num_bookmarks > 0)
2168     shortcuts_remove_rows (impl,
2169                            shortcuts_get_index (impl, SHORTCUTS_BOOKMARKS_SEPARATOR),
2170                            impl->num_bookmarks + 1);
2171
2172   impl->num_bookmarks = 0;
2173
2174   bookmarks = gtk_file_system_list_bookmarks (impl->file_system);
2175   shortcuts_append_paths (impl, bookmarks);
2176   gtk_file_paths_free (bookmarks);
2177
2178   if (impl->num_bookmarks > 0)
2179     shortcuts_insert_separator (impl, SHORTCUTS_BOOKMARKS_SEPARATOR);
2180
2181   if (impl->shortcuts_pane_filter_model)
2182     gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_pane_filter_model));
2183
2184   if (impl->shortcuts_combo_filter_model)
2185     gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_combo_filter_model));
2186
2187   if (list_selected)
2188     {
2189       shortcuts_find_folder (impl, list_selected);
2190       gtk_file_path_free (list_selected);
2191     }
2192
2193   if (combo_selected)
2194     {
2195       gint pos;
2196
2197       pos = shortcut_find_position (impl, combo_selected);
2198       if (pos != -1)
2199         gtk_combo_box_set_active (GTK_COMBO_BOX (impl->save_folder_combo),
2200                                   impl->has_search ? pos - 2 : pos);
2201       gtk_file_path_free (combo_selected);
2202     }
2203   
2204   impl->changing_folder = old_changing_folders;
2205
2206   profile_end ("end", NULL);
2207 }
2208
2209 /* Appends a separator and a row to the shortcuts list for the current folder */
2210 static void
2211 shortcuts_add_current_folder (GtkFileChooserDefault *impl)
2212 {
2213   int pos;
2214   gboolean success;
2215
2216   g_assert (!impl->shortcuts_current_folder_active);
2217
2218   success = TRUE;
2219
2220   g_assert (impl->current_folder != NULL);
2221
2222   pos = shortcut_find_position (impl, impl->current_folder);
2223   if (pos == -1)
2224     {
2225       GtkFileSystemVolume *volume;
2226       GtkFilePath *base_path;
2227
2228       /* Separator */
2229
2230       shortcuts_insert_separator (impl, SHORTCUTS_CURRENT_FOLDER_SEPARATOR);
2231
2232       /* Item */
2233
2234       pos = shortcuts_get_index (impl, SHORTCUTS_CURRENT_FOLDER);
2235
2236       volume = gtk_file_system_get_volume_for_path (impl->file_system, impl->current_folder);
2237       if (volume)
2238         base_path = gtk_file_system_volume_get_base_path (impl->file_system, volume);
2239       else
2240         base_path = NULL;
2241
2242       if (base_path &&
2243           strcmp (gtk_file_path_get_string (base_path), gtk_file_path_get_string (impl->current_folder)) == 0)
2244         {
2245           shortcuts_insert_path (impl, pos, SHORTCUT_TYPE_VOLUME, volume, NULL, NULL, FALSE, SHORTCUTS_CURRENT_FOLDER);
2246         }
2247       else
2248         {
2249           shortcuts_insert_path (impl, pos, SHORTCUT_TYPE_PATH, NULL, impl->current_folder, NULL, FALSE, SHORTCUTS_CURRENT_FOLDER);
2250           if (volume)
2251             gtk_file_system_volume_free (impl->file_system, volume);
2252         }
2253
2254       if (base_path)
2255         gtk_file_path_free (base_path);
2256     }
2257   else if (impl->save_folder_combo != NULL)
2258     gtk_combo_box_set_active (GTK_COMBO_BOX (impl->save_folder_combo), 
2259                               impl->has_search ? pos - 2 : pos);
2260 }
2261
2262 /* Updates the current folder row in the shortcuts model */
2263 static void
2264 shortcuts_update_current_folder (GtkFileChooserDefault *impl)
2265 {
2266   int pos;
2267
2268   pos = shortcuts_get_index (impl, SHORTCUTS_CURRENT_FOLDER_SEPARATOR);
2269
2270   if (impl->shortcuts_current_folder_active)
2271     {
2272       shortcuts_remove_rows (impl, pos, 2);
2273       impl->shortcuts_current_folder_active = FALSE;
2274     }
2275
2276   shortcuts_add_current_folder (impl);
2277 }
2278
2279 /* Filter function used for the shortcuts filter model */
2280 static gboolean
2281 shortcuts_pane_filter_cb (GtkTreeModel *model,
2282                           GtkTreeIter  *iter,
2283                           gpointer      data)
2284 {
2285   GtkFileChooserDefault *impl;
2286   GtkTreePath *path;
2287   int pos;
2288
2289   impl = GTK_FILE_CHOOSER_DEFAULT (data);
2290
2291   path = gtk_tree_model_get_path (model, iter);
2292   if (!path)
2293     return FALSE;
2294
2295   pos = *gtk_tree_path_get_indices (path);
2296   gtk_tree_path_free (path);
2297
2298   return (pos < shortcuts_get_index (impl, SHORTCUTS_CURRENT_FOLDER_SEPARATOR));
2299 }
2300
2301 /* Creates the list model for shortcuts */
2302 static void
2303 shortcuts_model_create (GtkFileChooserDefault *impl)
2304 {
2305   /* Keep this order in sync with the SHORCUTS_COL_* enum values */
2306   impl->shortcuts_model = gtk_list_store_new (SHORTCUTS_COL_NUM_COLUMNS,
2307                                               GDK_TYPE_PIXBUF,  /* pixbuf */
2308                                               G_TYPE_STRING,    /* name */
2309                                               G_TYPE_POINTER,   /* path or volume */
2310                                               G_TYPE_INT,       /* ShortcutType */
2311                                               G_TYPE_BOOLEAN,   /* removable */
2312                                               G_TYPE_BOOLEAN,   /* pixbuf cell visibility */
2313                                               G_TYPE_POINTER);   /* GtkFileSystemHandle */
2314
2315   if (search_is_possible (impl))
2316     {
2317       shortcuts_append_search (impl);
2318       shortcuts_insert_separator (impl, SHORTCUTS_SEARCH_SEPARATOR);
2319     }
2320
2321   if (impl->recent_manager)
2322     {
2323       shortcuts_append_recent (impl);
2324       shortcuts_insert_separator (impl, SHORTCUTS_RECENT_SEPARATOR);
2325     }
2326   
2327   if (impl->file_system)
2328     {
2329       shortcuts_append_home (impl);
2330       shortcuts_append_desktop (impl);
2331       shortcuts_add_volumes (impl);
2332     }
2333
2334   impl->shortcuts_pane_filter_model = shortcuts_pane_model_filter_new (impl,
2335                                                                        GTK_TREE_MODEL (impl->shortcuts_model),
2336                                                                        NULL);
2337
2338   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (impl->shortcuts_pane_filter_model),
2339                                           shortcuts_pane_filter_cb,
2340                                           impl,
2341                                           NULL);
2342 }
2343
2344 /* Callback used when the "New Folder" button is clicked */
2345 static void
2346 new_folder_button_clicked (GtkButton             *button,
2347                            GtkFileChooserDefault *impl)
2348 {
2349   GtkTreeIter iter;
2350   GtkTreePath *path;
2351
2352   if (!impl->browse_files_model)
2353     return; /* FIXME: this sucks.  Disable the New Folder button or something. */
2354
2355   /* Prevent button from being clicked twice */
2356   gtk_widget_set_sensitive (impl->browse_new_folder_button, FALSE);
2357
2358   _gtk_file_system_model_add_editable (impl->browse_files_model, &iter);
2359
2360   path = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->browse_files_model), &iter);
2361   gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (impl->browse_files_tree_view),
2362                                 path, impl->list_name_column,
2363                                 FALSE, 0.0, 0.0);
2364
2365   g_object_set (impl->list_name_renderer, "editable", TRUE, NULL);
2366   gtk_tree_view_set_cursor (GTK_TREE_VIEW (impl->browse_files_tree_view),
2367                             path,
2368                             impl->list_name_column,
2369                             TRUE);
2370
2371   gtk_tree_path_free (path);
2372 }
2373
2374 static void
2375 edited_idle_create_folder_cb (GtkFileSystemHandle *handle,
2376                               const GtkFilePath   *path,
2377                               const GError        *error,
2378                               gpointer             data)
2379 {
2380   gboolean cancelled = handle->cancelled;
2381   GtkFileChooserDefault *impl = data;
2382
2383   if (!g_slist_find (impl->pending_handles, handle))
2384     goto out;
2385
2386   impl->pending_handles = g_slist_remove (impl->pending_handles, handle);
2387
2388   if (cancelled)
2389     goto out;
2390
2391   if (!error)
2392     change_folder_and_display_error (impl, path, FALSE);
2393   else
2394     error_creating_folder_dialog (impl, path, g_error_copy (error));
2395
2396  out:
2397   g_object_unref (impl);
2398   g_object_unref (handle);
2399 }
2400
2401 /* Idle handler for creating a new folder after editing its name cell, or for
2402  * canceling the editing.
2403  */
2404 static gboolean
2405 edited_idle_cb (GtkFileChooserDefault *impl)
2406 {
2407   GDK_THREADS_ENTER ();
2408   
2409   g_source_destroy (impl->edited_idle);
2410   impl->edited_idle = NULL;
2411
2412   _gtk_file_system_model_remove_editable (impl->browse_files_model);
2413   g_object_set (impl->list_name_renderer, "editable", FALSE, NULL);
2414
2415   gtk_widget_set_sensitive (impl->browse_new_folder_button, TRUE);
2416
2417   if (impl->edited_new_text) /* not cancelled? */
2418     {
2419       GError *error;
2420       GtkFilePath *file_path;
2421
2422       error = NULL;
2423       file_path = gtk_file_system_make_path (impl->file_system,
2424                                              impl->current_folder,
2425                                              impl->edited_new_text,
2426                                              &error);
2427       if (file_path)
2428         {
2429           GtkFileSystemHandle *handle;
2430
2431           handle = gtk_file_system_create_folder (impl->file_system, file_path,
2432                                                   edited_idle_create_folder_cb,
2433                                                   g_object_ref (impl));
2434           impl->pending_handles = g_slist_append (impl->pending_handles, handle);
2435
2436           gtk_file_path_free (file_path);
2437         }
2438       else
2439         error_creating_folder_dialog (impl, file_path, error);
2440
2441       g_free (impl->edited_new_text);
2442       impl->edited_new_text = NULL;
2443     }
2444
2445   GDK_THREADS_LEAVE ();
2446
2447   return FALSE;
2448 }
2449
2450 static void
2451 queue_edited_idle (GtkFileChooserDefault *impl,
2452                    const gchar           *new_text)
2453 {
2454   /* We create the folder in an idle handler so that we don't modify the tree
2455    * just now.
2456    */
2457
2458   if (!impl->edited_idle)
2459     {
2460       impl->edited_idle = g_idle_source_new ();
2461       g_source_set_closure (impl->edited_idle,
2462                             g_cclosure_new_object (G_CALLBACK (edited_idle_cb),
2463                                                    G_OBJECT (impl)));
2464       g_source_attach (impl->edited_idle, NULL);
2465     }
2466
2467   g_free (impl->edited_new_text);
2468   impl->edited_new_text = g_strdup (new_text);
2469 }
2470
2471 /* Callback used from the text cell renderer when the new folder is named */
2472 static void
2473 renderer_edited_cb (GtkCellRendererText   *cell_renderer_text,
2474                     const gchar           *path,
2475                     const gchar           *new_text,
2476                     GtkFileChooserDefault *impl)
2477 {
2478   /* work around bug #154921 */
2479   g_object_set (cell_renderer_text, 
2480                 "mode", GTK_CELL_RENDERER_MODE_INERT, NULL);
2481   queue_edited_idle (impl, new_text);
2482 }
2483
2484 /* Callback used from the text cell renderer when the new folder edition gets
2485  * canceled.
2486  */
2487 static void
2488 renderer_editing_canceled_cb (GtkCellRendererText   *cell_renderer_text,
2489                               GtkFileChooserDefault *impl)
2490 {
2491   /* work around bug #154921 */
2492   g_object_set (cell_renderer_text, 
2493                 "mode", GTK_CELL_RENDERER_MODE_INERT, NULL);
2494   queue_edited_idle (impl, NULL);
2495 }
2496
2497 /* Creates the widgets for the filter combo box */
2498 static GtkWidget *
2499 filter_create (GtkFileChooserDefault *impl)
2500 {
2501   impl->filter_combo = gtk_combo_box_new_text ();
2502   gtk_combo_box_set_focus_on_click (GTK_COMBO_BOX (impl->filter_combo), FALSE);
2503
2504   g_signal_connect (impl->filter_combo, "changed",
2505                     G_CALLBACK (filter_combo_changed), impl);
2506
2507   return impl->filter_combo;
2508 }
2509
2510 static GtkWidget *
2511 button_new (GtkFileChooserDefault *impl,
2512             const char            *text,
2513             const char            *stock_id,
2514             gboolean               sensitive,
2515             gboolean               show,
2516             GCallback              callback)
2517 {
2518   GtkWidget *button;
2519   GtkWidget *image;
2520
2521   button = gtk_button_new_with_mnemonic (text);
2522   image = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_BUTTON);
2523   gtk_button_set_image (GTK_BUTTON (button), image);
2524
2525   gtk_widget_set_sensitive (button, sensitive);
2526   g_signal_connect (button, "clicked", callback, impl);
2527
2528   if (show)
2529     gtk_widget_show (button);
2530
2531   return button;
2532 }
2533
2534 /* Looks for a path among the shortcuts; returns its index or -1 if it doesn't exist */
2535 static int
2536 shortcut_find_position (GtkFileChooserDefault *impl,
2537                         const GtkFilePath     *path)
2538 {
2539   GtkTreeIter iter;
2540   int i;
2541   int current_folder_separator_idx;
2542
2543   if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (impl->shortcuts_model), &iter))
2544     return -1;
2545
2546   current_folder_separator_idx = shortcuts_get_index (impl, SHORTCUTS_CURRENT_FOLDER_SEPARATOR);
2547
2548 #if 0
2549   /* FIXME: is this still needed? */
2550   if (current_folder_separator_idx >= impl->shortcuts_model->length)
2551     return -1;
2552 #endif
2553
2554   for (i = 0; i < current_folder_separator_idx; i++)
2555     {
2556       gpointer col_data;
2557       ShortcutType shortcut_type;
2558
2559       gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter,
2560                           SHORTCUTS_COL_DATA, &col_data,
2561                           SHORTCUTS_COL_TYPE, &shortcut_type,
2562                           -1);
2563
2564       if (col_data)
2565         {
2566           if (shortcut_type == SHORTCUT_TYPE_VOLUME)
2567             {
2568               GtkFileSystemVolume *volume;
2569               GtkFilePath *base_path;
2570               gboolean exists;
2571
2572               volume = col_data;
2573               base_path = gtk_file_system_volume_get_base_path (impl->file_system, volume);
2574
2575               exists = base_path && strcmp (gtk_file_path_get_string (path),
2576                                             gtk_file_path_get_string (base_path)) == 0;
2577               g_free (base_path);
2578
2579               if (exists)
2580                 return i;
2581             }
2582           else if (shortcut_type == SHORTCUT_TYPE_PATH)
2583             {
2584               GtkFilePath *model_path;
2585
2586               model_path = col_data;
2587
2588               if (model_path && gtk_file_path_compare (model_path, path) == 0)
2589                 return i;
2590             }
2591         }
2592
2593       if (i < current_folder_separator_idx - 1)
2594         {
2595           if (!gtk_tree_model_iter_next (GTK_TREE_MODEL (impl->shortcuts_model), &iter))
2596             g_assert_not_reached ();
2597         }
2598     }
2599
2600   return -1;
2601 }
2602
2603 /* Tries to add a bookmark from a path name */
2604 static gboolean
2605 shortcuts_add_bookmark_from_path (GtkFileChooserDefault *impl,
2606                                   const GtkFilePath     *path,
2607                                   int                    pos)
2608 {
2609   GError *error;
2610
2611   g_return_val_if_fail (path != NULL, FALSE);
2612  
2613   if (shortcut_find_position (impl, path) != -1)
2614     return FALSE;
2615
2616   error = NULL;
2617   if (!gtk_file_system_insert_bookmark (impl->file_system, path, pos, &error))
2618     {
2619       error_adding_bookmark_dialog (impl, path, error);
2620       return FALSE;
2621     }
2622
2623   return TRUE;
2624 }
2625
2626 static void
2627 add_bookmark_foreach_cb (GtkTreeModel *model,
2628                          GtkTreePath  *path,
2629                          GtkTreeIter  *iter,
2630                          gpointer      data)
2631 {
2632   GtkFileChooserDefault *impl;
2633   GtkFileSystemModel *fs_model;
2634   GtkTreeIter child_iter;
2635   const GtkFilePath *file_path;
2636
2637   impl = (GtkFileChooserDefault *) data;
2638
2639   switch (impl->operation_mode)
2640     {
2641     case OPERATION_MODE_BROWSE:
2642       fs_model = impl->browse_files_model;
2643       gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model, &child_iter, iter);
2644       file_path = _gtk_file_system_model_get_path (fs_model, &child_iter);
2645       break;
2646
2647     case OPERATION_MODE_SEARCH:
2648       gtk_tree_model_filter_convert_iter_to_child_iter (impl->search_model_filter,
2649                                                         &child_iter, iter);
2650       gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &child_iter,
2651                           SEARCH_MODEL_COL_PATH, &file_path,
2652                           -1);
2653       break;
2654
2655     case OPERATION_MODE_RECENT:
2656       gtk_tree_model_filter_convert_iter_to_child_iter (impl->recent_model_filter,
2657                                                         &child_iter, iter);
2658       gtk_tree_model_get (GTK_TREE_MODEL (impl->recent_model), &child_iter,
2659                           RECENT_MODEL_COL_PATH, &file_path,
2660                           -1);
2661       break;
2662     }
2663   
2664   shortcuts_add_bookmark_from_path (impl, file_path, -1);
2665 }
2666
2667 /* Adds a bookmark from the currently selected item in the file list */
2668 static void
2669 bookmarks_add_selected_folder (GtkFileChooserDefault *impl)
2670 {
2671   GtkTreeSelection *selection;
2672
2673   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
2674
2675   if (gtk_tree_selection_count_selected_rows (selection) == 0)
2676     shortcuts_add_bookmark_from_path (impl, impl->current_folder, -1);
2677   else
2678     gtk_tree_selection_selected_foreach (selection,
2679                                          add_bookmark_foreach_cb,
2680                                          impl);
2681 }
2682
2683 /* Callback used when the "Add bookmark" button is clicked */
2684 static void
2685 add_bookmark_button_clicked_cb (GtkButton *button,
2686                                 GtkFileChooserDefault *impl)
2687 {
2688   bookmarks_add_selected_folder (impl);
2689 }
2690
2691 /* Returns TRUE plus an iter in the shortcuts_model if a row is selected;
2692  * returns FALSE if no shortcut is selected.
2693  */
2694 static gboolean
2695 shortcuts_get_selected (GtkFileChooserDefault *impl,
2696                         GtkTreeIter           *iter)
2697 {
2698   GtkTreeSelection *selection;
2699   GtkTreeIter parent_iter;
2700
2701   if (!impl->browse_shortcuts_tree_view)
2702     return FALSE;
2703
2704   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view));
2705
2706   if (!gtk_tree_selection_get_selected (selection, NULL, &parent_iter))
2707     return FALSE;
2708
2709   gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (impl->shortcuts_pane_filter_model),
2710                                                     iter,
2711                                                     &parent_iter);
2712   return TRUE;
2713 }
2714
2715 /* Removes the selected bookmarks */
2716 static void
2717 remove_selected_bookmarks (GtkFileChooserDefault *impl)
2718 {
2719   GtkTreeIter iter;
2720   gpointer col_data;
2721   GtkFilePath *path;
2722   gboolean removable;
2723   GError *error;
2724
2725   if (!shortcuts_get_selected (impl, &iter))
2726     return;
2727
2728   gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter,
2729                       SHORTCUTS_COL_DATA, &col_data,
2730                       SHORTCUTS_COL_REMOVABLE, &removable,
2731                       -1);
2732
2733   if (!removable)
2734     return;
2735
2736   g_assert (col_data != NULL);
2737
2738   path = col_data;
2739
2740   error = NULL;
2741   if (!gtk_file_system_remove_bookmark (impl->file_system, path, &error))
2742     error_removing_bookmark_dialog (impl, path, error);
2743 }
2744
2745 /* Callback used when the "Remove bookmark" button is clicked */
2746 static void
2747 remove_bookmark_button_clicked_cb (GtkButton *button,
2748                                    GtkFileChooserDefault *impl)
2749 {
2750   remove_selected_bookmarks (impl);
2751 }
2752
2753 struct selection_check_closure {
2754   GtkFileChooserDefault *impl;
2755   int num_selected;
2756   gboolean all_files;
2757   gboolean all_folders;
2758 };
2759
2760 /* Used from gtk_tree_selection_selected_foreach() */
2761 static void
2762 selection_check_foreach_cb (GtkTreeModel *model,
2763                             GtkTreePath  *path,
2764                             GtkTreeIter  *iter,
2765                             gpointer      data)
2766 {
2767   struct selection_check_closure *closure;
2768   GtkTreeIter child_iter;
2769   const GtkFileInfo *info;
2770   gboolean is_folder;
2771
2772   closure = data;
2773   closure->num_selected++;
2774
2775   switch (closure->impl->operation_mode)
2776     {
2777     case OPERATION_MODE_BROWSE:
2778       gtk_tree_model_sort_convert_iter_to_child_iter (closure->impl->sort_model, &child_iter, iter);
2779       info = _gtk_file_system_model_get_info (closure->impl->browse_files_model, &child_iter);
2780       is_folder = info ? gtk_file_info_get_is_folder (info) : FALSE;
2781       break;
2782
2783     case OPERATION_MODE_SEARCH:
2784       gtk_tree_model_filter_convert_iter_to_child_iter (closure->impl->search_model_filter, &child_iter, iter);
2785       gtk_tree_model_get (GTK_TREE_MODEL (closure->impl->search_model), &child_iter,
2786                           SEARCH_MODEL_COL_IS_FOLDER, &is_folder,
2787                           -1);
2788       break;
2789
2790     case OPERATION_MODE_RECENT:
2791       gtk_tree_model_filter_convert_iter_to_child_iter (closure->impl->recent_model_filter, &child_iter, iter);
2792       gtk_tree_model_get (GTK_TREE_MODEL (closure->impl->recent_model), &child_iter,
2793                           RECENT_MODEL_COL_IS_FOLDER, &is_folder,
2794                           -1);
2795       break;
2796     }
2797
2798   closure->all_folders = closure->all_folders && is_folder;
2799   closure->all_files = closure->all_files && !is_folder;
2800 }
2801
2802 /* Checks whether the selected items in the file list are all files or all folders */
2803 static void
2804 selection_check (GtkFileChooserDefault *impl,
2805                  gint                  *num_selected,
2806                  gboolean              *all_files,
2807                  gboolean              *all_folders)
2808 {
2809   struct selection_check_closure closure;
2810   GtkTreeSelection *selection;
2811
2812   closure.impl = impl;
2813   closure.num_selected = 0;
2814   closure.all_files = TRUE;
2815   closure.all_folders = TRUE;
2816
2817   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
2818   gtk_tree_selection_selected_foreach (selection,
2819                                        selection_check_foreach_cb,
2820                                        &closure);
2821
2822   g_assert (closure.num_selected == 0 || !(closure.all_files && closure.all_folders));
2823
2824   if (num_selected)
2825     *num_selected = closure.num_selected;
2826
2827   if (all_files)
2828     *all_files = closure.all_files;
2829
2830   if (all_folders)
2831     *all_folders = closure.all_folders;
2832 }
2833
2834 struct get_selected_path_closure {
2835   GtkFileChooserDefault *impl;
2836   const GtkFilePath *path;
2837 };
2838
2839 static void
2840 get_selected_path_foreach_cb (GtkTreeModel *model,
2841                               GtkTreePath  *path,
2842                               GtkTreeIter  *iter,
2843                               gpointer      data)
2844 {
2845   struct get_selected_path_closure *closure;
2846   GtkTreeIter child_iter;
2847
2848   closure = data;
2849
2850   switch (closure->impl->operation_mode)
2851     {
2852     case OPERATION_MODE_BROWSE:
2853       gtk_tree_model_sort_convert_iter_to_child_iter (closure->impl->sort_model, &child_iter, iter);
2854       closure->path = _gtk_file_system_model_get_path (closure->impl->browse_files_model, &child_iter);
2855       break;
2856
2857     case OPERATION_MODE_SEARCH:
2858       gtk_tree_model_filter_convert_iter_to_child_iter (closure->impl->search_model_filter, &child_iter, iter);
2859       gtk_tree_model_get (GTK_TREE_MODEL (closure->impl->search_model), &child_iter,
2860                           SEARCH_MODEL_COL_PATH, &closure->path,
2861                           -1);
2862       break;
2863
2864     case OPERATION_MODE_RECENT:
2865       gtk_tree_model_filter_convert_iter_to_child_iter (closure->impl->recent_model_filter, &child_iter, iter);
2866       gtk_tree_model_get (GTK_TREE_MODEL (closure->impl->recent_model), &child_iter,
2867                           RECENT_MODEL_COL_PATH, &closure->path,
2868                           -1);
2869       break;
2870     }
2871 }
2872
2873 /* Returns a selected path from the file list */
2874 static const GtkFilePath *
2875 get_selected_path (GtkFileChooserDefault *impl)
2876 {
2877   struct get_selected_path_closure closure;
2878   GtkTreeSelection *selection;
2879
2880   closure.impl = impl;
2881   closure.path = NULL;
2882
2883   selection =  gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
2884   gtk_tree_selection_selected_foreach (selection,
2885                                        get_selected_path_foreach_cb,
2886                                        &closure);
2887
2888   return closure.path;
2889 }
2890
2891 typedef struct {
2892   GtkFileChooserDefault *impl;
2893   gchar *tip;
2894 } UpdateTooltipData;
2895
2896 static void 
2897 update_tooltip (GtkTreeModel      *model,
2898                 GtkTreePath       *path,
2899                 GtkTreeIter       *iter,
2900                 gpointer           data)
2901 {
2902   UpdateTooltipData *udata = data;
2903   GtkTreeIter child_iter;
2904   const GtkFileInfo *info;
2905
2906   if (udata->tip == NULL)
2907     {
2908       const gchar *display_name;
2909
2910       switch (udata->impl->operation_mode)
2911         {
2912         case OPERATION_MODE_BROWSE:
2913           gtk_tree_model_sort_convert_iter_to_child_iter (udata->impl->sort_model,
2914                                                           &child_iter,
2915                                                           iter);
2916           info = _gtk_file_system_model_get_info (udata->impl->browse_files_model, &child_iter);
2917           display_name = gtk_file_info_get_display_name (info);
2918           break;
2919
2920         case OPERATION_MODE_SEARCH:
2921           gtk_tree_model_filter_convert_iter_to_child_iter (udata->impl->search_model_filter, &child_iter, iter);
2922           gtk_tree_model_get (GTK_TREE_MODEL (udata->impl->search_model), &child_iter,
2923                               SEARCH_MODEL_COL_DISPLAY_NAME, &display_name,
2924                               -1);
2925           break;
2926
2927         case OPERATION_MODE_RECENT:
2928           gtk_tree_model_filter_convert_iter_to_child_iter (udata->impl->recent_model_filter, &child_iter, iter);
2929           gtk_tree_model_get (GTK_TREE_MODEL (udata->impl->recent_model), &child_iter,
2930                               RECENT_MODEL_COL_DISPLAY_NAME, &display_name,
2931                               -1);
2932           break;
2933         }
2934
2935       udata->tip = g_strdup_printf (_("Add the folder '%s' to the bookmarks"),
2936                                     display_name);
2937     }
2938 }
2939
2940
2941 /* Sensitize the "add bookmark" button if all the selected items are folders, or
2942  * if there are no selected items *and* the current folder is not in the
2943  * bookmarks list.  De-sensitize the button otherwise.
2944  */
2945 static void
2946 bookmarks_check_add_sensitivity (GtkFileChooserDefault *impl)
2947 {
2948   gint num_selected;
2949   gboolean all_folders;
2950   gboolean active;
2951   gchar *tip;
2952
2953   selection_check (impl, &num_selected, NULL, &all_folders);
2954
2955   if (num_selected == 0)
2956     active = (impl->current_folder != NULL) && (shortcut_find_position (impl, impl->current_folder) == -1);
2957   else if (num_selected == 1)
2958     {
2959       const GtkFilePath *path;
2960
2961       path = get_selected_path (impl);
2962       active = all_folders && (shortcut_find_position (impl, path) == -1);
2963     }
2964   else
2965     active = all_folders;
2966
2967   gtk_widget_set_sensitive (impl->browse_shortcuts_add_button, active);
2968
2969   if (impl->browse_files_popup_menu_add_shortcut_item)
2970     gtk_widget_set_sensitive (impl->browse_files_popup_menu_add_shortcut_item,
2971                               (num_selected == 0) ? FALSE : active);
2972
2973   if (active)
2974     {
2975       if (num_selected == 0)
2976         tip = g_strdup_printf (_("Add the current folder to the bookmarks"));
2977       else if (num_selected > 1)
2978         tip = g_strdup_printf (_("Add the selected folders to the bookmarks"));
2979       else
2980         {
2981           GtkTreeSelection *selection;
2982           UpdateTooltipData data;
2983
2984           selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
2985           data.impl = impl;
2986           data.tip = NULL;
2987           gtk_tree_selection_selected_foreach (selection, update_tooltip, &data);
2988           tip = data.tip;
2989         }
2990
2991       gtk_tooltips_set_tip (impl->tooltips, impl->browse_shortcuts_add_button, tip, NULL);
2992       g_free (tip);
2993     }
2994 }
2995
2996 /* Sets the sensitivity of the "remove bookmark" button depending on whether a
2997  * bookmark row is selected in the shortcuts tree.
2998  */
2999 static void
3000 bookmarks_check_remove_sensitivity (GtkFileChooserDefault *impl)
3001 {
3002   GtkTreeIter iter;
3003   gboolean removable = FALSE;
3004   gchar *name = NULL;
3005   
3006   if (shortcuts_get_selected (impl, &iter))
3007     gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter,
3008                         SHORTCUTS_COL_REMOVABLE, &removable,
3009                         SHORTCUTS_COL_NAME, &name,
3010                         -1);
3011
3012   gtk_widget_set_sensitive (impl->browse_shortcuts_remove_button, removable);
3013
3014   if (removable)
3015     {
3016       gchar *tip;
3017
3018       tip = g_strdup_printf (_("Remove the bookmark '%s'"), name);
3019       gtk_tooltips_set_tip (impl->tooltips, impl->browse_shortcuts_remove_button,
3020                             tip, NULL);
3021       g_free (tip);
3022     }
3023
3024   g_free (name);
3025 }
3026
3027 static void
3028 shortcuts_check_popup_sensitivity (GtkFileChooserDefault *impl)
3029 {
3030   GtkTreeIter iter;
3031   gboolean removable = FALSE;
3032
3033   if (impl->browse_shortcuts_popup_menu == NULL)
3034     return;
3035
3036   if (shortcuts_get_selected (impl, &iter))
3037     gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter,
3038                         SHORTCUTS_COL_REMOVABLE, &removable,
3039                         -1);
3040
3041   gtk_widget_set_sensitive (impl->browse_shortcuts_popup_menu_remove_item, removable);
3042   gtk_widget_set_sensitive (impl->browse_shortcuts_popup_menu_rename_item, removable);
3043 }
3044
3045 /* GtkWidget::drag-begin handler for the shortcuts list. */
3046 static void
3047 shortcuts_drag_begin_cb (GtkWidget             *widget,
3048                          GdkDragContext        *context,
3049                          GtkFileChooserDefault *impl)
3050 {
3051 #if 0
3052   impl->shortcuts_drag_context = g_object_ref (context);
3053 #endif
3054 }
3055
3056 #if 0
3057 /* Removes the idle handler for outside drags */
3058 static void
3059 shortcuts_cancel_drag_outside_idle (GtkFileChooserDefault *impl)
3060 {
3061   if (!impl->shortcuts_drag_outside_idle)
3062     return;
3063
3064   g_source_destroy (impl->shortcuts_drag_outside_idle);
3065   impl->shortcuts_drag_outside_idle = NULL;
3066 }
3067 #endif
3068
3069 /* GtkWidget::drag-end handler for the shortcuts list. */
3070 static void
3071 shortcuts_drag_end_cb (GtkWidget             *widget,
3072                        GdkDragContext        *context,
3073                        GtkFileChooserDefault *impl)
3074 {
3075 #if 0
3076   g_object_unref (impl->shortcuts_drag_context);
3077
3078   shortcuts_cancel_drag_outside_idle (impl);
3079
3080   if (!impl->shortcuts_drag_outside)
3081     return;
3082
3083   gtk_button_clicked (GTK_BUTTON (impl->browse_shortcuts_remove_button));
3084
3085   impl->shortcuts_drag_outside = FALSE;
3086 #endif
3087 }
3088
3089 /* GtkWidget::drag-data-delete handler for the shortcuts list. */
3090 static void
3091 shortcuts_drag_data_delete_cb (GtkWidget             *widget,
3092                                GdkDragContext        *context,
3093                                GtkFileChooserDefault *impl)
3094 {
3095   g_signal_stop_emission_by_name (widget, "drag_data_delete");
3096 }
3097
3098 #if 0
3099 /* Creates a suitable drag cursor to indicate that the selected bookmark will be
3100  * deleted or not.
3101  */
3102 static void
3103 shortcuts_drag_set_delete_cursor (GtkFileChooserDefault *impl,
3104                                   gboolean               delete)
3105 {
3106   GtkTreeView *tree_view;
3107   GtkTreeIter iter;
3108   GtkTreePath *path;
3109   GdkPixmap *row_pixmap;
3110   GdkBitmap *mask;
3111   int row_pixmap_y;
3112   int cell_y;
3113
3114   tree_view = GTK_TREE_VIEW (impl->browse_shortcuts_tree_view);
3115
3116   /* Find the selected path and get its drag pixmap */
3117
3118   if (!shortcuts_get_selected (impl, &iter))
3119     g_assert_not_reached ();
3120
3121   path = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->shortcuts_model), &iter);
3122
3123   row_pixmap = gtk_tree_view_create_row_drag_icon (tree_view, path);
3124   gtk_tree_path_free (path);
3125
3126   mask = NULL;
3127   row_pixmap_y = 0;
3128
3129   if (delete)
3130     {
3131       GdkPixbuf *pixbuf;
3132
3133       pixbuf = gtk_widget_render_icon (impl->browse_shortcuts_tree_view,
3134                                        GTK_STOCK_DELETE,
3135                                        GTK_ICON_SIZE_DND,
3136                                        NULL);
3137       if (pixbuf)
3138         {
3139           GdkPixmap *composite;
3140           int row_pixmap_width, row_pixmap_height;
3141           int pixbuf_width, pixbuf_height;
3142           int composite_width, composite_height;
3143           int pixbuf_x, pixbuf_y;
3144           GdkGC *gc, *mask_gc;
3145           GdkColor color;
3146           GdkBitmap *pixbuf_mask;
3147
3148           /* Create pixmap and mask for composite image */
3149
3150           gdk_drawable_get_size (row_pixmap, &row_pixmap_width, &row_pixmap_height);
3151           pixbuf_width = gdk_pixbuf_get_width (pixbuf);
3152           pixbuf_height = gdk_pixbuf_get_height (pixbuf);
3153
3154           composite_width = MAX (row_pixmap_width, pixbuf_width);
3155           composite_height = MAX (row_pixmap_height, pixbuf_height);
3156
3157           row_pixmap_y = (composite_height - row_pixmap_height) / 2;
3158
3159           if (gtk_widget_get_direction (impl->browse_shortcuts_tree_view) == GTK_TEXT_DIR_RTL)
3160             pixbuf_x = 0;
3161           else
3162             pixbuf_x = composite_width - pixbuf_width;
3163
3164           pixbuf_y = (composite_height - pixbuf_height) / 2;
3165
3166           composite = gdk_pixmap_new (row_pixmap, composite_width, composite_height, -1);
3167           gc = gdk_gc_new (composite);
3168
3169           mask = gdk_pixmap_new (row_pixmap, composite_width, composite_height, 1);
3170           mask_gc = gdk_gc_new (mask);
3171           color.pixel = 0;
3172           gdk_gc_set_foreground (mask_gc, &color);
3173           gdk_draw_rectangle (mask, mask_gc, TRUE, 0, 0, composite_width, composite_height);
3174
3175           color.red = 0xffff;
3176           color.green = 0xffff;
3177           color.blue = 0xffff;
3178           gdk_gc_set_rgb_fg_color (gc, &color);
3179           gdk_draw_rectangle (composite, gc, TRUE, 0, 0, composite_width, composite_height);
3180
3181           /* Composite the row pixmap and the pixbuf */
3182
3183           gdk_pixbuf_render_pixmap_and_mask_for_colormap
3184             (pixbuf,
3185              gtk_widget_get_colormap (impl->browse_shortcuts_tree_view),
3186              NULL, &pixbuf_mask, 128);
3187           gdk_draw_drawable (mask, mask_gc, pixbuf_mask,
3188                              0, 0,
3189                              pixbuf_x, pixbuf_y,
3190                              pixbuf_width, pixbuf_height);
3191           g_object_unref (pixbuf_mask);
3192
3193           gdk_draw_drawable (composite, gc, row_pixmap,
3194                              0, 0,
3195                              0, row_pixmap_y,
3196                              row_pixmap_width, row_pixmap_height);
3197           color.pixel = 1;
3198           gdk_gc_set_foreground (mask_gc, &color);
3199           gdk_draw_rectangle (mask, mask_gc, TRUE, 0, row_pixmap_y, row_pixmap_width, row_pixmap_height);
3200
3201           gdk_draw_pixbuf (composite, gc, pixbuf,
3202                            0, 0,
3203                            pixbuf_x, pixbuf_y,
3204                            pixbuf_width, pixbuf_height,
3205                            GDK_RGB_DITHER_MAX,
3206                            0, 0);
3207
3208           g_object_unref (pixbuf);
3209           g_object_unref (row_pixmap);
3210
3211           row_pixmap = composite;
3212         }
3213     }
3214
3215   /* The hotspot offsets here are copied from gtk_tree_view_drag_begin(), ugh */
3216
3217   gtk_tree_view_get_path_at_pos (tree_view,
3218                                  tree_view->priv->press_start_x,
3219                                  tree_view->priv->press_start_y,
3220                                  NULL,
3221                                  NULL,
3222                                  NULL,
3223                                  &cell_y);
3224
3225   gtk_drag_set_icon_pixmap (impl->shortcuts_drag_context,
3226                             gdk_drawable_get_colormap (row_pixmap),
3227                             row_pixmap,
3228                             mask,
3229                             tree_view->priv->press_start_x + 1,
3230                             row_pixmap_y + cell_y + 1);
3231
3232   g_object_unref (row_pixmap);
3233   if (mask)
3234     g_object_unref (mask);
3235 }
3236
3237 /* We set the delete cursor and the shortcuts_drag_outside flag in an idle
3238  * handler so that we can tell apart the drag_leave event that comes right
3239  * before a drag_drop, from a normal drag_leave.  We don't want to set the
3240  * cursor nor the flag in the latter case.
3241  */
3242 static gboolean
3243 shortcuts_drag_outside_idle_cb (GtkFileChooserDefault *impl)
3244 {
3245   GDK_THREADS_ENTER ();
3246   
3247   shortcuts_drag_set_delete_cursor (impl, TRUE);
3248   impl->shortcuts_drag_outside = TRUE;
3249
3250   shortcuts_cancel_drag_outside_idle (impl);
3251
3252   GDK_THREADS_LEAVE ();
3253
3254   return FALSE;
3255 }
3256 #endif
3257
3258 /* GtkWidget::drag-leave handler for the shortcuts list.  We unhighlight the
3259  * drop position.
3260  */
3261 static void
3262 shortcuts_drag_leave_cb (GtkWidget             *widget,
3263                          GdkDragContext        *context,
3264                          guint                  time_,
3265                          GtkFileChooserDefault *impl)
3266 {
3267 #if 0
3268   if (gtk_drag_get_source_widget (context) == widget && !impl->shortcuts_drag_outside_idle)
3269     {
3270       impl->shortcuts_drag_outside_idle = g_idle_source_new ();
3271       g_source_set_closure (impl->shortcuts_drag_outside_idle,
3272                             g_cclosure_new_object (G_CALLBACK (shortcuts_drag_outside_idle_cb),
3273                                                    G_OBJECT (impl)));
3274       g_source_attach (impl->shortcuts_drag_outside_idle, NULL);
3275     }
3276 #endif
3277
3278   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view),
3279                                    NULL,
3280                                    GTK_TREE_VIEW_DROP_BEFORE);
3281
3282   g_signal_stop_emission_by_name (widget, "drag_leave");
3283 }
3284
3285 /* Computes the appropriate row and position for dropping */
3286 static void
3287 shortcuts_compute_drop_position (GtkFileChooserDefault   *impl,
3288                                  int                      x,
3289                                  int                      y,
3290                                  GtkTreePath            **path,
3291                                  GtkTreeViewDropPosition *pos)
3292 {
3293   GtkTreeView *tree_view;
3294   GtkTreeViewColumn *column;
3295   int cell_y;
3296   GdkRectangle cell;
3297   int row;
3298   int bookmarks_index;
3299
3300   tree_view = GTK_TREE_VIEW (impl->browse_shortcuts_tree_view);
3301
3302   bookmarks_index = shortcuts_get_index (impl, SHORTCUTS_BOOKMARKS);
3303
3304   if (!gtk_tree_view_get_path_at_pos (tree_view,
3305                                       x,
3306                                       y - TREE_VIEW_HEADER_HEIGHT (tree_view),
3307                                       path,
3308                                       &column,
3309                                       NULL,
3310                                       &cell_y))
3311     {
3312       row = bookmarks_index + impl->num_bookmarks - 1;
3313       *path = gtk_tree_path_new_from_indices (row, -1);
3314       *pos = GTK_TREE_VIEW_DROP_AFTER;
3315       return;
3316     }
3317
3318   row = *gtk_tree_path_get_indices (*path);
3319   gtk_tree_view_get_background_area (tree_view, *path, column, &cell);
3320   gtk_tree_path_free (*path);
3321
3322   if (row < bookmarks_index)
3323     {
3324       row = bookmarks_index;
3325       *pos = GTK_TREE_VIEW_DROP_BEFORE;
3326     }
3327   else if (row > bookmarks_index + impl->num_bookmarks - 1)
3328     {
3329       row = bookmarks_index + impl->num_bookmarks - 1;
3330       *pos = GTK_TREE_VIEW_DROP_AFTER;
3331     }
3332   else
3333     {
3334       if (cell_y < cell.height / 2)
3335         *pos = GTK_TREE_VIEW_DROP_BEFORE;
3336       else
3337         *pos = GTK_TREE_VIEW_DROP_AFTER;
3338     }
3339
3340   *path = gtk_tree_path_new_from_indices (row, -1);
3341 }
3342
3343 /* GtkWidget::drag-motion handler for the shortcuts list.  We basically
3344  * implement the destination side of DnD by hand, due to limitations in
3345  * GtkTreeView's DnD API.
3346  */
3347 static gboolean
3348 shortcuts_drag_motion_cb (GtkWidget             *widget,
3349                           GdkDragContext        *context,
3350                           gint                   x,
3351                           gint                   y,
3352                           guint                  time_,
3353                           GtkFileChooserDefault *impl)
3354 {
3355   GtkTreePath *path;
3356   GtkTreeViewDropPosition pos;
3357   GdkDragAction action;
3358
3359 #if 0
3360   if (gtk_drag_get_source_widget (context) == widget)
3361     {
3362       shortcuts_cancel_drag_outside_idle (impl);
3363
3364       if (impl->shortcuts_drag_outside)
3365         {
3366           shortcuts_drag_set_delete_cursor (impl, FALSE);
3367           impl->shortcuts_drag_outside = FALSE;
3368         }
3369     }
3370 #endif
3371
3372   if (context->suggested_action == GDK_ACTION_COPY ||
3373       (context->actions & GDK_ACTION_COPY) != 0)
3374     action = GDK_ACTION_COPY;
3375   else if (context->suggested_action == GDK_ACTION_MOVE ||
3376            (context->actions & GDK_ACTION_MOVE) != 0)
3377     action = GDK_ACTION_MOVE;
3378   else
3379     {
3380       action = 0;
3381       goto out;
3382     }
3383
3384   shortcuts_compute_drop_position (impl, x, y, &path, &pos);
3385   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view), path, pos);
3386   gtk_tree_path_free (path);
3387
3388  out:
3389
3390   g_signal_stop_emission_by_name (widget, "drag_motion");
3391
3392   if (action != 0)
3393     {
3394       gdk_drag_status (context, action, time_);
3395       return TRUE;
3396     }
3397   else
3398     return FALSE;
3399 }
3400
3401 /* GtkWidget::drag-drop handler for the shortcuts list. */
3402 static gboolean
3403 shortcuts_drag_drop_cb (GtkWidget             *widget,
3404                         GdkDragContext        *context,
3405                         gint                   x,
3406                         gint                   y,
3407                         guint                  time_,
3408                         GtkFileChooserDefault *impl)
3409 {
3410 #if 0
3411   shortcuts_cancel_drag_outside_idle (impl);
3412 #endif
3413
3414   g_signal_stop_emission_by_name (widget, "drag_drop");
3415   return TRUE;
3416 }
3417
3418 /* Parses a "text/uri-list" string and inserts its URIs as bookmarks */
3419 static void
3420 shortcuts_drop_uris (GtkFileChooserDefault *impl,
3421                      const char            *data,
3422                      int                    position)
3423 {
3424   gchar **uris;
3425   gint i;
3426
3427   uris = g_uri_list_extract_uris (data);
3428
3429   for (i = 0; uris[i]; i++)
3430     {
3431       char *uri;
3432       GtkFilePath *path;
3433
3434       uri = uris[i];
3435       path = gtk_file_system_uri_to_path (impl->file_system, uri);
3436
3437       if (path)
3438         {
3439           if (shortcuts_add_bookmark_from_path (impl, path, position))
3440             position++;
3441
3442           gtk_file_path_free (path);
3443         }
3444       else
3445         {
3446           GError *error;
3447
3448           g_set_error (&error,
3449                        GTK_FILE_CHOOSER_ERROR,
3450                        GTK_FILE_CHOOSER_ERROR_BAD_FILENAME,
3451                        _("Could not add a bookmark for '%s' "
3452                          "because it is an invalid path name."),
3453                        uri);
3454           error_adding_bookmark_dialog (impl, path, error);
3455         }
3456     }
3457
3458   g_strfreev (uris);
3459 }
3460
3461 /* Reorders the selected bookmark to the specified position */
3462 static void
3463 shortcuts_reorder (GtkFileChooserDefault *impl,
3464                    int                    new_position)
3465 {
3466   GtkTreeIter iter;
3467   gpointer col_data;
3468   ShortcutType shortcut_type;
3469   GtkTreePath *path;
3470   int old_position;
3471   int bookmarks_index;
3472   const GtkFilePath *file_path;
3473   GtkFilePath *file_path_copy;
3474   GError *error;
3475   gchar *name;
3476
3477   /* Get the selected path */
3478
3479   if (!shortcuts_get_selected (impl, &iter))
3480     g_assert_not_reached ();
3481
3482   path = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->shortcuts_model), &iter);
3483   old_position = *gtk_tree_path_get_indices (path);
3484   gtk_tree_path_free (path);
3485
3486   bookmarks_index = shortcuts_get_index (impl, SHORTCUTS_BOOKMARKS);
3487   old_position -= bookmarks_index;
3488   g_assert (old_position >= 0 && old_position < impl->num_bookmarks);
3489
3490   gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter,
3491                       SHORTCUTS_COL_NAME, &name,
3492                       SHORTCUTS_COL_DATA, &col_data,
3493                       SHORTCUTS_COL_TYPE, &shortcut_type,
3494                       -1);
3495   g_assert (col_data != NULL);
3496   g_assert (shortcut_type == SHORTCUT_TYPE_PATH);
3497   
3498   file_path = col_data;
3499   file_path_copy = gtk_file_path_copy (file_path); /* removal below will free file_path, so we need a copy */
3500
3501   /* Remove the path from the old position and insert it in the new one */
3502
3503   if (new_position > old_position)
3504     new_position--;
3505
3506   if (old_position == new_position)
3507     goto out;
3508
3509   error = NULL;
3510   if (gtk_file_system_remove_bookmark (impl->file_system, file_path_copy, &error))
3511     {
3512       shortcuts_add_bookmark_from_path (impl, file_path_copy, new_position);
3513       gtk_file_system_set_bookmark_label (impl->file_system, file_path_copy, name);
3514     }
3515   else
3516     error_adding_bookmark_dialog (impl, file_path_copy, error);
3517
3518  out:
3519
3520   gtk_file_path_free (file_path_copy);
3521 }
3522
3523 /* Callback used when we get the drag data for the bookmarks list.  We add the
3524  * received URIs as bookmarks if they are folders.
3525  */
3526 static void
3527 shortcuts_drag_data_received_cb (GtkWidget          *widget,
3528                                  GdkDragContext     *context,
3529                                  gint                x,
3530                                  gint                y,
3531                                  GtkSelectionData   *selection_data,
3532                                  guint               info,
3533                                  guint               time_,
3534                                  gpointer            data)
3535 {
3536   GtkFileChooserDefault *impl;
3537   GtkTreePath *tree_path;
3538   GtkTreeViewDropPosition tree_pos;
3539   int position;
3540   int bookmarks_index;
3541
3542   impl = GTK_FILE_CHOOSER_DEFAULT (data);
3543
3544   /* Compute position */
3545
3546   bookmarks_index = shortcuts_get_index (impl, SHORTCUTS_BOOKMARKS);
3547
3548   shortcuts_compute_drop_position (impl, x, y, &tree_path, &tree_pos);
3549   position = *gtk_tree_path_get_indices (tree_path);
3550   gtk_tree_path_free (tree_path);
3551
3552   if (tree_pos == GTK_TREE_VIEW_DROP_AFTER)
3553     position++;
3554
3555   g_assert (position >= bookmarks_index);
3556   position -= bookmarks_index;
3557
3558   if (selection_data->target == gdk_atom_intern_static_string ("text/uri-list"))
3559     shortcuts_drop_uris (impl, (const char *) selection_data->data, position);
3560   else if (selection_data->target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
3561     shortcuts_reorder (impl, position);
3562
3563   g_signal_stop_emission_by_name (widget, "drag_data_received");
3564 }
3565
3566 /* Callback used when the selection in the shortcuts tree changes */
3567 static void
3568 shortcuts_selection_changed_cb (GtkTreeSelection      *selection,
3569                                 GtkFileChooserDefault *impl)
3570 {
3571   bookmarks_check_remove_sensitivity (impl);
3572   shortcuts_check_popup_sensitivity (impl);
3573 }
3574
3575 static gboolean
3576 shortcuts_row_separator_func (GtkTreeModel *model,
3577                               GtkTreeIter  *iter,
3578                               gpointer      data)
3579 {
3580   ShortcutType shortcut_type;
3581
3582   gtk_tree_model_get (model, iter, SHORTCUTS_COL_TYPE, &shortcut_type, -1);
3583   
3584   return shortcut_type == SHORTCUT_TYPE_SEPARATOR;
3585 }
3586
3587 /* Since GtkTreeView has a keybinding attached to '/', we need to catch
3588  * keypresses before the TreeView gets them.
3589  */
3590 static gboolean
3591 tree_view_keybinding_cb (GtkWidget             *tree_view,
3592                          GdkEventKey           *event,
3593                          GtkFileChooserDefault *impl)
3594 {
3595   if ((event->keyval == GDK_slash
3596        || event->keyval == GDK_KP_Divide
3597 #ifdef G_OS_UNIX
3598        || event->keyval == GDK_asciitilde
3599 #endif
3600        ) && ! (event->state & (~GDK_SHIFT_MASK & gtk_accelerator_get_default_mod_mask ())))
3601     {
3602       location_popup_handler (impl, event->string);
3603       return TRUE;
3604     }
3605
3606   return FALSE;
3607 }
3608
3609 /* Callback used when the file list's popup menu is detached */
3610 static void
3611 shortcuts_popup_menu_detach_cb (GtkWidget *attach_widget,
3612                                 GtkMenu   *menu)
3613 {
3614   GtkFileChooserDefault *impl;
3615   
3616   impl = g_object_get_data (G_OBJECT (attach_widget), "GtkFileChooserDefault");
3617   g_assert (GTK_IS_FILE_CHOOSER_DEFAULT (impl));
3618
3619   impl->browse_shortcuts_popup_menu = NULL;
3620   impl->browse_shortcuts_popup_menu_remove_item = NULL;
3621   impl->browse_shortcuts_popup_menu_rename_item = NULL;
3622 }
3623
3624 static void
3625 remove_shortcut_cb (GtkMenuItem           *item,
3626                     GtkFileChooserDefault *impl)
3627 {
3628   remove_selected_bookmarks (impl);
3629 }
3630
3631 /* Rename the selected bookmark */
3632 static void
3633 rename_selected_bookmark (GtkFileChooserDefault *impl)
3634 {
3635   GtkTreeIter iter;
3636   GtkTreePath *path;
3637   GtkTreeViewColumn *column;
3638   GtkCellRenderer *cell;
3639   GList *renderers;
3640
3641   if (shortcuts_get_selected (impl, &iter))
3642     {
3643       path = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->shortcuts_model), &iter);
3644       column = gtk_tree_view_get_column (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view), 0);
3645       renderers = gtk_tree_view_column_get_cell_renderers (column);
3646       cell = g_list_nth_data (renderers, 1);
3647       g_list_free (renderers);
3648       g_object_set (cell, "editable", TRUE, NULL);
3649       gtk_tree_view_set_cursor_on_cell (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view),
3650                                         path, column, cell, TRUE);
3651       gtk_tree_path_free (path);
3652     }
3653 }
3654
3655 static void
3656 rename_shortcut_cb (GtkMenuItem           *item,
3657                     GtkFileChooserDefault *impl)
3658 {
3659   rename_selected_bookmark (impl);
3660 }
3661
3662 /* Constructs the popup menu for the file list if needed */
3663 static void
3664 shortcuts_build_popup_menu (GtkFileChooserDefault *impl)
3665 {
3666   GtkWidget *item;
3667
3668   if (impl->browse_shortcuts_popup_menu)
3669     return;
3670
3671   impl->browse_shortcuts_popup_menu = gtk_menu_new ();
3672   gtk_menu_attach_to_widget (GTK_MENU (impl->browse_shortcuts_popup_menu),
3673                              impl->browse_shortcuts_tree_view,
3674                              shortcuts_popup_menu_detach_cb);
3675
3676   item = gtk_image_menu_item_new_with_label (_("Remove"));
3677   impl->browse_shortcuts_popup_menu_remove_item = item;
3678   gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item),
3679                                  gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU));
3680   g_signal_connect (item, "activate",
3681                     G_CALLBACK (remove_shortcut_cb), impl);
3682   gtk_widget_show (item);
3683   gtk_menu_shell_append (GTK_MENU_SHELL (impl->browse_shortcuts_popup_menu), item);
3684
3685   item = gtk_menu_item_new_with_label (_("Rename..."));
3686   impl->browse_shortcuts_popup_menu_rename_item = item;
3687   g_signal_connect (item, "activate",
3688                     G_CALLBACK (rename_shortcut_cb), impl);
3689   gtk_widget_show (item);
3690   gtk_menu_shell_append (GTK_MENU_SHELL (impl->browse_shortcuts_popup_menu), item);
3691
3692   shortcuts_check_popup_sensitivity (impl);
3693 }
3694
3695 static void
3696 shortcuts_update_popup_menu (GtkFileChooserDefault *impl)
3697 {
3698   shortcuts_build_popup_menu (impl);  
3699 }
3700
3701 static void
3702 popup_position_func (GtkMenu   *menu,
3703                      gint      *x,
3704                      gint      *y,
3705                      gboolean  *push_in,
3706                      gpointer   user_data);
3707
3708 static void
3709 shortcuts_popup_menu (GtkFileChooserDefault *impl,
3710                       GdkEventButton        *event)
3711 {
3712   shortcuts_update_popup_menu (impl);
3713   if (event)
3714     gtk_menu_popup (GTK_MENU (impl->browse_shortcuts_popup_menu),
3715                     NULL, NULL, NULL, NULL,
3716                     event->button, event->time);
3717   else
3718     {
3719       gtk_menu_popup (GTK_MENU (impl->browse_shortcuts_popup_menu),
3720                       NULL, NULL,
3721                       popup_position_func, impl->browse_shortcuts_tree_view,
3722                       0, GDK_CURRENT_TIME);
3723       gtk_menu_shell_select_first (GTK_MENU_SHELL (impl->browse_shortcuts_popup_menu),
3724                                    FALSE);
3725     }
3726 }
3727
3728 /* Callback used for the GtkWidget::popup-menu signal of the shortcuts list */
3729 static gboolean
3730 shortcuts_popup_menu_cb (GtkWidget *widget,
3731                          GtkFileChooserDefault *impl)
3732 {
3733   shortcuts_popup_menu (impl, NULL);
3734   return TRUE;
3735 }
3736
3737 /* Callback used when a button is pressed on the shortcuts list.  
3738  * We trap button 3 to bring up a popup menu.
3739  */
3740 static gboolean
3741 shortcuts_button_press_event_cb (GtkWidget             *widget,
3742                                  GdkEventButton        *event,
3743                                  GtkFileChooserDefault *impl)
3744 {
3745   static gboolean in_press = FALSE;
3746   gboolean handled;
3747
3748   if (in_press)
3749     return FALSE;
3750
3751   if (event->button != 3)
3752     return FALSE;
3753
3754   in_press = TRUE;
3755   handled = gtk_widget_event (impl->browse_shortcuts_tree_view, (GdkEvent *) event);
3756   in_press = FALSE;
3757
3758   if (!handled)
3759     return FALSE;
3760
3761   shortcuts_popup_menu (impl, event);
3762   return TRUE;
3763 }
3764
3765 static void
3766 shortcuts_edited (GtkCellRenderer       *cell,
3767                   gchar                 *path_string,
3768                   gchar                 *new_text,
3769                   GtkFileChooserDefault *impl)
3770 {
3771   GtkTreePath *path;
3772   GtkTreeIter iter;
3773   GtkFilePath *shortcut;
3774
3775   g_object_set (cell, "editable", FALSE, NULL);
3776
3777   path = gtk_tree_path_new_from_string (path_string);
3778   if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->shortcuts_model), &iter, path))
3779     g_assert_not_reached ();
3780
3781   gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter,
3782                       SHORTCUTS_COL_DATA, &shortcut,
3783                       -1);
3784   gtk_tree_path_free (path);
3785   
3786   gtk_file_system_set_bookmark_label (impl->file_system, shortcut, new_text);
3787 }
3788
3789 static void
3790 shortcuts_editing_canceled (GtkCellRenderer       *cell,
3791                             GtkFileChooserDefault *impl)
3792 {
3793   g_object_set (cell, "editable", FALSE, NULL);
3794 }
3795
3796 /* Creates the widgets for the shortcuts and bookmarks tree */
3797 static GtkWidget *
3798 shortcuts_list_create (GtkFileChooserDefault *impl)
3799 {
3800   GtkWidget *swin;
3801   GtkTreeSelection *selection;
3802   GtkTreeViewColumn *column;
3803   GtkCellRenderer *renderer;
3804
3805   /* Scrolled window */
3806
3807   swin = gtk_scrolled_window_new (NULL, NULL);
3808   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swin),
3809                                   GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
3810   gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (swin),
3811                                        GTK_SHADOW_IN);
3812   gtk_widget_show (swin);
3813
3814   /* Tree */
3815
3816   impl->browse_shortcuts_tree_view = gtk_tree_view_new ();
3817 #ifdef PROFILE_FILE_CHOOSER
3818   g_object_set_data (G_OBJECT (impl->browse_shortcuts_tree_view), "fmq-name", "shortcuts");
3819 #endif
3820   g_signal_connect (impl->browse_shortcuts_tree_view, "key_press_event",
3821                     G_CALLBACK (tree_view_keybinding_cb), impl);
3822   g_signal_connect (impl->browse_shortcuts_tree_view, "popup_menu",
3823                     G_CALLBACK (shortcuts_popup_menu_cb), impl);
3824   g_signal_connect (impl->browse_shortcuts_tree_view, "button_press_event",
3825                     G_CALLBACK (shortcuts_button_press_event_cb), impl);
3826   /* Accessible object name for the file chooser's shortcuts pane */
3827   atk_object_set_name (gtk_widget_get_accessible (impl->browse_shortcuts_tree_view), _("Places"));
3828
3829   gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view), impl->shortcuts_pane_filter_model);
3830
3831   gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view),
3832                                           GDK_BUTTON1_MASK,
3833                                           shortcuts_source_targets,
3834                                           num_shortcuts_source_targets,
3835                                           GDK_ACTION_MOVE);
3836
3837   gtk_drag_dest_set (impl->browse_shortcuts_tree_view,
3838                      GTK_DEST_DEFAULT_ALL,
3839                      shortcuts_dest_targets,
3840                      num_shortcuts_dest_targets,
3841                      GDK_ACTION_COPY | GDK_ACTION_MOVE);
3842
3843   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view));
3844   gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
3845   gtk_tree_selection_set_select_function (selection,
3846                                           shortcuts_select_func,
3847                                           impl, NULL);
3848
3849   g_signal_connect (selection, "changed",
3850                     G_CALLBACK (shortcuts_selection_changed_cb), impl);
3851
3852   g_signal_connect (impl->browse_shortcuts_tree_view, "row_activated",
3853                     G_CALLBACK (shortcuts_row_activated_cb), impl);
3854
3855   g_signal_connect (impl->browse_shortcuts_tree_view, "key_press_event",
3856                     G_CALLBACK (shortcuts_key_press_event_cb), impl);
3857
3858   g_signal_connect (impl->browse_shortcuts_tree_view, "drag_begin",
3859                     G_CALLBACK (shortcuts_drag_begin_cb), impl);
3860   g_signal_connect (impl->browse_shortcuts_tree_view, "drag_end",
3861                     G_CALLBACK (shortcuts_drag_end_cb), impl);
3862   g_signal_connect (impl->browse_shortcuts_tree_view, "drag_data_delete",
3863                     G_CALLBACK (shortcuts_drag_data_delete_cb), impl);
3864
3865   g_signal_connect (impl->browse_shortcuts_tree_view, "drag_leave",
3866                     G_CALLBACK (shortcuts_drag_leave_cb), impl);
3867   g_signal_connect (impl->browse_shortcuts_tree_view, "drag_motion",
3868                     G_CALLBACK (shortcuts_drag_motion_cb), impl);
3869   g_signal_connect (impl->browse_shortcuts_tree_view, "drag_drop",
3870                     G_CALLBACK (shortcuts_drag_drop_cb), impl);
3871   g_signal_connect (impl->browse_shortcuts_tree_view, "drag_data_received",
3872                     G_CALLBACK (shortcuts_drag_data_received_cb), impl);
3873
3874   gtk_container_add (GTK_CONTAINER (swin), impl->browse_shortcuts_tree_view);
3875   gtk_widget_show (impl->browse_shortcuts_tree_view);
3876
3877   /* Column */
3878
3879   column = gtk_tree_view_column_new ();
3880   /* Column header for the file chooser's shortcuts pane */
3881   gtk_tree_view_column_set_title (column, _("_Places"));
3882
3883   renderer = gtk_cell_renderer_pixbuf_new ();
3884   gtk_tree_view_column_pack_start (column, renderer, FALSE);
3885   gtk_tree_view_column_set_attributes (column, renderer,
3886                                        "pixbuf", SHORTCUTS_COL_PIXBUF,
3887                                        "visible", SHORTCUTS_COL_PIXBUF_VISIBLE,
3888                                        NULL);
3889
3890   renderer = gtk_cell_renderer_text_new ();
3891   g_signal_connect (renderer, "edited", 
3892                     G_CALLBACK (shortcuts_edited), impl);
3893   g_signal_connect (renderer, "editing-canceled", 
3894                     G_CALLBACK (shortcuts_editing_canceled), impl);
3895   gtk_tree_view_column_pack_start (column, renderer, TRUE);
3896   gtk_tree_view_column_set_attributes (column, renderer,
3897                                        "text", SHORTCUTS_COL_NAME,
3898                                        NULL);
3899
3900   gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view),
3901                                         shortcuts_row_separator_func,
3902                                         NULL, NULL);
3903
3904   gtk_tree_view_append_column (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view), column);
3905
3906   return swin;
3907 }
3908
3909 /* Creates the widgets for the shortcuts/bookmarks pane */
3910 static GtkWidget *
3911 shortcuts_pane_create (GtkFileChooserDefault *impl,
3912                        GtkSizeGroup          *size_group)
3913 {
3914   GtkWidget *vbox;
3915   GtkWidget *hbox;
3916   GtkWidget *widget;
3917
3918   vbox = gtk_vbox_new (FALSE, 6);
3919   gtk_widget_show (vbox);
3920
3921   /* Shortcuts tree */
3922
3923   widget = shortcuts_list_create (impl);
3924   gtk_box_pack_start (GTK_BOX (vbox), widget, TRUE, TRUE, 0);
3925
3926   /* Box for buttons */
3927
3928   hbox = gtk_hbox_new (TRUE, 6);
3929   gtk_size_group_add_widget (size_group, hbox);
3930   gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
3931   gtk_widget_show (hbox);
3932
3933   /* Add bookmark button */
3934
3935   impl->browse_shortcuts_add_button = button_new (impl,
3936                                                   _("_Add"),
3937                                                   GTK_STOCK_ADD,
3938                                                   FALSE,
3939                                                   TRUE,
3940                                                   G_CALLBACK (add_bookmark_button_clicked_cb));
3941   gtk_box_pack_start (GTK_BOX (hbox), impl->browse_shortcuts_add_button, TRUE, TRUE, 0);
3942   gtk_tooltips_set_tip (impl->tooltips, impl->browse_shortcuts_add_button,
3943                         _("Add the selected folder to the Bookmarks"), NULL);
3944
3945   /* Remove bookmark button */
3946
3947   impl->browse_shortcuts_remove_button = button_new (impl,
3948                                                      _("_Remove"),
3949                                                      GTK_STOCK_REMOVE,
3950                                                      FALSE,
3951                                                      TRUE,
3952                                                      G_CALLBACK (remove_bookmark_button_clicked_cb));
3953   gtk_box_pack_start (GTK_BOX (hbox), impl->browse_shortcuts_remove_button, TRUE, TRUE, 0);
3954   gtk_tooltips_set_tip (impl->tooltips, impl->browse_shortcuts_remove_button,
3955                         _("Remove the selected bookmark"), NULL);
3956
3957   return vbox;
3958 }
3959
3960 /* Handles key press events on the file list, so that we can trap Enter to
3961  * activate the default button on our own.  Also, checks to see if '/' has been
3962  * pressed.  See comment by tree_view_keybinding_cb() for more details.
3963  */
3964 static gboolean
3965 trap_activate_cb (GtkWidget   *widget,
3966                   GdkEventKey *event,
3967                   gpointer     data)
3968 {
3969   GtkFileChooserDefault *impl;
3970   int modifiers;
3971
3972   impl = (GtkFileChooserDefault *) data;
3973
3974   modifiers = gtk_accelerator_get_default_mod_mask ();
3975
3976   if ((event->keyval == GDK_slash
3977        || event->keyval == GDK_KP_Divide
3978 #ifdef G_OS_UNIX
3979        || event->keyval == GDK_asciitilde
3980 #endif
3981        ) && ! (event->state & (~GDK_SHIFT_MASK & modifiers)))
3982     {
3983       location_popup_handler (impl, event->string);
3984       return TRUE;
3985     }
3986
3987   if ((event->keyval == GDK_Return
3988        || event->keyval == GDK_ISO_Enter
3989        || event->keyval == GDK_KP_Enter
3990        || event->keyval == GDK_space)
3991       && ((event->state & modifiers) == 0)
3992       && !(impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
3993            impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER))
3994     {
3995       GtkWindow *window;
3996
3997       window = get_toplevel (widget);
3998       if (window
3999           && widget != window->default_widget
4000           && !(widget == window->focus_widget &&
4001                (!window->default_widget || !GTK_WIDGET_SENSITIVE (window->default_widget))))
4002         {
4003           gtk_window_activate_default (window);
4004           return TRUE;
4005         }
4006     }
4007
4008   return FALSE;
4009 }
4010
4011 /* Callback used when the file list's popup menu is detached */
4012 static void
4013 popup_menu_detach_cb (GtkWidget *attach_widget,
4014                       GtkMenu   *menu)
4015 {
4016   GtkFileChooserDefault *impl;
4017
4018   impl = g_object_get_data (G_OBJECT (attach_widget), "GtkFileChooserDefault");
4019   g_assert (GTK_IS_FILE_CHOOSER_DEFAULT (impl));
4020
4021   impl->browse_files_popup_menu = NULL;
4022   impl->browse_files_popup_menu_add_shortcut_item = NULL;
4023   impl->browse_files_popup_menu_hidden_files_item = NULL;
4024 }
4025
4026 /* Callback used when the "Add to Bookmarks" menu item is activated */
4027 static void
4028 add_to_shortcuts_cb (GtkMenuItem           *item,
4029                      GtkFileChooserDefault *impl)
4030 {
4031   bookmarks_add_selected_folder (impl);
4032 }
4033
4034 /* Callback used when the "Show Hidden Files" menu item is toggled */
4035 static void
4036 show_hidden_toggled_cb (GtkCheckMenuItem      *item,
4037                         GtkFileChooserDefault *impl)
4038 {
4039   g_object_set (impl,
4040                 "show-hidden", gtk_check_menu_item_get_active (item),
4041                 NULL);
4042 }
4043
4044 /* Shows an error dialog about not being able to select a dragged file */
4045 static void
4046 error_selecting_dragged_file_dialog (GtkFileChooserDefault *impl,
4047                                      const GtkFilePath     *path,
4048                                      GError                *error)
4049 {
4050   error_dialog (impl,
4051                 _("Could not select file"),
4052                 path, error);
4053 }
4054
4055 static void
4056 file_list_drag_data_select_uris (GtkFileChooserDefault  *impl,
4057                                  gchar                 **uris)
4058 {
4059   int i;
4060   char *uri;
4061   GtkFileChooser *chooser = GTK_FILE_CHOOSER (impl);
4062
4063   for (i = 1; uris[i]; i++)
4064     {
4065       GtkFilePath *path;
4066
4067       uri = uris[i];
4068       path = gtk_file_system_uri_to_path (impl->file_system, uri);
4069
4070       if (path)
4071         {
4072           GError *error = NULL;
4073
4074           gtk_file_chooser_default_select_path (chooser, path, &error);
4075           if (error)
4076             error_selecting_dragged_file_dialog (impl, path, error);
4077
4078           gtk_file_path_free (path);
4079         }
4080     }
4081 }
4082
4083 struct FileListDragData
4084 {
4085   GtkFileChooserDefault *impl;
4086   gchar **uris;
4087   GtkFilePath *path;
4088 };
4089
4090 static void
4091 file_list_drag_data_received_get_info_cb (GtkFileSystemHandle *handle,
4092                                           const GtkFileInfo   *info,
4093                                           const GError        *error,
4094                                           gpointer             user_data)
4095 {
4096   gboolean cancelled = handle->cancelled;
4097   struct FileListDragData *data = user_data;
4098   GtkFileChooser *chooser = GTK_FILE_CHOOSER (data->impl);
4099
4100   if (handle != data->impl->file_list_drag_data_received_handle)
4101     goto out;
4102
4103   data->impl->file_list_drag_data_received_handle = NULL;
4104
4105   if (cancelled || error)
4106     goto out;
4107
4108   if ((data->impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
4109        data->impl->action == GTK_FILE_CHOOSER_ACTION_SAVE) &&
4110       data->uris[1] == 0 && !error &&
4111       gtk_file_info_get_is_folder (info))
4112     change_folder_and_display_error (data->impl, data->path, FALSE);
4113   else
4114     {
4115       GError *error = NULL;
4116
4117       gtk_file_chooser_default_unselect_all (chooser);
4118       gtk_file_chooser_default_select_path (chooser, data->path, &error);
4119       if (error)
4120         error_selecting_dragged_file_dialog (data->impl, data->path, error);
4121       else
4122         browse_files_center_selected_row (data->impl);
4123     }
4124
4125   if (data->impl->select_multiple)
4126     file_list_drag_data_select_uris (data->impl, data->uris);
4127
4128 out:
4129   g_object_unref (data->impl);
4130   g_strfreev (data->uris);
4131   gtk_file_path_free (data->path);
4132   g_free (data);
4133
4134   g_object_unref (handle);
4135 }
4136
4137 static void
4138 file_list_drag_data_received_cb (GtkWidget          *widget,
4139                                  GdkDragContext     *context,
4140                                  gint                x,
4141                                  gint                y,
4142                                  GtkSelectionData   *selection_data,
4143                                  guint               info,
4144                                  guint               time_,
4145                                  gpointer            data)
4146 {
4147   GtkFileChooserDefault *impl;
4148   GtkFileChooser *chooser;
4149   gchar **uris;
4150   char *uri;
4151   GtkFilePath *path;
4152   GError *error = NULL;
4153  
4154   impl = GTK_FILE_CHOOSER_DEFAULT (data);
4155   chooser = GTK_FILE_CHOOSER (data);
4156   
4157   /* Parse the text/uri-list string, navigate to the first one */
4158   uris = g_uri_list_extract_uris ((const char *) selection_data->data);
4159   if (uris[0]) 
4160     {
4161       uri = uris[0];
4162       path = gtk_file_system_uri_to_path (impl->file_system, uri);
4163       
4164       if (path)
4165         {
4166           struct FileListDragData *data;
4167
4168           data = g_new0 (struct FileListDragData, 1);
4169           data->impl = g_object_ref (impl);
4170           data->uris = uris;
4171           data->path = path;
4172
4173           if (impl->file_list_drag_data_received_handle)
4174             gtk_file_system_cancel_operation (impl->file_list_drag_data_received_handle);
4175
4176           impl->file_list_drag_data_received_handle =
4177             gtk_file_system_get_info (impl->file_system, path,
4178                                       GTK_FILE_INFO_IS_FOLDER,
4179                                       file_list_drag_data_received_get_info_cb,
4180                                       data);
4181           goto out;
4182         }
4183       else
4184         {
4185           g_set_error (&error,
4186                        GTK_FILE_CHOOSER_ERROR,
4187                        GTK_FILE_CHOOSER_ERROR_BAD_FILENAME,
4188                        _("Could not select file '%s' "
4189                          "because it is an invalid path name."),
4190                        uri);
4191           error_selecting_dragged_file_dialog (impl, NULL, error);
4192         }
4193
4194       if (impl->select_multiple)
4195         file_list_drag_data_select_uris (impl, uris);
4196     }
4197
4198   g_strfreev (uris);
4199
4200 out:
4201   g_signal_stop_emission_by_name (widget, "drag_data_received");
4202 }
4203
4204 /* Don't do anything with the drag_drop signal */
4205 static gboolean
4206 file_list_drag_drop_cb (GtkWidget             *widget,
4207                         GdkDragContext        *context,
4208                         gint                   x,
4209                         gint                   y,
4210                         guint                  time_,
4211                         GtkFileChooserDefault *impl)
4212 {
4213   g_signal_stop_emission_by_name (widget, "drag_drop");
4214   return TRUE;
4215 }
4216
4217 /* Disable the normal tree drag motion handler, it makes it look like you're
4218    dropping the dragged item onto a tree item */
4219 static gboolean
4220 file_list_drag_motion_cb (GtkWidget             *widget,
4221                           GdkDragContext        *context,
4222                           gint                   x,
4223                           gint                   y,
4224                           guint                  time_,
4225                           GtkFileChooserDefault *impl)
4226 {
4227   g_signal_stop_emission_by_name (widget, "drag_motion");
4228   return TRUE;
4229 }
4230
4231 /* Constructs the popup menu for the file list if needed */
4232 static void
4233 file_list_build_popup_menu (GtkFileChooserDefault *impl)
4234 {
4235   GtkWidget *item;
4236
4237   if (impl->browse_files_popup_menu)
4238     return;
4239
4240   impl->browse_files_popup_menu = gtk_menu_new ();
4241   gtk_menu_attach_to_widget (GTK_MENU (impl->browse_files_popup_menu),
4242                              impl->browse_files_tree_view,
4243                              popup_menu_detach_cb);
4244
4245   item = gtk_image_menu_item_new_with_mnemonic (_("_Add to Bookmarks"));
4246   impl->browse_files_popup_menu_add_shortcut_item = item;
4247   gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item),
4248                                  gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU));
4249   gtk_widget_set_sensitive (item, FALSE);
4250   g_signal_connect (item, "activate",
4251                     G_CALLBACK (add_to_shortcuts_cb), impl);
4252   gtk_widget_show (item);
4253   gtk_menu_shell_append (GTK_MENU_SHELL (impl->browse_files_popup_menu), item);
4254
4255   item = gtk_separator_menu_item_new ();
4256   gtk_widget_show (item);
4257   gtk_menu_shell_append (GTK_MENU_SHELL (impl->browse_files_popup_menu), item);
4258
4259   item = gtk_check_menu_item_new_with_mnemonic (_("Show _Hidden Files"));
4260   impl->browse_files_popup_menu_hidden_files_item = item;
4261   g_signal_connect (item, "toggled",
4262                     G_CALLBACK (show_hidden_toggled_cb), impl);
4263   gtk_widget_show (item);
4264   gtk_menu_shell_append (GTK_MENU_SHELL (impl->browse_files_popup_menu), item);
4265 }
4266
4267 /* Updates the popup menu for the file list, creating it if necessary */
4268 static void
4269 file_list_update_popup_menu (GtkFileChooserDefault *impl)
4270 {
4271   file_list_build_popup_menu (impl);
4272
4273   /* FIXME - handle OPERATION_MODE_SEARCH and OPERATION_MODE_RECENT */
4274
4275   /* The sensitivity of the Add to Bookmarks item is set in
4276    * bookmarks_check_add_sensitivity()
4277    */
4278
4279   g_signal_handlers_block_by_func (impl->browse_files_popup_menu_hidden_files_item,
4280                                    G_CALLBACK (show_hidden_toggled_cb), impl);
4281   gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (impl->browse_files_popup_menu_hidden_files_item),
4282                                   impl->show_hidden);
4283   g_signal_handlers_unblock_by_func (impl->browse_files_popup_menu_hidden_files_item,
4284                                      G_CALLBACK (show_hidden_toggled_cb), impl);
4285 }
4286
4287 static void
4288 popup_position_func (GtkMenu   *menu,
4289                      gint      *x,
4290                      gint      *y,
4291                      gboolean  *push_in,
4292                      gpointer   user_data)
4293 {
4294   GtkWidget *widget = GTK_WIDGET (user_data);
4295   GdkScreen *screen = gtk_widget_get_screen (widget);
4296   GtkRequisition req;
4297   gint monitor_num;
4298   GdkRectangle monitor;
4299
4300   g_return_if_fail (GTK_WIDGET_REALIZED (widget));
4301
4302   gdk_window_get_origin (widget->window, x, y);
4303
4304   gtk_widget_size_request (GTK_WIDGET (menu), &req);
4305
4306   *x += (widget->allocation.width - req.width) / 2;
4307   *y += (widget->allocation.height - req.height) / 2;
4308
4309   monitor_num = gdk_screen_get_monitor_at_point (screen, *x, *y);
4310   gtk_menu_set_monitor (menu, monitor_num);
4311   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
4312
4313   *x = CLAMP (*x, monitor.x, monitor.x + MAX (0, monitor.width - req.width));
4314   *y = CLAMP (*y, monitor.y, monitor.y + MAX (0, monitor.height - req.height));
4315
4316   *push_in = FALSE;
4317 }
4318
4319 static void
4320 file_list_popup_menu (GtkFileChooserDefault *impl,
4321                       GdkEventButton        *event)
4322 {
4323   file_list_update_popup_menu (impl);
4324   if (event)
4325     gtk_menu_popup (GTK_MENU (impl->browse_files_popup_menu),
4326                     NULL, NULL, NULL, NULL,
4327                     event->button, event->time);
4328   else
4329     {
4330       gtk_menu_popup (GTK_MENU (impl->browse_files_popup_menu),
4331                       NULL, NULL,
4332                       popup_position_func, impl->browse_files_tree_view,
4333                       0, GDK_CURRENT_TIME);
4334       gtk_menu_shell_select_first (GTK_MENU_SHELL (impl->browse_files_popup_menu),
4335                                    FALSE);
4336     }
4337
4338 }
4339
4340 /* Callback used for the GtkWidget::popup-menu signal of the file list */
4341 static gboolean
4342 list_popup_menu_cb (GtkWidget *widget,
4343                     GtkFileChooserDefault *impl)
4344 {
4345   file_list_popup_menu (impl, NULL);
4346   return TRUE;
4347 }
4348
4349 /* Callback used when a button is pressed on the file list.  We trap button 3 to
4350  * bring up a popup menu.
4351  */
4352 static gboolean
4353 list_button_press_event_cb (GtkWidget             *widget,
4354                             GdkEventButton        *event,
4355                             GtkFileChooserDefault *impl)
4356 {
4357   static gboolean in_press = FALSE;
4358   gboolean handled;
4359
4360   if (in_press)
4361     return FALSE;
4362
4363   if (event->button != 3)
4364     return FALSE;
4365
4366   in_press = TRUE;
4367   handled = gtk_widget_event (impl->browse_files_tree_view, (GdkEvent *) event);
4368   in_press = FALSE;
4369
4370   file_list_popup_menu (impl, event);
4371   return TRUE;
4372 }
4373
4374 /* Sets the sort column IDs for the file list based on the operation mode */
4375 static void
4376 file_list_set_sort_column_ids (GtkFileChooserDefault *impl)
4377 {
4378   int name_id, mtime_id;
4379
4380   name_id = mtime_id = 0;
4381
4382   switch (impl->operation_mode)
4383     {
4384     case OPERATION_MODE_BROWSE:
4385       name_id = FILE_LIST_COL_NAME;
4386       mtime_id = FILE_LIST_COL_MTIME;
4387       break;
4388     case OPERATION_MODE_SEARCH:
4389       name_id = SEARCH_MODEL_COL_PATH;
4390       mtime_id = SEARCH_MODEL_COL_STAT;
4391       break;
4392     case OPERATION_MODE_RECENT:
4393       name_id = RECENT_MODEL_COL_PATH;
4394       mtime_id = RECENT_MODEL_COL_INFO;
4395       break;
4396     }
4397
4398   gtk_tree_view_column_set_sort_column_id (impl->list_name_column, name_id);
4399   gtk_tree_view_column_set_sort_column_id (impl->list_mtime_column, mtime_id);
4400 }
4401
4402
4403 /* Creates the widgets for the file list */
4404 static GtkWidget *
4405 create_file_list (GtkFileChooserDefault *impl)
4406 {
4407   GtkWidget *swin;
4408   GtkTreeSelection *selection;
4409   GtkTreeViewColumn *column;
4410   GtkCellRenderer *renderer;
4411
4412   /* Scrolled window */
4413
4414   swin = gtk_scrolled_window_new (NULL, NULL);
4415   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swin),
4416                                   GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
4417   gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (swin),
4418                                        GTK_SHADOW_IN);
4419
4420   /* Tree/list view */
4421
4422   impl->browse_files_tree_view = gtk_tree_view_new ();
4423 #ifdef PROFILE_FILE_CHOOSER
4424   g_object_set_data (G_OBJECT (impl->browse_files_tree_view), "fmq-name", "file_list");
4425 #endif
4426   g_object_set_data (G_OBJECT (impl->browse_files_tree_view), I_("GtkFileChooserDefault"), impl);
4427   atk_object_set_name (gtk_widget_get_accessible (impl->browse_files_tree_view), _("Files"));
4428
4429   gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (impl->browse_files_tree_view), TRUE);
4430   gtk_container_add (GTK_CONTAINER (swin), impl->browse_files_tree_view);
4431
4432   gtk_drag_dest_set (impl->browse_files_tree_view,
4433                      GTK_DEST_DEFAULT_ALL,
4434                      file_list_dest_targets,
4435                      num_file_list_dest_targets,
4436                      GDK_ACTION_COPY | GDK_ACTION_MOVE);
4437   
4438   g_signal_connect (impl->browse_files_tree_view, "row_activated",
4439                     G_CALLBACK (list_row_activated), impl);
4440   g_signal_connect (impl->browse_files_tree_view, "key_press_event",
4441                     G_CALLBACK (trap_activate_cb), impl);
4442   g_signal_connect (impl->browse_files_tree_view, "popup_menu",
4443                     G_CALLBACK (list_popup_menu_cb), impl);
4444   g_signal_connect (impl->browse_files_tree_view, "button_press_event",
4445                     G_CALLBACK (list_button_press_event_cb), impl);
4446
4447   g_signal_connect (impl->browse_files_tree_view, "drag_data_received",
4448                     G_CALLBACK (file_list_drag_data_received_cb), impl);
4449   g_signal_connect (impl->browse_files_tree_view, "drag_drop",
4450                     G_CALLBACK (file_list_drag_drop_cb), impl);
4451   g_signal_connect (impl->browse_files_tree_view, "drag_motion",
4452                     G_CALLBACK (file_list_drag_motion_cb), impl);
4453
4454   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
4455   gtk_tree_selection_set_select_function (selection,
4456                                           list_select_func,
4457                                           impl, NULL);
4458   gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (impl->browse_files_tree_view),
4459                                           GDK_BUTTON1_MASK,
4460                                           file_list_source_targets,
4461                                           num_file_list_source_targets,
4462                                           GDK_ACTION_COPY);
4463
4464   g_signal_connect (selection, "changed",
4465                     G_CALLBACK (list_selection_changed), impl);
4466
4467   /* Filename column */
4468
4469   impl->list_name_column = gtk_tree_view_column_new ();
4470   gtk_tree_view_column_set_expand (impl->list_name_column, TRUE);
4471   gtk_tree_view_column_set_resizable (impl->list_name_column, TRUE);
4472   gtk_tree_view_column_set_title (impl->list_name_column, _("Name"));
4473   gtk_tree_view_column_set_sort_column_id (impl->list_name_column, FILE_LIST_COL_NAME);
4474
4475   renderer = gtk_cell_renderer_pixbuf_new ();
4476   gtk_tree_view_column_pack_start (impl->list_name_column, renderer, FALSE);
4477   gtk_tree_view_column_set_cell_data_func (impl->list_name_column, renderer,
4478                                            list_icon_data_func, impl, NULL);
4479
4480   impl->list_name_renderer = gtk_cell_renderer_text_new ();
4481   g_object_set (impl->list_name_renderer,
4482                 "ellipsize", PANGO_ELLIPSIZE_END,
4483                 NULL);
4484   g_signal_connect (impl->list_name_renderer, "edited",
4485                     G_CALLBACK (renderer_edited_cb), impl);
4486   g_signal_connect (impl->list_name_renderer, "editing_canceled",
4487                     G_CALLBACK (renderer_editing_canceled_cb), impl);
4488   gtk_tree_view_column_pack_start (impl->list_name_column, impl->list_name_renderer, TRUE);
4489   gtk_tree_view_column_set_cell_data_func (impl->list_name_column, impl->list_name_renderer,
4490                                            list_name_data_func, impl, NULL);
4491
4492   gtk_tree_view_append_column (GTK_TREE_VIEW (impl->browse_files_tree_view), impl->list_name_column);
4493 #if 0
4494   /* Size column */
4495
4496   column = gtk_tree_view_column_new ();
4497   gtk_tree_view_column_set_title (column, _("Size"));
4498
4499   renderer = gtk_cell_renderer_text_new ();
4500   gtk_tree_view_column_pack_start (column, renderer, TRUE); /* bug: it doesn't expand */
4501   gtk_tree_view_column_set_cell_data_func (column, renderer,
4502                                            list_size_data_func, impl, NULL);
4503   gtk_tree_view_column_set_sort_column_id (column, FILE_LIST_COL_SIZE);
4504   gtk_tree_view_append_column (GTK_TREE_VIEW (impl->browse_files_tree_view), column);
4505 #endif
4506
4507   /* Modification time column */
4508
4509   column = gtk_tree_view_column_new ();
4510   gtk_tree_view_column_set_resizable (column, TRUE);
4511   gtk_tree_view_column_set_title (column, _("Modified"));
4512
4513   renderer = gtk_cell_renderer_text_new ();
4514   gtk_tree_view_column_pack_start (column, renderer, TRUE);
4515   gtk_tree_view_column_set_cell_data_func (column, renderer,
4516                                            list_mtime_data_func, impl, NULL);
4517   gtk_tree_view_append_column (GTK_TREE_VIEW (impl->browse_files_tree_view), column);
4518   impl->list_mtime_column = column;
4519   
4520   file_list_set_sort_column_ids (impl);
4521
4522   gtk_widget_show_all (swin);
4523
4524   return swin;
4525 }
4526
4527 static GtkWidget *
4528 create_path_bar (GtkFileChooserDefault *impl)
4529 {
4530   GtkWidget *path_bar;
4531
4532   path_bar = g_object_new (GTK_TYPE_PATH_BAR, NULL);
4533   _gtk_path_bar_set_file_system (GTK_PATH_BAR (path_bar), impl->file_system);
4534
4535   return path_bar;
4536 }
4537
4538 static void
4539 set_filter_tooltip (GtkWidget *widget, 
4540                     gpointer   data)
4541 {
4542   GtkTooltips *tooltips = (GtkTooltips *)data;
4543
4544   if (GTK_IS_BUTTON (widget))
4545     gtk_tooltips_set_tip (tooltips, widget,
4546                           _("Select which types of files are shown"), 
4547                           NULL);
4548 }
4549
4550 static void
4551 realize_filter_combo (GtkWidget *combo,
4552                       gpointer   data)
4553 {
4554   GtkFileChooserDefault *impl = (GtkFileChooserDefault *)data;
4555
4556   gtk_container_forall (GTK_CONTAINER (combo),
4557                         set_filter_tooltip,
4558                         impl->tooltips);
4559 }
4560
4561 /* Creates the widgets for the files/folders pane */
4562 static GtkWidget *
4563 file_pane_create (GtkFileChooserDefault *impl,
4564                   GtkSizeGroup          *size_group)
4565 {
4566   GtkWidget *vbox;
4567   GtkWidget *hbox;
4568   GtkWidget *widget;
4569
4570   vbox = gtk_vbox_new (FALSE, 6);
4571   gtk_widget_show (vbox);
4572
4573   /* Box for lists and preview */
4574
4575   hbox = gtk_hbox_new (FALSE, PREVIEW_HBOX_SPACING);
4576   gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
4577   gtk_widget_show (hbox);
4578
4579   /* File list */
4580
4581   widget = create_file_list (impl);
4582   gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 0);
4583
4584   /* Preview */
4585
4586   impl->preview_box = gtk_vbox_new (FALSE, 12);
4587   gtk_box_pack_start (GTK_BOX (hbox), impl->preview_box, FALSE, FALSE, 0);
4588   /* Don't show preview box initially */
4589
4590   /* Filter combo */
4591
4592   impl->filter_combo_hbox = gtk_hbox_new (FALSE, 12);
4593
4594   widget = filter_create (impl);
4595
4596   g_signal_connect (widget, "realize",
4597                     G_CALLBACK (realize_filter_combo), impl);
4598
4599   gtk_widget_show (widget);
4600   gtk_box_pack_end (GTK_BOX (impl->filter_combo_hbox), widget, FALSE, FALSE, 0);
4601
4602   gtk_size_group_add_widget (size_group, impl->filter_combo_hbox);
4603   gtk_box_pack_end (GTK_BOX (vbox), impl->filter_combo_hbox, FALSE, FALSE, 0);
4604
4605   return vbox;
4606 }
4607
4608 /* Callback used when the "Browse for more folders" expander is toggled */
4609 static void
4610 expander_changed_cb (GtkExpander           *expander,
4611                      GParamSpec            *pspec,
4612                      GtkFileChooserDefault *impl)
4613 {
4614   impl->expand_folders = gtk_expander_get_expanded(GTK_EXPANDER (impl->save_expander));
4615   update_appearance (impl);
4616 }
4617
4618 /* Callback used when the selection changes in the save folder combo box */
4619 static void
4620 save_folder_combo_changed_cb (GtkComboBox           *combo,
4621                               GtkFileChooserDefault *impl)
4622 {
4623   GtkTreeIter iter;
4624
4625   if (impl->changing_folder)
4626     return;
4627
4628   if (gtk_combo_box_get_active_iter (combo, &iter))
4629     {
4630       GtkTreeIter child_iter;
4631       
4632       gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (impl->shortcuts_combo_filter_model),
4633                                                         &child_iter,
4634                                                         &iter);
4635       shortcuts_activate_iter (impl, &child_iter);
4636     }
4637 }
4638
4639 /* Filter function used to filter out the Search item and its separator.  
4640  * Used for the "Save in folder" combo box, so that these items do not appear in it.
4641  */
4642 static gboolean
4643 shortcuts_combo_filter_func (GtkTreeModel *model,
4644                              GtkTreeIter  *iter,
4645                              gpointer      data)
4646 {
4647   GtkFileChooserDefault *impl;
4648   GtkTreePath *tree_path;
4649   gint *indices;
4650   int idx;
4651   gboolean retval;
4652
4653   impl = GTK_FILE_CHOOSER_DEFAULT (data);
4654
4655   g_assert (model == GTK_TREE_MODEL (impl->shortcuts_model));
4656
4657   tree_path = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->shortcuts_model), iter);
4658   g_assert (tree_path != NULL);
4659
4660   indices = gtk_tree_path_get_indices (tree_path);
4661
4662   retval = TRUE;
4663
4664   if (impl->has_search)
4665     {
4666       idx = shortcuts_get_index (impl, SHORTCUTS_SEARCH);
4667       if (idx == indices[0])
4668         retval = FALSE;
4669       else
4670         {
4671           idx = shortcuts_get_index (impl, SHORTCUTS_SEARCH_SEPARATOR);
4672           if (idx == indices[0])
4673             retval = FALSE;
4674         }
4675     }
4676   
4677   if (impl->has_recent)
4678     {
4679       idx = shortcuts_get_index (impl, SHORTCUTS_RECENT);
4680       if (idx == indices[0])
4681         retval = FALSE;
4682       else
4683         {
4684           idx = shortcuts_get_index (impl, SHORTCUTS_RECENT_SEPARATOR);
4685           if (idx == indices[0])
4686             retval = FALSE;
4687         }
4688     }
4689
4690   gtk_tree_path_free (tree_path);
4691
4692   return retval;
4693  }
4694
4695 /* Creates the combo box with the save folders */
4696 static GtkWidget *
4697 save_folder_combo_create (GtkFileChooserDefault *impl)
4698 {
4699   GtkWidget *combo;
4700   GtkCellRenderer *cell;
4701
4702   impl->shortcuts_combo_filter_model = gtk_tree_model_filter_new (GTK_TREE_MODEL (impl->shortcuts_model), NULL);
4703   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (impl->shortcuts_combo_filter_model),
4704                                           shortcuts_combo_filter_func,
4705                                           impl,
4706                                           NULL);
4707
4708   combo = g_object_new (GTK_TYPE_COMBO_BOX,
4709                         "model", impl->shortcuts_combo_filter_model,
4710                         "focus-on-click", FALSE,
4711                         NULL);
4712   gtk_widget_show (combo);
4713
4714   cell = gtk_cell_renderer_pixbuf_new ();
4715   gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, FALSE);
4716   gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), cell,
4717                                   "pixbuf", SHORTCUTS_COL_PIXBUF,
4718                                   "visible", SHORTCUTS_COL_PIXBUF_VISIBLE,
4719                                   "sensitive", SHORTCUTS_COL_PIXBUF_VISIBLE,
4720                                   NULL);
4721
4722   cell = gtk_cell_renderer_text_new ();
4723   gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, TRUE);
4724   gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), cell,
4725                                   "text", SHORTCUTS_COL_NAME,
4726                                   "sensitive", SHORTCUTS_COL_PIXBUF_VISIBLE,
4727                                   NULL);
4728
4729   gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (combo),
4730                                         shortcuts_row_separator_func,
4731                                         NULL, NULL);
4732
4733   g_signal_connect (combo, "changed",
4734                     G_CALLBACK (save_folder_combo_changed_cb), impl);
4735
4736   return combo;
4737 }
4738
4739 /* Creates the widgets specific to Save mode */
4740 static void
4741 save_widgets_create (GtkFileChooserDefault *impl)
4742 {
4743   GtkWidget *vbox;
4744   GtkWidget *table;
4745   GtkWidget *widget;
4746   GtkWidget *alignment;
4747
4748   if (impl->save_widgets != NULL)
4749     return;
4750
4751   location_switch_to_path_bar (impl);
4752
4753   vbox = gtk_vbox_new (FALSE, 12);
4754
4755   table = gtk_table_new (2, 2, FALSE);
4756   gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
4757   gtk_widget_show (table);
4758   gtk_table_set_row_spacings (GTK_TABLE (table), 12);
4759   gtk_table_set_col_spacings (GTK_TABLE (table), 12);
4760
4761   /* Label */
4762
4763   widget = gtk_label_new_with_mnemonic (_("_Name:"));
4764   gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
4765   gtk_table_attach (GTK_TABLE (table), widget,
4766                     0, 1, 0, 1,
4767                     GTK_FILL, GTK_FILL,
4768                     0, 0);
4769   gtk_widget_show (widget);
4770
4771   /* Location entry */
4772
4773   impl->location_entry = _gtk_file_chooser_entry_new (TRUE);
4774   _gtk_file_chooser_entry_set_file_system (GTK_FILE_CHOOSER_ENTRY (impl->location_entry),
4775                                            impl->file_system);
4776   gtk_entry_set_width_chars (GTK_ENTRY (impl->location_entry), 45);
4777   gtk_entry_set_activates_default (GTK_ENTRY (impl->location_entry), TRUE);
4778   gtk_table_attach (GTK_TABLE (table), impl->location_entry,
4779                     1, 2, 0, 1,
4780                     GTK_EXPAND | GTK_FILL, 0,
4781                     0, 0);
4782   gtk_widget_show (impl->location_entry);
4783   gtk_label_set_mnemonic_widget (GTK_LABEL (widget), impl->location_entry);
4784
4785   /* Folder combo */
4786   impl->save_folder_label = gtk_label_new (NULL);
4787   gtk_misc_set_alignment (GTK_MISC (impl->save_folder_label), 0.0, 0.5);
4788   gtk_table_attach (GTK_TABLE (table), impl->save_folder_label,
4789                     0, 1, 1, 2,
4790                     GTK_FILL, GTK_FILL,
4791                     0, 0);
4792   gtk_widget_show (impl->save_folder_label);
4793
4794   impl->save_folder_combo = save_folder_combo_create (impl);
4795   gtk_table_attach (GTK_TABLE (table), impl->save_folder_combo,
4796                     1, 2, 1, 2,
4797                     GTK_EXPAND | GTK_FILL, GTK_FILL,
4798                     0, 0);
4799   gtk_label_set_mnemonic_widget (GTK_LABEL (impl->save_folder_label), impl->save_folder_combo);
4800
4801   /* Expander */
4802   alignment = gtk_alignment_new (0.0, 0.5, 1.0, 1.0);
4803   gtk_box_pack_start (GTK_BOX (vbox), alignment, FALSE, FALSE, 0);
4804
4805   impl->save_expander = gtk_expander_new_with_mnemonic (_("_Browse for other folders"));
4806   gtk_container_add (GTK_CONTAINER (alignment), impl->save_expander);
4807   g_signal_connect (impl->save_expander, "notify::expanded",
4808                     G_CALLBACK (expander_changed_cb),
4809                     impl);
4810   gtk_widget_show_all (alignment);
4811
4812   impl->save_widgets = vbox;
4813   gtk_box_pack_start (GTK_BOX (impl), impl->save_widgets, FALSE, FALSE, 0);
4814   gtk_box_reorder_child (GTK_BOX (impl), impl->save_widgets, 0);
4815   gtk_widget_show (impl->save_widgets);
4816 }
4817
4818 /* Destroys the widgets specific to Save mode */
4819 static void
4820 save_widgets_destroy (GtkFileChooserDefault *impl)
4821 {
4822   if (impl->save_widgets == NULL)
4823     return;
4824
4825   gtk_widget_destroy (impl->save_widgets);
4826   impl->save_widgets = NULL;
4827   impl->location_entry = NULL;
4828   impl->save_folder_label = NULL;
4829   impl->save_folder_combo = NULL;
4830   impl->save_expander = NULL;
4831 }
4832
4833 /* Turns on the path bar widget.  Can be called even if we are already in that
4834  * mode.
4835  */
4836 static void
4837 location_switch_to_path_bar (GtkFileChooserDefault *impl)
4838 {
4839   if (impl->location_entry)
4840     {
4841       gtk_widget_destroy (impl->location_entry);
4842       impl->location_entry = NULL;
4843     }
4844
4845   gtk_widget_hide (impl->location_entry_box);
4846 }
4847
4848 /* Sets the full path of the current folder as the text in the location entry. */
4849 static void
4850 location_entry_set_initial_text (GtkFileChooserDefault *impl)
4851 {
4852   char *text;
4853
4854   if (!impl->current_folder)
4855     return;
4856
4857   if (gtk_file_system_path_is_local (impl->file_system, impl->current_folder))
4858     {
4859       char *filename;
4860
4861       filename = gtk_file_system_path_to_filename (impl->file_system, impl->current_folder);
4862       if (filename)
4863         {
4864           text = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL);
4865           g_free (filename);
4866         }
4867       else
4868         text = NULL;
4869     }
4870   else
4871     text = gtk_file_system_path_to_uri (impl->file_system, impl->current_folder);
4872
4873   if (text)
4874     {
4875       gboolean need_slash;
4876       int len;
4877
4878       len = strlen (text);
4879       need_slash = (text[len - 1] != G_DIR_SEPARATOR);
4880
4881       if (need_slash)
4882         {
4883           char *slash_text;
4884
4885           slash_text = g_new (char, len + 2);
4886           strcpy (slash_text, text);
4887           slash_text[len] = G_DIR_SEPARATOR;
4888           slash_text[len + 1] = 0;
4889
4890           g_free (text);
4891           text = slash_text;
4892         }
4893
4894       _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), text);
4895       g_free (text);
4896     }
4897 }
4898
4899 /* Turns on the location entry.  Can be called even if we are already in that
4900  * mode.
4901  */
4902 static void
4903 location_switch_to_filename_entry (GtkFileChooserDefault *impl)
4904 {
4905   /* when in search or recent files mode, we are not showing the
4906    * location_entry_box container, so there's no point in switching
4907    * to it.
4908    */
4909   if (impl->operation_mode == OPERATION_MODE_SEARCH ||
4910       impl->operation_mode == OPERATION_MODE_RECENT)
4911     return;
4912
4913   if (impl->location_entry)
4914     gtk_widget_destroy (impl->location_entry);
4915
4916   /* Box */
4917
4918   gtk_widget_show (impl->location_entry_box);
4919
4920   /* Entry */
4921
4922   impl->location_entry = _gtk_file_chooser_entry_new (TRUE);
4923   _gtk_file_chooser_entry_set_file_system (GTK_FILE_CHOOSER_ENTRY (impl->location_entry),
4924                                            impl->file_system);
4925   gtk_entry_set_activates_default (GTK_ENTRY (impl->location_entry), TRUE);
4926   _gtk_file_chooser_entry_set_action (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), impl->action);
4927
4928   gtk_box_pack_start (GTK_BOX (impl->location_entry_box), impl->location_entry, TRUE, TRUE, 0);
4929   gtk_label_set_mnemonic_widget (GTK_LABEL (impl->location_label), impl->location_entry);
4930
4931   /* Configure the entry */
4932
4933   _gtk_file_chooser_entry_set_base_folder (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), impl->current_folder);
4934
4935   /* Done */
4936
4937   gtk_widget_show (impl->location_entry);
4938   gtk_widget_grab_focus (impl->location_entry);
4939 }
4940
4941 /* Sets a new location mode.  set_buttons determines whether the toggle button
4942  * for the mode will also be changed.
4943  */
4944 static void
4945 location_mode_set (GtkFileChooserDefault *impl,
4946                    LocationMode new_mode,
4947                    gboolean set_button)
4948 {
4949   if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
4950       impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
4951     {
4952       GtkWindow *toplevel;
4953       GtkWidget *current_focus;
4954       gboolean button_active;
4955       gboolean switch_to_file_list;
4956
4957       switch (new_mode)
4958         {
4959         case LOCATION_MODE_PATH_BAR:
4960           button_active = FALSE;
4961
4962           /* The location_entry will disappear when we switch to path bar mode.  So,
4963            * we'll focus the file list in that case, to avoid having a window with
4964            * no focused widget.
4965            */
4966           toplevel = get_toplevel (GTK_WIDGET (impl));
4967           switch_to_file_list = FALSE;
4968           if (toplevel)
4969             {
4970               current_focus = gtk_window_get_focus (toplevel);
4971               if (!current_focus || current_focus == impl->location_entry)
4972                 switch_to_file_list = TRUE;
4973             }
4974
4975           location_switch_to_path_bar (impl);
4976
4977           if (switch_to_file_list)
4978             gtk_widget_grab_focus (impl->browse_files_tree_view);
4979
4980           break;
4981
4982         case LOCATION_MODE_FILENAME_ENTRY:
4983           button_active = TRUE;
4984           location_switch_to_filename_entry (impl);
4985           break;
4986
4987         default:
4988           g_assert_not_reached ();
4989           return;
4990         }
4991
4992       if (set_button)
4993         {
4994           g_signal_handlers_block_by_func (impl->location_button,
4995                                            G_CALLBACK (location_button_toggled_cb), impl);
4996
4997           gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (impl->location_button), button_active);
4998
4999           g_signal_handlers_unblock_by_func (impl->location_button,
5000                                              G_CALLBACK (location_button_toggled_cb), impl);
5001         }
5002     }
5003
5004   impl->location_mode = new_mode;
5005 }
5006
5007 static void
5008 toggle_location_mode (GtkFileChooserDefault *impl,
5009                       gboolean               set_button)
5010 {
5011   LocationMode new_mode;
5012
5013   /* toggle value */
5014   new_mode = (impl->location_mode == LOCATION_MODE_PATH_BAR) ?
5015     LOCATION_MODE_FILENAME_ENTRY : LOCATION_MODE_PATH_BAR;
5016
5017   location_mode_set (impl, new_mode, set_button);
5018 }
5019
5020 static void
5021 location_toggle_popup_handler (GtkFileChooserDefault *impl)
5022 {
5023   toggle_location_mode (impl, TRUE);
5024 }
5025
5026 /* Callback used when one of the location mode buttons is toggled */
5027 static void
5028 location_button_toggled_cb (GtkToggleButton *toggle,
5029                             GtkFileChooserDefault *impl)
5030 {
5031   gboolean is_active;
5032
5033   is_active = gtk_toggle_button_get_active (toggle);
5034
5035   if (is_active)
5036     g_assert (impl->location_mode == LOCATION_MODE_PATH_BAR);
5037   else
5038     g_assert (impl->location_mode == LOCATION_MODE_FILENAME_ENTRY);
5039
5040   toggle_location_mode (impl, FALSE);
5041 }
5042
5043 /* Creates a toggle button for the location entry. */
5044 static void
5045 location_button_create (GtkFileChooserDefault *impl)
5046 {
5047   GtkWidget *image;
5048   const char *str;
5049
5050   image = gtk_image_new_from_stock (GTK_STOCK_EDIT, GTK_ICON_SIZE_BUTTON);
5051   gtk_widget_show (image);
5052
5053   impl->location_button = g_object_new (GTK_TYPE_TOGGLE_BUTTON,
5054                                         "image", image,
5055                                         NULL);
5056
5057   g_signal_connect (impl->location_button, "toggled",
5058                     G_CALLBACK (location_button_toggled_cb), impl);
5059
5060   str = _("Type a file name");
5061
5062   gtk_tooltips_set_tip (impl->tooltips, impl->location_button, str, NULL);
5063   atk_object_set_name (gtk_widget_get_accessible (impl->location_button), str);
5064 }
5065
5066 /* Creates the main hpaned with the widgets shared by Open and Save mode */
5067 static GtkWidget *
5068 browse_widgets_create (GtkFileChooserDefault *impl)
5069 {
5070   GtkWidget *vbox;
5071   GtkWidget *hbox;
5072   GtkWidget *hpaned;
5073   GtkWidget *widget;
5074   GtkSizeGroup *size_group;
5075
5076   /* size group is used by the [+][-] buttons and the filter combo */
5077   size_group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL);
5078   vbox = gtk_vbox_new (FALSE, 12);
5079
5080   /* Location widgets */
5081   hbox = gtk_hbox_new (FALSE, 12);
5082   gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
5083   gtk_widget_show (hbox);
5084   impl->browse_path_bar_hbox = hbox;
5085
5086   location_button_create (impl);
5087   gtk_box_pack_start (GTK_BOX (hbox), impl->location_button, FALSE, FALSE, 0);
5088
5089   /* Path bar */
5090
5091   impl->browse_path_bar = create_path_bar (impl);
5092   g_signal_connect (impl->browse_path_bar, "path-clicked", G_CALLBACK (path_bar_clicked), impl);
5093   gtk_widget_show_all (impl->browse_path_bar);
5094   gtk_box_pack_start (GTK_BOX (hbox), impl->browse_path_bar, TRUE, TRUE, 0);
5095
5096   /* Create Folder */
5097   impl->browse_new_folder_button = gtk_button_new_with_mnemonic (_("Create Fo_lder"));
5098   g_signal_connect (impl->browse_new_folder_button, "clicked",
5099                     G_CALLBACK (new_folder_button_clicked), impl);
5100   gtk_box_pack_end (GTK_BOX (hbox), impl->browse_new_folder_button, FALSE, FALSE, 0);
5101
5102   /* Box for the location label and entry */
5103
5104   impl->location_entry_box = gtk_hbox_new (FALSE, 12);
5105   gtk_box_pack_start (GTK_BOX (vbox), impl->location_entry_box, FALSE, FALSE, 0);
5106
5107   impl->location_label = gtk_label_new_with_mnemonic (_("_Location:"));
5108   gtk_widget_show (impl->location_label);
5109   gtk_box_pack_start (GTK_BOX (impl->location_entry_box), impl->location_label, FALSE, FALSE, 0);
5110
5111   /* Paned widget */
5112   hpaned = gtk_hpaned_new ();
5113   gtk_widget_show (hpaned);
5114   gtk_box_pack_start (GTK_BOX (vbox), hpaned, TRUE, TRUE, 0);
5115
5116   widget = shortcuts_pane_create (impl, size_group);
5117   gtk_paned_pack1 (GTK_PANED (hpaned), widget, FALSE, FALSE);
5118   widget = file_pane_create (impl, size_group);
5119   gtk_paned_pack2 (GTK_PANED (hpaned), widget, TRUE, FALSE);
5120
5121   g_object_unref (size_group);
5122
5123   return vbox;
5124 }
5125
5126 static GObject*
5127 gtk_file_chooser_default_constructor (GType                  type,
5128                                       guint                  n_construct_properties,
5129                                       GObjectConstructParam *construct_params)
5130 {
5131   GtkFileChooserDefault *impl;
5132   GObject *object;
5133
5134   profile_start ("start", NULL);
5135
5136   object = G_OBJECT_CLASS (_gtk_file_chooser_default_parent_class)->constructor (type,
5137                                                                                 n_construct_properties,
5138                                                                                 construct_params);
5139   impl = GTK_FILE_CHOOSER_DEFAULT (object);
5140
5141   g_assert (impl->file_system);
5142
5143   gtk_widget_push_composite_child ();
5144
5145   /* Recent files manager */
5146   recent_manager_update (impl);
5147
5148   /* Shortcuts model */
5149   shortcuts_model_create (impl);
5150
5151   /* The browse widgets */
5152   impl->browse_widgets = browse_widgets_create (impl);
5153   gtk_box_pack_start (GTK_BOX (impl), impl->browse_widgets, TRUE, TRUE, 0);
5154
5155   /* Alignment to hold extra widget */
5156   impl->extra_align = gtk_alignment_new (0.0, 0.5, 1.0, 1.0);
5157   gtk_box_pack_start (GTK_BOX (impl), impl->extra_align, FALSE, FALSE, 0);
5158
5159   gtk_widget_pop_composite_child ();
5160   update_appearance (impl);
5161
5162   profile_end ("end", NULL);
5163
5164   return object;
5165 }
5166
5167 /* Sets the extra_widget by packing it in the appropriate place */
5168 static void
5169 set_extra_widget (GtkFileChooserDefault *impl,
5170                   GtkWidget             *extra_widget)
5171 {
5172   if (extra_widget)
5173     {
5174       g_object_ref (extra_widget);
5175       /* FIXME: is this right ? */
5176       gtk_widget_show (extra_widget);
5177     }
5178
5179   if (impl->extra_widget)
5180     {
5181       gtk_container_remove (GTK_CONTAINER (impl->extra_align), impl->extra_widget);
5182       g_object_unref (impl->extra_widget);
5183     }
5184
5185   impl->extra_widget = extra_widget;
5186   if (impl->extra_widget)
5187     {
5188       gtk_container_add (GTK_CONTAINER (impl->extra_align), impl->extra_widget);
5189       gtk_widget_show (impl->extra_align);
5190     }
5191   else
5192     gtk_widget_hide (impl->extra_align);
5193 }
5194
5195 static void
5196 set_local_only (GtkFileChooserDefault *impl,
5197                 gboolean               local_only)
5198 {
5199   if (local_only != impl->local_only)
5200     {
5201       impl->local_only = local_only;
5202
5203       if (impl->shortcuts_model && impl->file_system)
5204         {
5205           shortcuts_add_volumes (impl);
5206           shortcuts_add_bookmarks (impl);
5207         }
5208
5209       if (local_only &&
5210           !gtk_file_system_path_is_local (impl->file_system, impl->current_folder))
5211         {
5212           /* If we are pointing to a non-local folder, make an effort to change
5213            * back to a local folder, but it's really up to the app to not cause
5214            * such a situation, so we ignore errors.
5215            */
5216           const gchar *home = g_get_home_dir ();
5217           GtkFilePath *home_path;
5218
5219           if (home == NULL)
5220             return;
5221
5222           home_path = gtk_file_system_filename_to_path (impl->file_system, home);
5223
5224           _gtk_file_chooser_set_current_folder_path (GTK_FILE_CHOOSER (impl), home_path, NULL);
5225
5226           gtk_file_path_free (home_path);
5227         }
5228     }
5229 }
5230
5231 static void
5232 volumes_changed_cb (GtkFileSystem         *file_system,
5233                     GtkFileChooserDefault *impl)
5234 {
5235   shortcuts_add_volumes (impl);
5236 }
5237
5238 /* Callback used when the set of bookmarks changes in the file system */
5239 static void
5240 bookmarks_changed_cb (GtkFileSystem         *file_system,
5241                       GtkFileChooserDefault *impl)
5242 {
5243   shortcuts_add_bookmarks (impl);
5244
5245   bookmarks_check_add_sensitivity (impl);
5246   bookmarks_check_remove_sensitivity (impl);
5247   shortcuts_check_popup_sensitivity (impl);
5248 }
5249
5250 /* Sets the file chooser to multiple selection mode */
5251 static void
5252 set_select_multiple (GtkFileChooserDefault *impl,
5253                      gboolean               select_multiple,
5254                      gboolean               property_notify)
5255 {
5256   GtkTreeSelection *selection;
5257   GtkSelectionMode mode;
5258
5259   if (select_multiple == impl->select_multiple)
5260     return;
5261
5262   mode = select_multiple ? GTK_SELECTION_MULTIPLE : GTK_SELECTION_BROWSE;
5263
5264   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
5265   gtk_tree_selection_set_mode (selection, mode);
5266
5267   impl->select_multiple = select_multiple;
5268   g_object_notify (G_OBJECT (impl), "select-multiple");
5269
5270   check_preview_change (impl);
5271 }
5272
5273 static void
5274 set_file_system_backend (GtkFileChooserDefault *impl,
5275                          const char *backend)
5276 {
5277   profile_start ("start for backend", backend ? backend : "default");
5278
5279   if (impl->file_system)
5280     {
5281       g_signal_handler_disconnect (impl->file_system, impl->volumes_changed_id);
5282       impl->volumes_changed_id = 0;
5283       g_signal_handler_disconnect (impl->file_system, impl->bookmarks_changed_id);
5284       impl->bookmarks_changed_id = 0;
5285       g_object_unref (impl->file_system);
5286     }
5287
5288   impl->file_system = NULL;
5289   if (backend)
5290     impl->file_system = _gtk_file_system_create (backend);
5291   else
5292     {
5293       GtkSettings *settings = gtk_settings_get_default ();
5294       gchar *default_backend = NULL;
5295
5296       g_object_get (settings, "gtk-file-chooser-backend", &default_backend, NULL);
5297       if (default_backend)
5298         {
5299           impl->file_system = _gtk_file_system_create (default_backend);
5300           g_free (default_backend);
5301         }
5302     }
5303
5304   if (!impl->file_system)
5305     {
5306 #if defined (G_OS_UNIX)
5307       impl->file_system = gtk_file_system_unix_new ();
5308 #elif defined (G_OS_WIN32)
5309       impl->file_system = gtk_file_system_win32_new ();
5310 #else
5311 #error "No default filesystem implementation on the platform"
5312 #endif
5313     }
5314
5315   if (impl->file_system)
5316     {
5317       impl->volumes_changed_id = g_signal_connect (impl->file_system, "volumes-changed",
5318                                                    G_CALLBACK (volumes_changed_cb),
5319                                                    impl);
5320       impl->bookmarks_changed_id = g_signal_connect (impl->file_system, "bookmarks-changed",
5321                                                      G_CALLBACK (bookmarks_changed_cb),
5322                                                      impl);
5323     }
5324
5325   profile_end ("end", NULL);
5326 }
5327
5328 /* This function is basically a do_all function.
5329  *
5330  * It sets the visibility on all the widgets based on the current state, and
5331  * moves the custom_widget if needed.
5332  */
5333 static void
5334 update_appearance (GtkFileChooserDefault *impl)
5335 {
5336   if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE ||
5337       impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
5338     {
5339       const char *text;
5340
5341       gtk_widget_hide (impl->location_button);
5342       save_widgets_create (impl);
5343
5344       if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
5345         text = _("Save in _folder:");
5346       else
5347         text = _("Create in _folder:");
5348
5349       gtk_label_set_text_with_mnemonic (GTK_LABEL (impl->save_folder_label), text);
5350
5351       if (gtk_expander_get_expanded (GTK_EXPANDER (impl->save_expander)))
5352         {
5353           gtk_widget_set_sensitive (impl->save_folder_label, FALSE);
5354           gtk_widget_set_sensitive (impl->save_folder_combo, FALSE);
5355           gtk_widget_show (impl->browse_widgets);
5356         }
5357       else
5358         {
5359           gtk_widget_set_sensitive (impl->save_folder_label, TRUE);
5360           gtk_widget_set_sensitive (impl->save_folder_combo, TRUE);
5361           gtk_widget_hide (impl->browse_widgets);
5362         }
5363
5364       gtk_widget_show (impl->browse_new_folder_button);
5365
5366       if (impl->select_multiple)
5367         {
5368           g_warning ("Save mode cannot be set in conjunction with multiple selection mode.  "
5369                      "Re-setting to single selection mode.");
5370           set_select_multiple (impl, FALSE, TRUE);
5371         }
5372     }
5373   else if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
5374            impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
5375     {
5376       gtk_widget_show (impl->location_button);
5377       save_widgets_destroy (impl);
5378       gtk_widget_show (impl->browse_widgets);
5379       location_mode_set (impl, impl->location_mode, TRUE);
5380     }
5381
5382   if (impl->location_entry)
5383     _gtk_file_chooser_entry_set_action (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), impl->action);
5384
5385   if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN)
5386     gtk_widget_hide (impl->browse_new_folder_button);
5387   else
5388     gtk_widget_show (impl->browse_new_folder_button);
5389
5390   /* This *is* needed; we need to redraw the file list because the "sensitivity"
5391    * of files may change depending whether we are in a file or folder-only mode.
5392    */
5393   gtk_widget_queue_draw (impl->browse_files_tree_view);
5394
5395   g_signal_emit_by_name (impl, "default-size-changed");
5396 }
5397
5398 static void
5399 gtk_file_chooser_default_set_property (GObject      *object,
5400                                        guint         prop_id,
5401                                        const GValue *value,
5402                                        GParamSpec   *pspec)
5403
5404 {
5405   GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (object);
5406
5407   switch (prop_id)
5408     {
5409     case GTK_FILE_CHOOSER_PROP_ACTION:
5410       {
5411         GtkFileChooserAction action = g_value_get_enum (value);
5412
5413         if (action != impl->action)
5414           {
5415             gtk_file_chooser_default_unselect_all (GTK_FILE_CHOOSER (impl));
5416             
5417             if ((action == GTK_FILE_CHOOSER_ACTION_SAVE ||
5418                  action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
5419                 && impl->select_multiple)
5420               {
5421                 g_warning ("Tried to change the file chooser action to SAVE or CREATE_FOLDER, but "
5422                            "this is not allowed in multiple selection mode.  Resetting the file chooser "
5423                            "to single selection mode.");
5424                 set_select_multiple (impl, FALSE, TRUE);
5425               }
5426             impl->action = action;
5427             update_appearance (impl);
5428           }
5429       }
5430       break;
5431
5432     case GTK_FILE_CHOOSER_PROP_FILE_SYSTEM_BACKEND:
5433       set_file_system_backend (impl, g_value_get_string (value));
5434       break;
5435
5436     case GTK_FILE_CHOOSER_PROP_FILTER:
5437       set_current_filter (impl, g_value_get_object (value));
5438       break;
5439
5440     case GTK_FILE_CHOOSER_PROP_LOCAL_ONLY:
5441       set_local_only (impl, g_value_get_boolean (value));
5442       break;
5443
5444     case GTK_FILE_CHOOSER_PROP_PREVIEW_WIDGET:
5445       set_preview_widget (impl, g_value_get_object (value));
5446       break;
5447
5448     case GTK_FILE_CHOOSER_PROP_PREVIEW_WIDGET_ACTIVE:
5449       impl->preview_widget_active = g_value_get_boolean (value);
5450       update_preview_widget_visibility (impl);
5451       break;
5452
5453     case GTK_FILE_CHOOSER_PROP_USE_PREVIEW_LABEL:
5454       impl->use_preview_label = g_value_get_boolean (value);
5455       update_preview_widget_visibility (impl);
5456       break;
5457
5458     case GTK_FILE_CHOOSER_PROP_EXTRA_WIDGET:
5459       set_extra_widget (impl, g_value_get_object (value));
5460       break;
5461
5462     case GTK_FILE_CHOOSER_PROP_SELECT_MULTIPLE:
5463       {
5464         gboolean select_multiple = g_value_get_boolean (value);
5465         if ((impl->action == GTK_FILE_CHOOSER_ACTION_SAVE ||
5466              impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
5467             && select_multiple)
5468           {
5469             g_warning ("Tried to set the file chooser to multiple selection mode, but this is "
5470                        "not allowed in SAVE or CREATE_FOLDER modes.  Ignoring the change and "
5471                        "leaving the file chooser in single selection mode.");
5472             return;
5473           }
5474
5475         set_select_multiple (impl, select_multiple, FALSE);
5476       }
5477       break;
5478
5479     case GTK_FILE_CHOOSER_PROP_SHOW_HIDDEN:
5480       {
5481         gboolean show_hidden = g_value_get_boolean (value);
5482         if (show_hidden != impl->show_hidden)
5483           {
5484             impl->show_hidden = show_hidden;
5485
5486             if (impl->browse_files_model)
5487               _gtk_file_system_model_set_show_hidden (impl->browse_files_model, show_hidden);
5488           }
5489       }
5490       break;
5491
5492     case GTK_FILE_CHOOSER_PROP_DO_OVERWRITE_CONFIRMATION:
5493       {
5494         gboolean do_overwrite_confirmation = g_value_get_boolean (value);
5495         impl->do_overwrite_confirmation = do_overwrite_confirmation;
5496       }
5497       break;
5498
5499     default:
5500       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
5501       break;
5502     }
5503 }
5504
5505 static void
5506 gtk_file_chooser_default_get_property (GObject    *object,
5507                                        guint       prop_id,
5508                                        GValue     *value,
5509                                        GParamSpec *pspec)
5510 {
5511   GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (object);
5512
5513   switch (prop_id)
5514     {
5515     case GTK_FILE_CHOOSER_PROP_ACTION:
5516       g_value_set_enum (value, impl->action);
5517       break;
5518
5519     case GTK_FILE_CHOOSER_PROP_FILTER:
5520       g_value_set_object (value, impl->current_filter);
5521       break;
5522
5523     case GTK_FILE_CHOOSER_PROP_LOCAL_ONLY:
5524       g_value_set_boolean (value, impl->local_only);
5525       break;
5526
5527     case GTK_FILE_CHOOSER_PROP_PREVIEW_WIDGET:
5528       g_value_set_object (value, impl->preview_widget);
5529       break;
5530
5531     case GTK_FILE_CHOOSER_PROP_PREVIEW_WIDGET_ACTIVE:
5532       g_value_set_boolean (value, impl->preview_widget_active);
5533       break;
5534
5535     case GTK_FILE_CHOOSER_PROP_USE_PREVIEW_LABEL:
5536       g_value_set_boolean (value, impl->use_preview_label);
5537       break;
5538
5539     case GTK_FILE_CHOOSER_PROP_EXTRA_WIDGET:
5540       g_value_set_object (value, impl->extra_widget);
5541       break;
5542
5543     case GTK_FILE_CHOOSER_PROP_SELECT_MULTIPLE:
5544       g_value_set_boolean (value, impl->select_multiple);
5545       break;
5546
5547     case GTK_FILE_CHOOSER_PROP_SHOW_HIDDEN:
5548       g_value_set_boolean (value, impl->show_hidden);
5549       break;
5550
5551     case GTK_FILE_CHOOSER_PROP_DO_OVERWRITE_CONFIRMATION:
5552       g_value_set_boolean (value, impl->do_overwrite_confirmation);
5553       break;
5554
5555     default:
5556       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
5557       break;
5558     }
5559 }
5560
5561 /* Removes the settings signal handler.  It's safe to call multiple times */
5562 static void
5563 remove_settings_signal (GtkFileChooserDefault *impl,
5564                         GdkScreen             *screen)
5565 {
5566   if (impl->settings_signal_id)
5567     {
5568       GtkSettings *settings;
5569
5570       settings = gtk_settings_get_for_screen (screen);
5571       g_signal_handler_disconnect (settings,
5572                                    impl->settings_signal_id);
5573       impl->settings_signal_id = 0;
5574     }
5575 }
5576
5577 static void
5578 gtk_file_chooser_default_dispose (GObject *object)
5579 {
5580   GSList *l;
5581   GtkFileChooserDefault *impl = (GtkFileChooserDefault *) object;
5582
5583   if (impl->extra_widget)
5584     {
5585       g_object_unref (impl->extra_widget);
5586       impl->extra_widget = NULL;
5587     }
5588
5589   if (impl->volumes_changed_id > 0)
5590     {
5591       g_signal_handler_disconnect (impl->file_system, impl->volumes_changed_id);
5592       impl->volumes_changed_id = 0;
5593     }
5594
5595   if (impl->bookmarks_changed_id > 0)
5596     {
5597       g_signal_handler_disconnect (impl->file_system, impl->bookmarks_changed_id);
5598       impl->bookmarks_changed_id = 0;
5599     }
5600
5601   pending_select_paths_free (impl);
5602
5603   /* cancel all pending operations */
5604   if (impl->pending_handles)
5605     {
5606       for (l = impl->pending_handles; l; l = l->next)
5607         {
5608           GtkFileSystemHandle *handle =l->data;
5609           gtk_file_system_cancel_operation (handle);
5610         }
5611       g_slist_free (impl->pending_handles);
5612       impl->pending_handles = NULL;
5613     }
5614
5615   if (impl->reload_icon_handles)
5616     {
5617       for (l = impl->reload_icon_handles; l; l = l->next)
5618         {
5619           GtkFileSystemHandle *handle =l->data;
5620           gtk_file_system_cancel_operation (handle);
5621         }
5622       g_slist_free (impl->reload_icon_handles);
5623       impl->reload_icon_handles = NULL;
5624     }
5625
5626   if (impl->loading_shortcuts)
5627     {
5628       for (l = impl->loading_shortcuts; l; l = l->next)
5629         {
5630           GtkFileSystemHandle *handle =l->data;
5631           gtk_file_system_cancel_operation (handle);
5632         }
5633       g_slist_free (impl->loading_shortcuts);
5634       impl->loading_shortcuts = NULL;
5635     }
5636
5637   if (impl->file_list_drag_data_received_handle)
5638     {
5639       gtk_file_system_cancel_operation (impl->file_list_drag_data_received_handle);
5640       impl->file_list_drag_data_received_handle = NULL;
5641     }
5642
5643   if (impl->update_current_folder_handle)
5644     {
5645       gtk_file_system_cancel_operation (impl->update_current_folder_handle);
5646       impl->update_current_folder_handle = NULL;
5647     }
5648
5649   if (impl->show_and_select_paths_handle)
5650     {
5651       gtk_file_system_cancel_operation (impl->show_and_select_paths_handle);
5652       impl->show_and_select_paths_handle = NULL;
5653     }
5654
5655   if (impl->should_respond_get_info_handle)
5656     {
5657       gtk_file_system_cancel_operation (impl->should_respond_get_info_handle);
5658       impl->should_respond_get_info_handle = NULL;
5659     }
5660
5661   if (impl->update_from_entry_handle)
5662     {
5663       gtk_file_system_cancel_operation (impl->update_from_entry_handle);
5664       impl->update_from_entry_handle = NULL;
5665     }
5666
5667   if (impl->shortcuts_activate_iter_handle)
5668     {
5669       gtk_file_system_cancel_operation (impl->shortcuts_activate_iter_handle);
5670       impl->shortcuts_activate_iter_handle = NULL;
5671     }
5672
5673   search_stop_searching (impl, TRUE);
5674   recent_stop_loading (impl);
5675
5676   remove_settings_signal (impl, gtk_widget_get_screen (GTK_WIDGET (impl)));
5677
5678   G_OBJECT_CLASS (_gtk_file_chooser_default_parent_class)->dispose (object);
5679 }
5680
5681 /* We override show-all since we have internal widgets that
5682  * shouldn't be shown when you call show_all(), like the filter
5683  * combo box.
5684  */
5685 static void
5686 gtk_file_chooser_default_show_all (GtkWidget *widget)
5687 {
5688   GtkFileChooserDefault *impl = (GtkFileChooserDefault *) widget;
5689
5690   gtk_widget_show (widget);
5691
5692   if (impl->extra_widget)
5693     gtk_widget_show_all (impl->extra_widget);
5694 }
5695
5696 /* Handler for GtkWindow::set-focus; this is where we save the last-focused
5697  * widget on our toplevel.  See gtk_file_chooser_default_hierarchy_changed()
5698  */
5699 static void
5700 toplevel_set_focus_cb (GtkWindow             *window,
5701                        GtkWidget             *focus,
5702                        GtkFileChooserDefault *impl)
5703 {
5704   impl->toplevel_last_focus_widget = gtk_window_get_focus (window);
5705 }
5706
5707 /* We monitor the focus widget on our toplevel to be able to know which widget
5708  * was last focused at the time our "should_respond" method gets called.
5709  */
5710 static void
5711 gtk_file_chooser_default_hierarchy_changed (GtkWidget *widget,
5712                                             GtkWidget *previous_toplevel)
5713 {
5714   GtkFileChooserDefault *impl;
5715   GtkWidget *toplevel;
5716
5717   impl = GTK_FILE_CHOOSER_DEFAULT (widget);
5718
5719   if (previous_toplevel)
5720     {
5721       g_assert (impl->toplevel_set_focus_id != 0);
5722       g_signal_handler_disconnect (previous_toplevel, impl->toplevel_set_focus_id);
5723       impl->toplevel_set_focus_id = 0;
5724       impl->toplevel_last_focus_widget = NULL;
5725     }
5726   else
5727     g_assert (impl->toplevel_set_focus_id == 0);
5728
5729   toplevel = gtk_widget_get_toplevel (widget);
5730   if (GTK_IS_WINDOW (toplevel))
5731     {
5732       impl->toplevel_set_focus_id = g_signal_connect (toplevel, "set_focus",
5733                                                       G_CALLBACK (toplevel_set_focus_cb), impl);
5734       impl->toplevel_last_focus_widget = gtk_window_get_focus (GTK_WINDOW (toplevel));
5735     }
5736 }
5737
5738 /* Changes the icons wherever it is needed */
5739 static void
5740 change_icon_theme (GtkFileChooserDefault *impl)
5741 {
5742   GtkSettings *settings;
5743   gint width, height;
5744
5745   profile_start ("start", NULL);
5746
5747   settings = gtk_settings_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (impl)));
5748
5749   if (gtk_icon_size_lookup_for_settings (settings, GTK_ICON_SIZE_MENU, &width, &height))
5750     impl->icon_size = MAX (width, height);
5751   else
5752     impl->icon_size = FALLBACK_ICON_SIZE;
5753
5754   shortcuts_reload_icons (impl);
5755   gtk_widget_queue_resize (impl->browse_files_tree_view);
5756
5757   profile_end ("end", NULL);
5758 }
5759
5760 /* Callback used when a GtkSettings value changes */
5761 static void
5762 settings_notify_cb (GObject               *object,
5763                     GParamSpec            *pspec,
5764                     GtkFileChooserDefault *impl)
5765 {
5766   const char *name;
5767
5768   profile_start ("start", NULL);
5769
5770   name = g_param_spec_get_name (pspec);
5771
5772   if (strcmp (name, "gtk-icon-theme-name") == 0 ||
5773       strcmp (name, "gtk-icon-sizes") == 0)
5774     change_icon_theme (impl);
5775
5776   profile_end ("end", NULL);
5777 }
5778
5779 /* Installs a signal handler for GtkSettings so that we can monitor changes in
5780  * the icon theme.
5781  */
5782 static void
5783 check_icon_theme (GtkFileChooserDefault *impl)
5784 {
5785   GtkSettings *settings;
5786
5787   profile_start ("start", NULL);
5788
5789   if (impl->settings_signal_id)
5790     {
5791       profile_end ("end", NULL);
5792       return;
5793     }
5794
5795   if (gtk_widget_has_screen (GTK_WIDGET (impl)))
5796     {
5797       settings = gtk_settings_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (impl)));
5798       impl->settings_signal_id = g_signal_connect (settings, "notify",
5799                                                    G_CALLBACK (settings_notify_cb), impl);
5800
5801       change_icon_theme (impl);
5802     }
5803
5804   profile_end ("end", NULL);
5805 }
5806
5807 static void
5808 recent_manager_update (GtkFileChooserDefault *impl)
5809 {
5810   GtkRecentManager *manager;
5811
5812   profile_start ("start", NULL);
5813
5814   if (gtk_widget_has_screen (GTK_WIDGET (impl)))
5815     manager = gtk_recent_manager_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (impl)));
5816   else
5817     manager = gtk_recent_manager_get_default ();
5818
5819   if (impl->recent_manager != manager)
5820     impl->recent_manager = manager;
5821
5822   profile_end ("end", NULL);
5823 }
5824
5825 static void
5826 gtk_file_chooser_default_style_set (GtkWidget *widget,
5827                                     GtkStyle  *previous_style)
5828 {
5829   GtkFileChooserDefault *impl;
5830
5831   profile_start ("start", NULL);
5832
5833   impl = GTK_FILE_CHOOSER_DEFAULT (widget);
5834
5835   profile_msg ("    parent class style_set start", NULL);
5836   if (GTK_WIDGET_CLASS (_gtk_file_chooser_default_parent_class)->style_set)
5837     GTK_WIDGET_CLASS (_gtk_file_chooser_default_parent_class)->style_set (widget, previous_style);
5838   profile_msg ("    parent class style_set end", NULL);
5839
5840   if (gtk_widget_has_screen (GTK_WIDGET (impl)))
5841     change_icon_theme (impl);
5842
5843   profile_msg ("    emit default-size-changed start", NULL);
5844   g_signal_emit_by_name (widget, "default-size-changed");
5845   profile_msg ("    emit default-size-changed end", NULL);
5846
5847   profile_end ("end", NULL);
5848 }
5849
5850 static void
5851 gtk_file_chooser_default_screen_changed (GtkWidget *widget,
5852                                          GdkScreen *previous_screen)
5853 {
5854   GtkFileChooserDefault *impl;
5855
5856   profile_start ("start", NULL);
5857
5858   impl = GTK_FILE_CHOOSER_DEFAULT (widget);
5859
5860   if (GTK_WIDGET_CLASS (_gtk_file_chooser_default_parent_class)->screen_changed)
5861     GTK_WIDGET_CLASS (_gtk_file_chooser_default_parent_class)->screen_changed (widget, previous_screen);
5862
5863   remove_settings_signal (impl, previous_screen);
5864   check_icon_theme (impl);
5865   recent_manager_update (impl);
5866
5867   g_signal_emit_by_name (widget, "default-size-changed");
5868
5869   profile_end ("end", NULL);
5870 }
5871
5872 static gboolean
5873 get_is_file_filtered (GtkFileChooserDefault *impl,
5874                       const GtkFilePath     *path,
5875                       GtkFileInfo           *file_info)
5876 {
5877   GtkFileFilterInfo filter_info;
5878   GtkFileFilterFlags needed;
5879   gboolean result;
5880
5881   if (!impl->current_filter)
5882     return FALSE;
5883
5884   filter_info.contains = GTK_FILE_FILTER_DISPLAY_NAME | GTK_FILE_FILTER_MIME_TYPE;
5885
5886   needed = gtk_file_filter_get_needed (impl->current_filter);
5887
5888   filter_info.display_name = gtk_file_info_get_display_name (file_info);
5889   filter_info.mime_type = gtk_file_info_get_mime_type (file_info);
5890
5891   if (needed & GTK_FILE_FILTER_FILENAME)
5892     {
5893       filter_info.filename = gtk_file_system_path_to_filename (impl->file_system, path);
5894       if (filter_info.filename)
5895         filter_info.contains |= GTK_FILE_FILTER_FILENAME;
5896     }
5897   else
5898     filter_info.filename = NULL;
5899
5900   if (needed & GTK_FILE_FILTER_URI)
5901     {
5902       filter_info.uri = gtk_file_system_path_to_uri (impl->file_system, path);
5903       if (filter_info.uri)
5904         filter_info.contains |= GTK_FILE_FILTER_URI;
5905     }
5906   else
5907     filter_info.uri = NULL;
5908
5909   result = gtk_file_filter_filter (impl->current_filter, &filter_info);
5910
5911   if (filter_info.filename)
5912     g_free ((gchar *)filter_info.filename);
5913   if (filter_info.uri)
5914     g_free ((gchar *)filter_info.uri);
5915
5916   return !result;
5917 }
5918
5919 static void
5920 settings_load (GtkFileChooserDefault *impl)
5921 {
5922   GtkFileChooserSettings *settings;
5923   LocationMode location_mode;
5924   gboolean show_hidden;
5925   gboolean expand_folders;
5926
5927   settings = _gtk_file_chooser_settings_new ();
5928
5929   location_mode = _gtk_file_chooser_settings_get_location_mode (settings);
5930   show_hidden = _gtk_file_chooser_settings_get_show_hidden (settings);
5931   expand_folders = _gtk_file_chooser_settings_get_expand_folders (settings);
5932
5933   g_object_unref (settings);
5934
5935   location_mode_set (impl, location_mode, TRUE);
5936   gtk_file_chooser_set_show_hidden (GTK_FILE_CHOOSER (impl), show_hidden);
5937   impl->expand_folders = expand_folders;
5938   if (impl->save_expander)
5939     gtk_expander_set_expanded (GTK_EXPANDER (impl->save_expander), expand_folders);
5940 }
5941
5942 static void
5943 settings_save (GtkFileChooserDefault *impl)
5944 {
5945   GtkFileChooserSettings *settings;
5946
5947   settings = _gtk_file_chooser_settings_new ();
5948
5949   _gtk_file_chooser_settings_set_location_mode (settings, impl->location_mode);
5950   _gtk_file_chooser_settings_set_show_hidden (settings, gtk_file_chooser_get_show_hidden (GTK_FILE_CHOOSER (impl)));
5951   _gtk_file_chooser_settings_set_expand_folders (settings, impl->expand_folders);
5952
5953   /* NULL GError */
5954   _gtk_file_chooser_settings_save (settings, NULL);
5955
5956   g_object_unref (settings);
5957 }
5958
5959 /* GtkWidget::map method */
5960 static void
5961 gtk_file_chooser_default_map (GtkWidget *widget)
5962 {
5963   GtkFileChooserDefault *impl;
5964   char *current_working_dir;
5965
5966   profile_start ("start", NULL);
5967
5968   impl = GTK_FILE_CHOOSER_DEFAULT (widget);
5969
5970   GTK_WIDGET_CLASS (_gtk_file_chooser_default_parent_class)->map (widget);
5971
5972   if (impl->operation_mode == OPERATION_MODE_BROWSE)
5973     {
5974       switch (impl->reload_state)
5975         {
5976         case RELOAD_EMPTY:
5977           /* The user didn't explicitly give us a folder to
5978            * display, so we'll use the cwd
5979            */
5980           current_working_dir = g_get_current_dir ();
5981           gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (impl),
5982                                                current_working_dir);
5983           g_free (current_working_dir);
5984           break;
5985         
5986         case RELOAD_HAS_FOLDER:
5987           /* Nothing; we are already loading or loaded, so we
5988            * don't need to reload
5989            */
5990           break;
5991
5992         case RELOAD_WAS_UNMAPPED:
5993           /* Just reload the current folder; else continue
5994            * the pending load.
5995            */
5996           if (impl->current_folder)
5997             {
5998               pending_select_paths_store_selection (impl);
5999               change_folder_and_display_error (impl, impl->current_folder, FALSE);
6000             }
6001           break;
6002
6003         default:
6004           g_assert_not_reached ();
6005       }
6006     }
6007
6008   bookmarks_changed_cb (impl->file_system, impl);
6009
6010   settings_load (impl);
6011
6012   profile_end ("end", NULL);
6013 }
6014
6015 /* GtkWidget::unmap method */
6016 static void
6017 gtk_file_chooser_default_unmap (GtkWidget *widget)
6018 {
6019   GtkFileChooserDefault *impl;
6020
6021   impl = GTK_FILE_CHOOSER_DEFAULT (widget);
6022
6023   settings_save (impl);
6024
6025   GTK_WIDGET_CLASS (_gtk_file_chooser_default_parent_class)->unmap (widget);
6026
6027   impl->reload_state = RELOAD_WAS_UNMAPPED;
6028 }
6029
6030 static gboolean
6031 list_model_filter_func (GtkFileSystemModel *model,
6032                         GtkFilePath        *path,
6033                         const GtkFileInfo  *file_info,
6034                         gpointer            user_data)
6035 {
6036   GtkFileChooserDefault *impl = user_data;
6037
6038   if (!impl->current_filter)
6039     return TRUE;
6040
6041   if (gtk_file_info_get_is_folder (file_info))
6042     return TRUE;
6043
6044   return !get_is_file_filtered (impl, path, (GtkFileInfo *) file_info);
6045 }
6046
6047 static void
6048 install_list_model_filter (GtkFileChooserDefault *impl)
6049 {
6050   GtkFileSystemModelFilter filter;
6051   gpointer data;
6052
6053   g_assert (impl->browse_files_model != NULL);
6054
6055   if (impl->current_filter)
6056     {
6057       filter = list_model_filter_func;
6058       data   = impl;
6059     }
6060   else
6061     {
6062       filter = NULL;
6063       data   = NULL;
6064     }
6065   
6066   _gtk_file_system_model_set_filter (impl->browse_files_model,
6067                                      filter,
6068                                      data);
6069 }
6070
6071 #define COMPARE_DIRECTORIES                                                                                    \
6072   GtkFileChooserDefault *impl = user_data;                                                                     \
6073   const GtkFileInfo *info_a = _gtk_file_system_model_get_info (impl->browse_files_model, a);                   \
6074   const GtkFileInfo *info_b = _gtk_file_system_model_get_info (impl->browse_files_model, b);                   \
6075   gboolean dir_a, dir_b;                                                                                       \
6076                                                                                                                \
6077   if (info_a)                                                                                                  \
6078     dir_a = gtk_file_info_get_is_folder (info_a);                                                              \
6079   else                                                                                                         \
6080     return impl->list_sort_ascending ? -1 : 1;                                                                 \
6081                                                                                                                \
6082   if (info_b)                                                                                                  \
6083     dir_b = gtk_file_info_get_is_folder (info_b);                                                              \
6084   else                                                                                                         \
6085     return impl->list_sort_ascending ? 1 : -1;                                                                 \
6086                                                                                                                \
6087   if (dir_a != dir_b)                                                                                          \
6088     return impl->list_sort_ascending ? (dir_a ? -1 : 1) : (dir_a ? 1 : -1) /* Directories *always* go first */
6089
6090 /* Sort callback for the filename column */
6091 static gint
6092 name_sort_func (GtkTreeModel *model,
6093                 GtkTreeIter  *a,
6094                 GtkTreeIter  *b,
6095                 gpointer      user_data)
6096 {
6097   COMPARE_DIRECTORIES;
6098   else
6099     return strcmp (gtk_file_info_get_display_key (info_a), gtk_file_info_get_display_key (info_b));
6100 }
6101
6102 /* Sort callback for the size column */
6103 static gint
6104 size_sort_func (GtkTreeModel *model,
6105                 GtkTreeIter  *a,
6106                 GtkTreeIter  *b,
6107                 gpointer      user_data)
6108 {
6109   COMPARE_DIRECTORIES;
6110   else
6111     {
6112       gint64 size_a = gtk_file_info_get_size (info_a);
6113       gint64 size_b = gtk_file_info_get_size (info_b);
6114
6115       return size_a > size_b ? -1 : (size_a == size_b ? 0 : 1);
6116     }
6117 }
6118
6119 /* Sort callback for the mtime column */
6120 static gint
6121 mtime_sort_func (GtkTreeModel *model,
6122                  GtkTreeIter  *a,
6123                  GtkTreeIter  *b,
6124                  gpointer      user_data)
6125 {
6126   COMPARE_DIRECTORIES;
6127   else
6128     {
6129       GtkFileTime ta = gtk_file_info_get_modification_time (info_a);
6130       GtkFileTime tb = gtk_file_info_get_modification_time (info_b);
6131
6132       return ta > tb ? -1 : (ta == tb ? 0 : 1);
6133     }
6134 }
6135
6136 /* Callback used when the sort column changes.  We cache the sort order for use
6137  * in name_sort_func().
6138  */
6139 static void
6140 list_sort_column_changed_cb (GtkTreeSortable       *sortable,
6141                              GtkFileChooserDefault *impl)
6142 {
6143   GtkSortType sort_type;
6144
6145   if (gtk_tree_sortable_get_sort_column_id (sortable, NULL, &sort_type))
6146     impl->list_sort_ascending = (sort_type == GTK_SORT_ASCENDING);
6147 }
6148
6149 static void
6150 set_busy_cursor (GtkFileChooserDefault *impl,
6151                  gboolean               busy)
6152 {
6153   GtkWindow *toplevel;
6154   GdkDisplay *display;
6155   GdkCursor *cursor;
6156
6157   toplevel = get_toplevel (GTK_WIDGET (impl));
6158   if (!toplevel || !GTK_WIDGET_REALIZED (toplevel))
6159     return;
6160
6161   display = gtk_widget_get_display (GTK_WIDGET (toplevel));
6162
6163   if (busy)
6164     cursor = gdk_cursor_new_for_display (display, GDK_WATCH);
6165   else
6166     cursor = NULL;
6167
6168   gdk_window_set_cursor (GTK_WIDGET (toplevel)->window, cursor);
6169   gdk_display_flush (display);
6170
6171   if (cursor)
6172     gdk_cursor_unref (cursor);
6173 }
6174
6175 /* Creates a sort model to wrap the file system model and sets it on the tree view */
6176 static void
6177 load_set_model (GtkFileChooserDefault *impl)
6178 {
6179   profile_start ("start", NULL);
6180
6181   g_assert (impl->browse_files_model != NULL);
6182   g_assert (impl->sort_model == NULL);
6183
6184   profile_msg ("    gtk_tree_model_sort_new_with_model start", NULL);
6185   impl->sort_model = (GtkTreeModelSort *)gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (impl->browse_files_model));
6186   gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->sort_model), FILE_LIST_COL_NAME, name_sort_func, impl, NULL);
6187   gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->sort_model), FILE_LIST_COL_SIZE, size_sort_func, impl, NULL);
6188   gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->sort_model), FILE_LIST_COL_MTIME, mtime_sort_func, impl, NULL);
6189   gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (impl->sort_model), NULL, NULL, NULL);
6190   gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (impl->sort_model), FILE_LIST_COL_NAME, GTK_SORT_ASCENDING);
6191   impl->list_sort_ascending = TRUE;
6192   profile_msg ("    gtk_tree_model_sort_new_with_model end", NULL);
6193
6194   g_signal_connect (impl->sort_model, "sort_column_changed",
6195                     G_CALLBACK (list_sort_column_changed_cb), impl);
6196
6197   profile_msg ("    gtk_tree_view_set_model start", NULL);
6198   gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view),
6199                            GTK_TREE_MODEL (impl->sort_model));
6200   gtk_tree_view_columns_autosize (GTK_TREE_VIEW (impl->browse_files_tree_view));
6201   gtk_tree_view_set_search_column (GTK_TREE_VIEW (impl->browse_files_tree_view),
6202                                    GTK_FILE_SYSTEM_MODEL_DISPLAY_NAME);
6203   profile_msg ("    gtk_tree_view_set_model end", NULL);
6204
6205   profile_end ("end", NULL);
6206 }
6207
6208 /* Timeout callback used when the loading timer expires */
6209 static gboolean
6210 load_timeout_cb (gpointer data)
6211 {
6212   GtkFileChooserDefault *impl;
6213
6214   profile_start ("start", NULL);
6215
6216   impl = GTK_FILE_CHOOSER_DEFAULT (data);
6217   g_assert (impl->load_state == LOAD_PRELOAD);
6218   g_assert (impl->load_timeout_id != 0);
6219   g_assert (impl->browse_files_model != NULL);
6220
6221   impl->load_timeout_id = 0;
6222   impl->load_state = LOAD_LOADING;
6223
6224   load_set_model (impl);
6225
6226   profile_end ("end", NULL);
6227
6228   return FALSE;
6229 }
6230
6231 /* Sets up a new load timer for the model and switches to the LOAD_PRELOAD state */
6232 static void
6233 load_setup_timer (GtkFileChooserDefault *impl)
6234 {
6235   g_assert (impl->load_timeout_id == 0);
6236   g_assert (impl->load_state != LOAD_PRELOAD);
6237
6238   impl->load_timeout_id = gdk_threads_add_timeout (MAX_LOADING_TIME, load_timeout_cb, impl);
6239   impl->load_state = LOAD_PRELOAD;
6240 }
6241
6242 /* Removes the load timeout and switches to the LOAD_FINISHED state */
6243 static void
6244 load_remove_timer (GtkFileChooserDefault *impl)
6245 {
6246   if (impl->load_timeout_id != 0)
6247     {
6248       g_assert (impl->load_state == LOAD_PRELOAD);
6249
6250       g_source_remove (impl->load_timeout_id);
6251       impl->load_timeout_id = 0;
6252       impl->load_state = LOAD_EMPTY;
6253     }
6254   else
6255     g_assert (impl->load_state == LOAD_EMPTY ||
6256               impl->load_state == LOAD_LOADING ||
6257               impl->load_state == LOAD_FINISHED);
6258 }
6259
6260 /* Selects the first row in the file list */
6261 static void
6262 browse_files_select_first_row (GtkFileChooserDefault *impl)
6263 {
6264   GtkTreePath *path;
6265
6266   if (!impl->sort_model)
6267     return;
6268
6269   path = gtk_tree_path_new_from_indices (0, -1);
6270   gtk_tree_view_set_cursor (GTK_TREE_VIEW (impl->browse_files_tree_view), path, NULL, FALSE);
6271   gtk_tree_path_free (path);
6272 }
6273
6274 struct center_selected_row_closure {
6275   GtkFileChooserDefault *impl;
6276   gboolean already_centered;
6277 };
6278
6279 /* Callback used from gtk_tree_selection_selected_foreach(); centers the
6280  * selected row in the tree view.
6281  */
6282 static void
6283 center_selected_row_foreach_cb (GtkTreeModel      *model,
6284                                 GtkTreePath       *path,
6285                                 GtkTreeIter       *iter,
6286                                 gpointer           data)
6287 {
6288   struct center_selected_row_closure *closure;
6289
6290   closure = data;
6291   if (closure->already_centered)
6292     return;
6293
6294   gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (closure->impl->browse_files_tree_view), path, NULL, TRUE, 0.5, 0.0);
6295   closure->already_centered = TRUE;
6296 }
6297
6298 /* Centers the selected row in the tree view */
6299 static void
6300 browse_files_center_selected_row (GtkFileChooserDefault *impl)
6301 {
6302   struct center_selected_row_closure closure;
6303   GtkTreeSelection *selection;
6304
6305   closure.impl = impl;
6306   closure.already_centered = FALSE;
6307
6308   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
6309   gtk_tree_selection_selected_foreach (selection, center_selected_row_foreach_cb, &closure);
6310 }
6311
6312 struct ShowAndSelectPathsData
6313 {
6314   GtkFileChooserDefault *impl;
6315   GSList *paths;
6316 };
6317
6318 static void
6319 show_and_select_paths_finished_loading (GtkFileFolder *folder,
6320                                         gpointer user_data)
6321 {
6322   gboolean have_hidden;
6323   gboolean have_filtered;
6324   GSList *l;
6325   struct ShowAndSelectPathsData *data = user_data;
6326
6327   have_hidden = FALSE;
6328   have_filtered = FALSE;
6329
6330   for (l = data->paths; l; l = l->next)
6331     {
6332       const GtkFilePath *path;
6333       GtkFileInfo *info;
6334
6335       path = l->data;
6336
6337       /* NULL GError */
6338       info = gtk_file_folder_get_info (folder, path, NULL);
6339       if (info)
6340         {
6341           if (!have_hidden)
6342             have_hidden = gtk_file_info_get_is_hidden (info);
6343
6344           if (!have_filtered)
6345             have_filtered = !gtk_file_info_get_is_folder (info) && get_is_file_filtered (data->impl, path, info);
6346
6347           gtk_file_info_free (info);
6348
6349           if (have_hidden && have_filtered)
6350             break; /* we now have all the information we need */
6351         }
6352     }
6353
6354   g_signal_handlers_disconnect_by_func (folder,
6355                                         show_and_select_paths_finished_loading,
6356                                         user_data);
6357
6358   g_object_unref (folder);
6359
6360   if (have_hidden)
6361     g_object_set (data->impl, "show-hidden", TRUE, NULL);
6362
6363   if (have_filtered)
6364     set_current_filter (data->impl, NULL);
6365
6366   for (l = data->paths; l; l = l->next)
6367     {
6368       const GtkFilePath *path;
6369
6370       path = l->data;
6371       _gtk_file_system_model_path_do (data->impl->browse_files_model, path,
6372                                       select_func, data->impl);
6373     }
6374
6375   browse_files_center_selected_row (data->impl);
6376
6377   g_object_unref (data->impl);
6378   gtk_file_paths_free (data->paths);
6379   g_free (data);
6380 }
6381
6382 static void
6383 show_and_select_paths_get_folder_cb (GtkFileSystemHandle   *handle,
6384                                      GtkFileFolder         *folder,
6385                                      const GError          *error,
6386                                      gpointer               user_data)
6387 {
6388   gboolean cancelled = handle->cancelled;
6389   struct ShowAndSelectPathsData *data = user_data;
6390
6391   if (data->impl->show_and_select_paths_handle != handle)
6392     goto out;
6393
6394   data->impl->show_and_select_paths_handle = NULL;
6395
6396   if (cancelled || error)
6397     goto out;
6398
6399   g_object_unref (handle);
6400
6401   if (gtk_file_folder_is_finished_loading (folder))
6402     show_and_select_paths_finished_loading (folder, user_data);
6403   else
6404     g_signal_connect (folder, "finished-loading",
6405                       G_CALLBACK (show_and_select_paths_finished_loading),
6406                       user_data);
6407
6408   return;
6409
6410 out:
6411   g_object_unref (data->impl);
6412   gtk_file_paths_free (data->paths);
6413   g_free (data);
6414
6415   g_object_unref (handle);
6416 }
6417
6418 static gboolean
6419 show_and_select_paths (GtkFileChooserDefault *impl,
6420                        const GtkFilePath     *parent_path,
6421                        GSList                *paths,
6422                        GError                **error)
6423 {
6424   struct ShowAndSelectPathsData *info;
6425
6426   profile_start ("start", NULL);
6427
6428   if (!paths)
6429     {
6430       profile_end ("end", NULL);
6431       return TRUE;
6432     }
6433
6434   info = g_new (struct ShowAndSelectPathsData, 1);
6435   info->impl = g_object_ref (impl);
6436   info->paths = gtk_file_paths_copy (paths);
6437
6438   if (impl->show_and_select_paths_handle)
6439     gtk_file_system_cancel_operation (impl->show_and_select_paths_handle);
6440
6441   impl->show_and_select_paths_handle =
6442     gtk_file_system_get_folder (impl->file_system, parent_path,
6443                                 GTK_FILE_INFO_IS_FOLDER | GTK_FILE_INFO_IS_HIDDEN,
6444                                 show_and_select_paths_get_folder_cb, info);
6445
6446   profile_end ("end", NULL);
6447   return TRUE;
6448 }
6449
6450 /* Processes the pending operation when a folder is finished loading */
6451 static void
6452 pending_select_paths_process (GtkFileChooserDefault *impl)
6453 {
6454   g_assert (impl->load_state == LOAD_FINISHED);
6455   g_assert (impl->browse_files_model != NULL);
6456   g_assert (impl->sort_model != NULL);
6457
6458   if (impl->pending_select_paths)
6459     {
6460       /* NULL GError */
6461       show_and_select_paths (impl, impl->current_folder, impl->pending_select_paths, NULL);
6462       pending_select_paths_free (impl);
6463       browse_files_center_selected_row (impl);
6464     }
6465   else
6466     {
6467       /* We only select the first row if the chooser is actually mapped ---
6468        * selecting the first row is to help the user when he is interacting with
6469        * the chooser, but sometimes a chooser works not on behalf of the user,
6470        * but rather on behalf of something else like GtkFileChooserButton.  In
6471        * that case, the chooser's selection should be what the caller expects,
6472        * as the user can't see that something else got selected.  See bug #165264.
6473        */
6474       if (GTK_WIDGET_MAPPED (impl) && impl->action == GTK_FILE_CHOOSER_ACTION_OPEN)
6475         browse_files_select_first_row (impl);
6476     }
6477
6478   g_assert (impl->pending_select_paths == NULL);
6479 }
6480
6481 /* Callback used when the file system model finishes loading */
6482 static void
6483 browse_files_model_finished_loading_cb (GtkFileSystemModel    *model,
6484                                         GtkFileChooserDefault *impl)
6485 {
6486   profile_start ("start", NULL);
6487
6488   if (impl->load_state == LOAD_PRELOAD)
6489     {
6490       load_remove_timer (impl);
6491       load_set_model (impl);
6492     }
6493   else if (impl->load_state == LOAD_LOADING)
6494     {
6495       /* Nothing */
6496     }
6497   else
6498     {
6499       /* We can't g_assert_not_reached(), as something other than us may have
6500        *  initiated a folder reload.  See #165556.
6501        */
6502       profile_end ("end", NULL);
6503       return;
6504     }
6505
6506   g_assert (impl->load_timeout_id == 0);
6507
6508   impl->load_state = LOAD_FINISHED;
6509
6510   pending_select_paths_process (impl);
6511   set_busy_cursor (impl, FALSE);
6512 #ifdef PROFILE_FILE_CHOOSER
6513   access ("MARK: *** FINISHED LOADING", F_OK);
6514 #endif
6515
6516   profile_end ("end", NULL);
6517 }
6518
6519 static void
6520 stop_loading_and_clear_list_model (GtkFileChooserDefault *impl)
6521 {
6522   load_remove_timer (impl); /* This changes the state to LOAD_EMPTY */
6523   
6524   if (impl->browse_files_model)
6525     {
6526       g_object_unref (impl->browse_files_model);
6527       impl->browse_files_model = NULL;
6528     }
6529
6530   if (impl->sort_model)
6531     {
6532       g_object_unref (impl->sort_model);
6533       impl->sort_model = NULL;
6534     }
6535   
6536   gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view), NULL);
6537 }
6538
6539 /* Gets rid of the old list model and creates a new one for the current folder */
6540 static gboolean
6541 set_list_model (GtkFileChooserDefault *impl,
6542                 GError               **error)
6543 {
6544   g_assert (impl->current_folder != NULL);
6545
6546   profile_start ("start", NULL);
6547
6548   stop_loading_and_clear_list_model (impl);
6549
6550   set_busy_cursor (impl, TRUE);
6551   gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view), NULL);
6552
6553   impl->browse_files_model = _gtk_file_system_model_new (impl->file_system,
6554                                                          impl->current_folder, 0,
6555                                                          GTK_FILE_INFO_ALL,
6556                                                          error);
6557   if (!impl->browse_files_model)
6558     {
6559       set_busy_cursor (impl, FALSE);
6560       profile_end ("end", NULL);
6561       return FALSE;
6562     }
6563
6564   load_setup_timer (impl); /* This changes the state to LOAD_PRELOAD */
6565
6566   g_signal_connect (impl->browse_files_model, "finished-loading",
6567                     G_CALLBACK (browse_files_model_finished_loading_cb), impl);
6568
6569   _gtk_file_system_model_set_show_hidden (impl->browse_files_model, impl->show_hidden);
6570
6571   install_list_model_filter (impl);
6572
6573   profile_end ("end", NULL);
6574
6575   return TRUE;
6576 }
6577
6578 struct update_chooser_entry_selected_foreach_closure {
6579   int num_selected;
6580   GtkTreeIter first_selected_iter;
6581 };
6582
6583 static gint
6584 compare_utf8_filenames (const gchar *a,
6585                         const gchar *b)
6586 {
6587   gchar *a_folded, *b_folded;
6588   gint retval;
6589
6590   a_folded = g_utf8_strdown (a, -1);
6591   b_folded = g_utf8_strdown (b, -1);
6592
6593   retval = strcmp (a_folded, b_folded);
6594
6595   g_free (a_folded);
6596   g_free (b_folded);
6597
6598   return retval;
6599 }
6600
6601 static void
6602 update_chooser_entry_selected_foreach (GtkTreeModel *model,
6603                                        GtkTreePath *path,
6604                                        GtkTreeIter *iter,
6605                                        gpointer data)
6606 {
6607   struct update_chooser_entry_selected_foreach_closure *closure;
6608
6609   closure = data;
6610   closure->num_selected++;
6611
6612   if (closure->num_selected == 1)
6613     closure->first_selected_iter = *iter;
6614 }
6615
6616 static void
6617 update_chooser_entry (GtkFileChooserDefault *impl)
6618 {
6619   GtkTreeSelection *selection;
6620   struct update_chooser_entry_selected_foreach_closure closure;
6621   const char *file_part;
6622
6623   if (impl->operation_mode == OPERATION_MODE_SEARCH ||
6624       impl->operation_mode == OPERATION_MODE_RECENT ||
6625       !impl->location_entry)
6626     return;
6627
6628   if (!(impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
6629         || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER
6630         || ((impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
6631              || impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
6632             && impl->location_mode == LOCATION_MODE_FILENAME_ENTRY)))
6633     return;
6634
6635   g_assert (impl->location_entry != NULL);
6636
6637   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
6638   closure.num_selected = 0;
6639   gtk_tree_selection_selected_foreach (selection, update_chooser_entry_selected_foreach, &closure);
6640
6641   file_part = NULL;
6642
6643   if (closure.num_selected == 0)
6644     {
6645       goto maybe_clear_entry;
6646     }
6647   else if (closure.num_selected == 1)
6648     {
6649       GtkTreeIter child_iter;
6650       
6651       if (impl->operation_mode == OPERATION_MODE_BROWSE)
6652         {
6653           const GtkFileInfo *info;
6654           gboolean change_entry;
6655
6656           gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model,
6657                                                           &child_iter,
6658                                                           &closure.first_selected_iter);
6659
6660           info = _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
6661
6662           /* If the cursor moved to the row of the newly created folder, 
6663            * retrieving info will return NULL.
6664            */
6665           if (!info)
6666             return;
6667
6668           g_free (impl->browse_files_last_selected_name);
6669           impl->browse_files_last_selected_name =
6670             g_strdup (gtk_file_info_get_display_name (info));
6671
6672           if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
6673               impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
6674             change_entry = !gtk_file_info_get_is_folder (info); /* We don't want the name to change when clicking on a folder... */
6675           else
6676             change_entry = TRUE;                                /* ... unless we are in one of the folder modes */
6677
6678           if (change_entry)
6679             _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry),
6680                                                    impl->browse_files_last_selected_name);
6681
6682         }
6683       else if (impl->operation_mode == OPERATION_MODE_SEARCH)
6684         {
6685           gtk_tree_model_filter_convert_iter_to_child_iter (impl->search_model_filter,
6686                                                             &child_iter,
6687                                                             &closure.first_selected_iter);
6688           gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &child_iter,
6689                               SEARCH_MODEL_COL_DISPLAY_NAME, &file_part,
6690                               -1);
6691         }
6692       else if (impl->operation_mode == OPERATION_MODE_RECENT)
6693         {
6694           gtk_tree_model_filter_convert_iter_to_child_iter (impl->recent_model_filter,
6695                                                             &child_iter,
6696                                                             &closure.first_selected_iter);
6697           gtk_tree_model_get (GTK_TREE_MODEL (impl->recent_model), &child_iter,
6698                               RECENT_MODEL_COL_DISPLAY_NAME, &file_part,
6699                               -1);
6700         }
6701     }
6702   else
6703     {
6704       g_assert (!(impl->action == GTK_FILE_CHOOSER_ACTION_SAVE ||
6705                   impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER));
6706
6707       /* Multiple selection, so just clear the entry. */
6708
6709       g_free (impl->browse_files_last_selected_name);
6710       impl->browse_files_last_selected_name = NULL;
6711
6712       _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), "");
6713       return;
6714     }
6715
6716  maybe_clear_entry:
6717
6718   if (impl->browse_files_last_selected_name)
6719     {
6720       const char *entry_text;
6721       int len;
6722       gboolean clear_entry;
6723
6724       entry_text = gtk_entry_get_text (GTK_ENTRY (impl->location_entry));
6725       len = strlen (entry_text);
6726       if (len != 0)
6727         {
6728           /* The file chooser entry may have appended a "/" to its text.  So
6729            * take it out, and compare the result to the old selection.
6730            */
6731           if (entry_text[len - 1] == G_DIR_SEPARATOR)
6732             {
6733               char *tmp;
6734
6735               tmp = g_strndup (entry_text, len - 1);
6736               clear_entry = (compare_utf8_filenames (impl->browse_files_last_selected_name, tmp) == 0);
6737               g_free (tmp);
6738             }
6739           else
6740             clear_entry = (compare_utf8_filenames (impl->browse_files_last_selected_name, entry_text) == 0);
6741         }
6742       else
6743         clear_entry = FALSE;
6744
6745       if (clear_entry)
6746         _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), "");
6747     }
6748 }
6749
6750 static gboolean
6751 gtk_file_chooser_default_set_current_folder (GtkFileChooser    *chooser,
6752                                              const GtkFilePath *path,
6753                                              GError           **error)
6754 {
6755   return gtk_file_chooser_default_update_current_folder (chooser, path, FALSE, FALSE, error);
6756 }
6757
6758
6759 struct UpdateCurrentFolderData
6760 {
6761   GtkFileChooserDefault *impl;
6762   GtkFilePath *path;
6763   gboolean keep_trail;
6764   gboolean clear_entry;
6765   GtkFilePath *original_path;
6766   GError *original_error;
6767 };
6768
6769 static void
6770 update_current_folder_get_info_cb (GtkFileSystemHandle *handle,
6771                                    const GtkFileInfo   *info,
6772                                    const GError        *error,
6773                                    gpointer             user_data)
6774 {
6775   gboolean cancelled = handle->cancelled;
6776   struct UpdateCurrentFolderData *data = user_data;
6777   GtkFileChooserDefault *impl = data->impl;
6778
6779   if (handle != impl->update_current_folder_handle)
6780     goto out;
6781
6782   impl->update_current_folder_handle = NULL;
6783   impl->reload_state = RELOAD_EMPTY;
6784
6785   set_busy_cursor (impl, FALSE);
6786
6787   if (cancelled)
6788     goto out;
6789
6790   if (error)
6791     {
6792       GtkFilePath *parent_path;
6793
6794       if (!data->original_path)
6795         {
6796           data->original_path = gtk_file_path_copy (data->path);
6797           data->original_error = g_error_copy (error);
6798         }
6799
6800       /* get parent path and try to change the folder to that */
6801       if (gtk_file_system_get_parent (impl->file_system, data->path, &parent_path, NULL) &&
6802           parent_path != NULL)
6803         {
6804           gtk_file_path_free (data->path);
6805           data->path = parent_path;
6806
6807           g_object_unref (handle);
6808
6809           /* restart the update current folder operation */
6810           impl->reload_state = RELOAD_HAS_FOLDER;
6811
6812           impl->update_current_folder_handle =
6813             gtk_file_system_get_info (impl->file_system, data->path,
6814                                       GTK_FILE_INFO_IS_FOLDER,
6815                                       update_current_folder_get_info_cb,
6816                                       data);
6817
6818           set_busy_cursor (impl, TRUE);
6819
6820           return;
6821         }
6822       else
6823         {
6824           /* error and bail out */
6825           error_changing_folder_dialog (impl, data->original_path, data->original_error);
6826
6827           gtk_file_path_free (data->original_path);
6828
6829           goto out;
6830         }
6831     }
6832
6833   if (data->original_path)
6834     {
6835       error_changing_folder_dialog (impl, data->original_path, data->original_error);
6836
6837       gtk_file_path_free (data->original_path);
6838     }
6839
6840   if (!gtk_file_info_get_is_folder (info))
6841     goto out;
6842
6843   if (!_gtk_path_bar_set_path (GTK_PATH_BAR (impl->browse_path_bar), data->path, data->keep_trail, NULL))
6844     goto out;
6845
6846   if (impl->current_folder != data->path)
6847     {
6848       if (impl->current_folder)
6849         gtk_file_path_free (impl->current_folder);
6850
6851       impl->current_folder = gtk_file_path_copy (data->path);
6852
6853       impl->reload_state = RELOAD_HAS_FOLDER;
6854     }
6855
6856   /* Update the widgets that may trigger a folder change themselves.  */
6857
6858   if (!impl->changing_folder)
6859     {
6860       impl->changing_folder = TRUE;
6861
6862       shortcuts_update_current_folder (impl);
6863
6864       impl->changing_folder = FALSE;
6865     }
6866
6867   /* Set the folder on the save entry */
6868
6869   if (impl->location_entry)
6870     {
6871       _gtk_file_chooser_entry_set_base_folder (GTK_FILE_CHOOSER_ENTRY (impl->location_entry),
6872                                                impl->current_folder);
6873
6874       if (data->clear_entry)
6875         _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), "");
6876     }
6877
6878   /* Create a new list model.  This is slightly evil; we store the result value
6879    * but perform more actions rather than returning immediately even if it
6880    * generates an error.
6881    */
6882   set_list_model (impl, NULL);
6883
6884   /* Refresh controls */
6885
6886   shortcuts_find_current_folder (impl);
6887
6888   g_signal_emit_by_name (impl, "current-folder-changed", 0);
6889
6890   check_preview_change (impl);
6891   bookmarks_check_add_sensitivity (impl);
6892
6893   g_signal_emit_by_name (impl, "selection-changed", 0);
6894
6895 out:
6896   gtk_file_path_free (data->path);
6897   g_free (data);
6898
6899   g_object_unref (handle);
6900 }
6901
6902 static gboolean
6903 gtk_file_chooser_default_update_current_folder (GtkFileChooser    *chooser,
6904                                                 const GtkFilePath *path,
6905                                                 gboolean           keep_trail,
6906                                                 gboolean           clear_entry,
6907                                                 GError           **error)
6908 {
6909   GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
6910   struct UpdateCurrentFolderData *data;
6911
6912   profile_start ("start", (char *) path);
6913
6914   switch (impl->operation_mode)
6915     {
6916     case OPERATION_MODE_SEARCH:
6917       search_switch_to_browse_mode (impl);
6918       break;
6919     case OPERATION_MODE_RECENT:
6920       recent_switch_to_browse_mode (impl);
6921       break;
6922     case OPERATION_MODE_BROWSE:
6923       break;
6924     }
6925
6926   g_assert (path != NULL);
6927
6928   if (impl->local_only &&
6929       !gtk_file_system_path_is_local (impl->file_system, path))
6930     {
6931       g_set_error (error,
6932                    GTK_FILE_CHOOSER_ERROR,
6933                    GTK_FILE_CHOOSER_ERROR_BAD_FILENAME,
6934                    _("Cannot change to folder because it is not local"));
6935
6936       profile_end ("end - not local", (char *) path);
6937       return FALSE;
6938     }
6939
6940   if (impl->update_current_folder_handle)
6941     gtk_file_system_cancel_operation (impl->update_current_folder_handle);
6942
6943   /* Test validity of path here.  */
6944   data = g_new0 (struct UpdateCurrentFolderData, 1);
6945   data->impl = impl;
6946   data->path = gtk_file_path_copy (path);
6947   data->keep_trail = keep_trail;
6948   data->clear_entry = clear_entry;
6949
6950   impl->reload_state = RELOAD_HAS_FOLDER;
6951
6952   impl->update_current_folder_handle =
6953     gtk_file_system_get_info (impl->file_system, path, GTK_FILE_INFO_IS_FOLDER,
6954                               update_current_folder_get_info_cb,
6955                               data);
6956
6957   set_busy_cursor (impl, TRUE);
6958
6959   profile_end ("end", NULL);
6960   return TRUE;
6961 }
6962
6963 static GtkFilePath *
6964 gtk_file_chooser_default_get_current_folder (GtkFileChooser *chooser)
6965 {
6966   GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
6967
6968   if (impl->operation_mode == OPERATION_MODE_SEARCH ||
6969       impl->operation_mode == OPERATION_MODE_RECENT)
6970     return NULL;
6971  
6972   if (impl->reload_state == RELOAD_EMPTY)
6973     {
6974       char *current_working_dir;
6975       GtkFilePath *path;
6976
6977       /* We are unmapped, or we had an error while loading the last folder.  We'll return
6978        * the $cwd since once we get (re)mapped, we'll load $cwd anyway unless the caller
6979        * explicitly calls set_current_folder() on us.
6980        */
6981       current_working_dir = g_get_current_dir ();
6982       path = gtk_file_system_filename_to_path (impl->file_system, current_working_dir);
6983       g_free (current_working_dir);
6984       return path;
6985     }
6986
6987   return gtk_file_path_copy (impl->current_folder);
6988 }
6989
6990 static void
6991 gtk_file_chooser_default_set_current_name (GtkFileChooser *chooser,
6992                                            const gchar    *name)
6993 {
6994   GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
6995
6996   g_return_if_fail (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE ||
6997                     impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER);
6998
6999   pending_select_paths_free (impl);
7000   _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), name);
7001 }
7002
7003 static void
7004 select_func (GtkFileSystemModel *model,
7005              GtkTreePath        *path,
7006              GtkTreeIter        *iter,
7007              gpointer            user_data)
7008 {
7009   GtkFileChooserDefault *impl = user_data;
7010   GtkTreeSelection *selection;
7011   GtkTreeIter sorted_iter;
7012
7013   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
7014
7015   gtk_tree_model_sort_convert_child_iter_to_iter (impl->sort_model, &sorted_iter, iter);
7016   gtk_tree_selection_select_iter (selection, &sorted_iter);
7017 }
7018
7019 static gboolean
7020 gtk_file_chooser_default_select_path (GtkFileChooser    *chooser,
7021                                       const GtkFilePath *path,
7022                                       GError           **error)
7023 {
7024   GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
7025   GtkFilePath *parent_path;
7026   gboolean same_path;
7027
7028   if (!gtk_file_system_get_parent (impl->file_system, path, &parent_path, error))
7029     return FALSE;
7030
7031   if (!parent_path)
7032    return _gtk_file_chooser_set_current_folder_path (chooser, path, error);
7033
7034   if (impl->operation_mode == OPERATION_MODE_SEARCH ||
7035       impl->operation_mode == OPERATION_MODE_RECENT ||
7036       impl->load_state == LOAD_EMPTY)
7037     {
7038       same_path = FALSE;
7039     }
7040   else
7041     {
7042       g_assert (impl->current_folder != NULL);
7043
7044       same_path = gtk_file_path_compare (parent_path, impl->current_folder) == 0;
7045     }
7046
7047   if (same_path && impl->load_state == LOAD_FINISHED)
7048     {
7049       gboolean result;
7050       GSList paths;
7051
7052       paths.data = (gpointer) path;
7053       paths.next = NULL;
7054
7055       result = show_and_select_paths (impl, parent_path, &paths, error);
7056       gtk_file_path_free (parent_path);
7057       return result;
7058     }
7059
7060   pending_select_paths_add (impl, path);
7061
7062   if (!same_path)
7063     {
7064       gboolean result;
7065
7066       result = _gtk_file_chooser_set_current_folder_path (chooser, parent_path, error);
7067       gtk_file_path_free (parent_path);
7068       return result;
7069     }
7070
7071   gtk_file_path_free (parent_path);
7072   return TRUE;
7073 }
7074
7075 static void
7076 unselect_func (GtkFileSystemModel *model,
7077                GtkTreePath        *path,
7078                GtkTreeIter        *iter,
7079                gpointer            user_data)
7080 {
7081   GtkFileChooserDefault *impl = user_data;
7082   GtkTreeView *tree_view = GTK_TREE_VIEW (impl->browse_files_tree_view);
7083   GtkTreePath *sorted_path;
7084
7085   sorted_path = gtk_tree_model_sort_convert_child_path_to_path (impl->sort_model,
7086                                                                 path);
7087   gtk_tree_selection_unselect_path (gtk_tree_view_get_selection (tree_view),
7088                                     sorted_path);
7089   gtk_tree_path_free (sorted_path);
7090 }
7091
7092 static void
7093 gtk_file_chooser_default_unselect_path (GtkFileChooser    *chooser,
7094                                         const GtkFilePath *path)
7095 {
7096   GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
7097
7098   if (!impl->browse_files_model)
7099     return;
7100
7101   _gtk_file_system_model_path_do (impl->browse_files_model, path,
7102                                   unselect_func, impl);
7103 }
7104
7105 static gboolean
7106 maybe_select (GtkTreeModel *model, 
7107               GtkTreePath  *path, 
7108               GtkTreeIter  *iter, 
7109               gpointer     data)
7110 {
7111   GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (data);
7112   GtkTreeSelection *selection;
7113   const GtkFileInfo *info;
7114   gboolean is_folder;
7115   
7116   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
7117   
7118   info = get_list_file_info (impl, iter);
7119   is_folder = gtk_file_info_get_is_folder (info);
7120
7121   if ((is_folder && impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER) ||
7122       (!is_folder && impl->action == GTK_FILE_CHOOSER_ACTION_OPEN))
7123     gtk_tree_selection_select_iter (selection, iter);
7124   else
7125     gtk_tree_selection_unselect_iter (selection, iter);
7126     
7127   return FALSE;
7128 }
7129
7130 static void
7131 gtk_file_chooser_default_select_all (GtkFileChooser *chooser)
7132 {
7133   GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
7134
7135   if (impl->operation_mode == OPERATION_MODE_SEARCH ||
7136       impl->operation_mode == OPERATION_MODE_RECENT)
7137     {
7138       GtkTreeSelection *selection;
7139       
7140       selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
7141       gtk_tree_selection_select_all (selection);
7142       return;
7143     }
7144
7145   if (impl->select_multiple)
7146     gtk_tree_model_foreach (GTK_TREE_MODEL (impl->sort_model), 
7147                             maybe_select, impl);
7148 }
7149
7150 static void
7151 gtk_file_chooser_default_unselect_all (GtkFileChooser *chooser)
7152 {
7153   GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
7154   GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
7155
7156   gtk_tree_selection_unselect_all (selection);
7157   pending_select_paths_free (impl);
7158 }
7159
7160 /* Checks whether the filename entry for the Save modes contains a well-formed filename.
7161  *
7162  * is_well_formed_ret - whether what the user typed passes gkt_file_system_make_path()
7163  *
7164  * is_empty_ret - whether the file entry is totally empty
7165  *
7166  * is_file_part_empty_ret - whether the file part is empty (will be if user types "foobar/", and
7167  *                          the path will be "$cwd/foobar")
7168  */
7169 static void
7170 check_save_entry (GtkFileChooserDefault *impl,
7171                   GtkFilePath          **path_ret,
7172                   gboolean              *is_well_formed_ret,
7173                   gboolean              *is_empty_ret,
7174                   gboolean              *is_file_part_empty_ret,
7175                   gboolean              *is_folder)
7176 {
7177   GtkFileChooserEntry *chooser_entry;
7178   const GtkFilePath *current_folder;
7179   const char *file_part;
7180   GtkFilePath *path;
7181   GError *error;
7182
7183   g_assert (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
7184             || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER
7185             || ((impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
7186                  || impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
7187                 && impl->location_mode == LOCATION_MODE_FILENAME_ENTRY));
7188
7189   chooser_entry = GTK_FILE_CHOOSER_ENTRY (impl->location_entry);
7190
7191   if (strlen (gtk_entry_get_text (GTK_ENTRY (chooser_entry))) == 0)
7192     {
7193       *path_ret = NULL;
7194       *is_well_formed_ret = TRUE;
7195       *is_empty_ret = TRUE;
7196       *is_file_part_empty_ret = TRUE;
7197       *is_folder = FALSE;
7198
7199       return;
7200     }
7201
7202   *is_empty_ret = FALSE;
7203
7204   current_folder = _gtk_file_chooser_entry_get_current_folder (chooser_entry);
7205   if (!current_folder)
7206     {
7207       *path_ret = NULL;
7208       *is_well_formed_ret = FALSE;
7209       *is_file_part_empty_ret = FALSE;
7210       *is_folder = FALSE;
7211
7212       return;
7213     }
7214
7215   file_part = _gtk_file_chooser_entry_get_file_part (chooser_entry);
7216
7217   if (!file_part || file_part[0] == '\0')
7218     {
7219       *path_ret = gtk_file_path_copy (current_folder);
7220       *is_well_formed_ret = TRUE;
7221       *is_file_part_empty_ret = TRUE;
7222       *is_folder = TRUE;
7223
7224       return;
7225     }
7226
7227   *is_file_part_empty_ret = FALSE;
7228
7229   error = NULL;
7230   path = gtk_file_system_make_path (impl->file_system, current_folder, file_part, &error);
7231
7232   if (!path)
7233     {
7234       error_building_filename_dialog (impl, current_folder, file_part, error);
7235       *path_ret = NULL;
7236       *is_well_formed_ret = FALSE;
7237       *is_folder = FALSE;
7238
7239       return;
7240     }
7241
7242   *path_ret = path;
7243   *is_well_formed_ret = TRUE;
7244   *is_folder = _gtk_file_chooser_entry_get_is_folder (chooser_entry, path);
7245 }
7246
7247 struct get_paths_closure {
7248   GtkFileChooserDefault *impl;
7249   GSList *result;
7250   GtkFilePath *path_from_entry;
7251 };
7252
7253 static void
7254 get_paths_foreach (GtkTreeModel *model,
7255                    GtkTreePath  *path,
7256                    GtkTreeIter  *iter,
7257                    gpointer      data)
7258 {
7259   struct get_paths_closure *info;
7260   const GtkFilePath *file_path;
7261   GtkFileSystemModel *fs_model;
7262   GtkTreeIter sel_iter;
7263
7264   info = data;
7265   fs_model = info->impl->browse_files_model;
7266   gtk_tree_model_sort_convert_iter_to_child_iter (info->impl->sort_model, &sel_iter, iter);
7267
7268   file_path = _gtk_file_system_model_get_path (fs_model, &sel_iter);
7269   if (!file_path)
7270     return; /* We are on the editable row */
7271
7272   if (!info->path_from_entry
7273       || gtk_file_path_compare (info->path_from_entry, file_path) != 0)
7274     info->result = g_slist_prepend (info->result, gtk_file_path_copy (file_path));
7275 }
7276
7277 static GSList *
7278 gtk_file_chooser_default_get_paths (GtkFileChooser *chooser)
7279 {
7280   GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
7281   struct get_paths_closure info;
7282   GtkWindow *toplevel;
7283   GtkWidget *current_focus;
7284   gboolean file_list_seen;
7285
7286   if (impl->operation_mode == OPERATION_MODE_SEARCH)
7287     return search_get_selected_paths (impl);
7288
7289   if (impl->operation_mode == OPERATION_MODE_RECENT)
7290     return recent_get_selected_paths (impl);
7291
7292   info.impl = impl;
7293   info.result = NULL;
7294   info.path_from_entry = NULL;
7295
7296   toplevel = get_toplevel (GTK_WIDGET (impl));
7297   if (toplevel)
7298     current_focus = gtk_window_get_focus (toplevel);
7299   else
7300     current_focus = NULL;
7301
7302   file_list_seen = FALSE;
7303   if (current_focus == impl->browse_files_tree_view)
7304     {
7305       GtkTreeSelection *selection;
7306
7307     file_list:
7308
7309       file_list_seen = TRUE;
7310       selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
7311       gtk_tree_selection_selected_foreach (selection, get_paths_foreach, &info);
7312
7313       /* If there is no selection in the file list, we probably have this situation:
7314        *
7315        * 1. The user typed a filename in the SAVE filename entry ("foo.txt").
7316        * 2. He then double-clicked on a folder ("bar") in the file list
7317        *
7318        * So we want the selection to be "bar/foo.txt".  Jump to the case for the
7319        * filename entry to see if that is the case.
7320        */
7321       if (info.result == NULL && impl->location_entry)
7322         goto file_entry;
7323     }
7324   else if (impl->location_entry && current_focus == impl->location_entry)
7325     {
7326       gboolean is_well_formed, is_empty, is_file_part_empty, is_folder;
7327
7328     file_entry:
7329
7330       check_save_entry (impl, &info.path_from_entry, &is_well_formed, &is_empty, &is_file_part_empty, &is_folder);
7331
7332       if (is_empty)
7333         goto out;
7334
7335       if (!is_well_formed)
7336         return NULL;
7337
7338       if (is_file_part_empty && impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
7339         {
7340           gtk_file_path_free (info.path_from_entry);
7341           return NULL;
7342         }
7343
7344       if (info.path_from_entry)
7345         info.result = g_slist_prepend (info.result, info.path_from_entry);
7346       else if (!file_list_seen) 
7347         goto file_list;
7348       else
7349         return NULL;
7350     }
7351   else if (impl->toplevel_last_focus_widget == impl->browse_files_tree_view)
7352     goto file_list;
7353   else if (impl->location_entry && impl->toplevel_last_focus_widget == impl->location_entry)
7354     goto file_entry;
7355   else
7356     {
7357       /* The focus is on a dialog's action area button or something else */
7358       if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE ||
7359           impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
7360         goto file_entry;
7361       else
7362         goto file_list; 
7363     }
7364
7365  out:
7366
7367   /* If there's no folder selected, and we're in SELECT_FOLDER mode, then we
7368    * fall back to the current directory */
7369   if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER &&
7370       info.result == NULL)
7371     {
7372       info.result = g_slist_prepend (info.result, _gtk_file_chooser_get_current_folder_path (chooser));
7373     }
7374
7375   return g_slist_reverse (info.result);
7376 }
7377
7378 static GtkFilePath *
7379 gtk_file_chooser_default_get_preview_path (GtkFileChooser *chooser)
7380 {
7381   GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
7382
7383   if (impl->preview_path)
7384     return gtk_file_path_copy (impl->preview_path);
7385   else
7386     return NULL;
7387 }
7388
7389 static GtkFileSystem *
7390 gtk_file_chooser_default_get_file_system (GtkFileChooser *chooser)
7391 {
7392   GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
7393
7394   return impl->file_system;
7395 }
7396
7397 /* Shows or hides the filter widgets */
7398 static void
7399 show_filters (GtkFileChooserDefault *impl,
7400               gboolean               show)
7401 {
7402   if (show)
7403     gtk_widget_show (impl->filter_combo_hbox);
7404   else
7405     gtk_widget_hide (impl->filter_combo_hbox);
7406 }
7407
7408 static void
7409 gtk_file_chooser_default_add_filter (GtkFileChooser *chooser,
7410                                      GtkFileFilter  *filter)
7411 {
7412   GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
7413   const gchar *name;
7414
7415   if (g_slist_find (impl->filters, filter))
7416     {
7417       g_warning ("gtk_file_chooser_add_filter() called on filter already in list\n");
7418       return;
7419     }
7420
7421   g_object_ref_sink (filter);
7422   impl->filters = g_slist_append (impl->filters, filter);
7423
7424   name = gtk_file_filter_get_name (filter);
7425   if (!name)
7426     name = "Untitled filter";   /* Place-holder, doesn't need to be marked for translation */
7427
7428   gtk_combo_box_append_text (GTK_COMBO_BOX (impl->filter_combo), name);
7429
7430   if (!g_slist_find (impl->filters, impl->current_filter))
7431     set_current_filter (impl, filter);
7432
7433   show_filters (impl, TRUE);
7434 }
7435
7436 static void
7437 gtk_file_chooser_default_remove_filter (GtkFileChooser *chooser,
7438                                         GtkFileFilter  *filter)
7439 {
7440   GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
7441   GtkTreeModel *model;
7442   GtkTreeIter iter;
7443   gint filter_index;
7444
7445   filter_index = g_slist_index (impl->filters, filter);
7446
7447   if (filter_index < 0)
7448     {
7449       g_warning ("gtk_file_chooser_remove_filter() called on filter not in list\n");
7450       return;
7451     }
7452
7453   impl->filters = g_slist_remove (impl->filters, filter);
7454
7455   if (filter == impl->current_filter)
7456     {
7457       if (impl->filters)
7458         set_current_filter (impl, impl->filters->data);
7459       else
7460         set_current_filter (impl, NULL);
7461     }
7462
7463   /* Remove row from the combo box */
7464   model = gtk_combo_box_get_model (GTK_COMBO_BOX (impl->filter_combo));
7465   if (!gtk_tree_model_iter_nth_child  (model, &iter, NULL, filter_index))
7466     g_assert_not_reached ();
7467
7468   gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
7469
7470   g_object_unref (filter);
7471
7472   if (!impl->filters)
7473     show_filters (impl, FALSE);
7474 }
7475
7476 static GSList *
7477 gtk_file_chooser_default_list_filters (GtkFileChooser *chooser)
7478 {
7479   GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
7480
7481   return g_slist_copy (impl->filters);
7482 }
7483
7484 /* Returns the position in the shortcuts tree where the nth specified shortcut would appear */
7485 static int
7486 shortcuts_get_pos_for_shortcut_folder (GtkFileChooserDefault *impl,
7487                                        int                    pos)
7488 {
7489   return pos + shortcuts_get_index (impl, SHORTCUTS_SHORTCUTS);
7490 }
7491
7492 struct AddShortcutData
7493 {
7494   GtkFileChooserDefault *impl;
7495   GtkFilePath *path;
7496 };
7497
7498 static void
7499 add_shortcut_get_info_cb (GtkFileSystemHandle *handle,
7500                           const GtkFileInfo   *info,
7501                           const GError        *error,
7502                           gpointer             user_data)
7503 {
7504   int pos;
7505   gboolean cancelled = handle->cancelled;
7506   struct AddShortcutData *data = user_data;
7507
7508   if (!g_slist_find (data->impl->loading_shortcuts, handle))
7509     goto out;
7510
7511   data->impl->loading_shortcuts = g_slist_remove (data->impl->loading_shortcuts, handle);
7512
7513   if (cancelled || error || !gtk_file_info_get_is_folder (info))
7514     goto out;
7515
7516   pos = shortcuts_get_pos_for_shortcut_folder (data->impl, data->impl->num_shortcuts);
7517
7518   shortcuts_insert_path (data->impl, pos, SHORTCUT_TYPE_PATH, NULL, data->path, NULL, FALSE, SHORTCUTS_SHORTCUTS);
7519
7520 out:
7521   g_object_unref (data->impl);
7522   gtk_file_path_free (data->path);
7523   g_free (data);
7524
7525   g_object_unref (handle);
7526 }
7527
7528 static gboolean
7529 gtk_file_chooser_default_add_shortcut_folder (GtkFileChooser    *chooser,
7530                                               const GtkFilePath *path,
7531                                               GError           **error)
7532 {
7533   GtkFileSystemHandle *handle;
7534   GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
7535   struct AddShortcutData *data;
7536   GSList *l;
7537   int pos;
7538
7539   /* Avoid adding duplicates */
7540   pos = shortcut_find_position (impl, path);
7541   if (pos >= 0 && pos < shortcuts_get_index (impl, SHORTCUTS_BOOKMARKS_SEPARATOR))
7542     {
7543       gchar *uri;
7544
7545       uri = gtk_file_system_path_to_uri (impl->file_system, path);
7546       /* translators, "Shortcut" means "Bookmark" here */
7547       g_set_error (error,
7548                    GTK_FILE_CHOOSER_ERROR,
7549                    GTK_FILE_CHOOSER_ERROR_ALREADY_EXISTS,
7550                    _("Shortcut %s already exists"),
7551                    uri);
7552       g_free (uri);
7553
7554       return FALSE;
7555     }
7556
7557   for (l = impl->loading_shortcuts; l; l = l->next)
7558     {
7559       GtkFileSystemHandle *h = l->data;
7560       GtkFilePath *p;
7561
7562       p = g_object_get_data (G_OBJECT (h), "add-shortcut-path-key");
7563       if (p && !gtk_file_path_compare (path, p))
7564         {
7565           gchar *uri;
7566
7567           uri = gtk_file_system_path_to_uri (impl->file_system, path);
7568           g_set_error (error,
7569                        GTK_FILE_CHOOSER_ERROR,
7570                        GTK_FILE_CHOOSER_ERROR_ALREADY_EXISTS,
7571                        _("Shortcut %s already exists"),
7572                        uri);
7573           g_free (uri);
7574
7575           return FALSE;
7576         }
7577     }
7578
7579   data = g_new0 (struct AddShortcutData, 1);
7580   data->impl = g_object_ref (impl);
7581   data->path = gtk_file_path_copy (path);
7582
7583   handle = gtk_file_system_get_info (impl->file_system, path,
7584                                      GTK_FILE_INFO_IS_FOLDER,
7585                                      add_shortcut_get_info_cb, data);
7586
7587   if (!handle)
7588     return FALSE;
7589
7590   impl->loading_shortcuts = g_slist_append (impl->loading_shortcuts, handle);
7591   g_object_set_data (G_OBJECT (handle), "add-shortcut-path-key", data->path);
7592
7593   return TRUE;
7594 }
7595
7596 static gboolean
7597 gtk_file_chooser_default_remove_shortcut_folder (GtkFileChooser    *chooser,
7598                                                  const GtkFilePath *path,
7599                                                  GError           **error)
7600 {
7601   GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
7602   int pos;
7603   GtkTreeIter iter;
7604   GSList *l;
7605   char *uri;
7606   int i;
7607
7608   for (l = impl->loading_shortcuts; l; l = l->next)
7609     {
7610       GtkFileSystemHandle *h = l->data;
7611       GtkFilePath *p;
7612
7613       p = g_object_get_data (G_OBJECT (h), "add-shortcut-path-key");
7614       if (p && !gtk_file_path_compare (path, p))
7615         {
7616           impl->loading_shortcuts = g_slist_remove (impl->loading_shortcuts, h);
7617           gtk_file_system_cancel_operation (h);
7618           return TRUE;
7619         }
7620     }
7621
7622   if (impl->num_shortcuts == 0)
7623     goto out;
7624
7625   pos = shortcuts_get_pos_for_shortcut_folder (impl, 0);
7626   if (!gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (impl->shortcuts_model), &iter, NULL, pos))
7627     g_assert_not_reached ();
7628
7629   for (i = 0; i < impl->num_shortcuts; i++)
7630     {
7631       gpointer col_data;
7632       ShortcutType shortcut_type;
7633       GtkFilePath *shortcut;
7634
7635       gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter,
7636                           SHORTCUTS_COL_DATA, &col_data,
7637                           SHORTCUTS_COL_TYPE, &shortcut_type,
7638                           -1);
7639       g_assert (col_data != NULL);
7640       g_assert (shortcut_type == SHORTCUT_TYPE_PATH);
7641
7642       shortcut = col_data;
7643       if (gtk_file_path_compare (shortcut, path) == 0)
7644         {
7645           shortcuts_remove_rows (impl, pos + i, 1);
7646           impl->num_shortcuts--;
7647           return TRUE;
7648         }
7649
7650       if (!gtk_tree_model_iter_next (GTK_TREE_MODEL (impl->shortcuts_model), &iter))
7651         g_assert_not_reached ();
7652     }
7653
7654  out:
7655
7656   uri = gtk_file_system_path_to_uri (impl->file_system, path);
7657   /* translators, "Shortcut" means "Bookmark" here */
7658   g_set_error (error,
7659                GTK_FILE_CHOOSER_ERROR,
7660                GTK_FILE_CHOOSER_ERROR_NONEXISTENT,
7661                _("Shortcut %s does not exist"),
7662                uri);
7663   g_free (uri);
7664
7665   return FALSE;
7666 }
7667
7668 static GSList *
7669 gtk_file_chooser_default_list_shortcut_folders (GtkFileChooser *chooser)
7670 {
7671   GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
7672   int pos;
7673   GtkTreeIter iter;
7674   int i;
7675   GSList *list;
7676
7677   if (impl->num_shortcuts == 0)
7678     return NULL;
7679
7680   pos = shortcuts_get_pos_for_shortcut_folder (impl, 0);
7681   if (!gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (impl->shortcuts_model), &iter, NULL, pos))
7682     g_assert_not_reached ();
7683
7684   list = NULL;
7685
7686   for (i = 0; i < impl->num_shortcuts; i++)
7687     {
7688       gpointer col_data;
7689       ShortcutType shortcut_type;
7690       GtkFilePath *shortcut;
7691
7692       gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter,
7693                           SHORTCUTS_COL_DATA, &col_data,
7694                           SHORTCUTS_COL_TYPE, &shortcut_type,
7695                           -1);
7696       g_assert (col_data != NULL);
7697       g_assert (shortcut_type == SHORTCUT_TYPE_PATH);
7698
7699       shortcut = col_data;
7700       list = g_slist_prepend (list, gtk_file_path_copy (shortcut));
7701
7702       if (i != impl->num_shortcuts - 1)
7703         {
7704           if (!gtk_tree_model_iter_next (GTK_TREE_MODEL (impl->shortcuts_model), &iter))
7705             g_assert_not_reached ();
7706         }
7707     }
7708
7709   return g_slist_reverse (list);
7710 }
7711
7712 /* Guesses a size based upon font sizes */
7713 static void
7714 find_good_size_from_style (GtkWidget *widget,
7715                            gint      *width,
7716                            gint      *height)
7717 {
7718   GtkFileChooserDefault *impl;
7719   gint default_width, default_height;
7720   int font_size;
7721   GtkRequisition req;
7722   GdkScreen *screen;
7723   double resolution;
7724
7725   g_assert (widget->style != NULL);
7726   impl = GTK_FILE_CHOOSER_DEFAULT (widget);
7727
7728   screen = gtk_widget_get_screen (widget);
7729   if (screen)
7730     {
7731       resolution = gdk_screen_get_resolution (screen);
7732       if (resolution < 0.0) /* will be -1 if the resolution is not defined in the GdkScreen */
7733         resolution = 96.0;
7734     }
7735   else
7736     resolution = 96.0; /* wheeee */
7737
7738   font_size = pango_font_description_get_size (widget->style->font_desc);
7739   font_size = PANGO_PIXELS (font_size) * resolution / 72.0;
7740
7741   default_width = font_size * NUM_CHARS;
7742   default_height = font_size * NUM_LINES;
7743
7744   if (impl->preview_widget_active && impl->preview_widget)
7745     {
7746       gtk_widget_size_request (impl->preview_box, &req);
7747       default_width += PREVIEW_HBOX_SPACING + req.width;
7748     }
7749
7750   if (impl->extra_widget)
7751     {
7752       gtk_widget_size_request (impl->extra_align, &req);
7753       default_height += GTK_BOX (widget)->spacing + req.height;
7754     }
7755
7756   gtk_widget_size_request (widget, &req);
7757   default_width = MAX (default_width, req.width);
7758   default_height = MAX (default_height, req.height);
7759
7760   *width = default_width;
7761   *height = default_height;
7762 }
7763
7764 static void
7765 gtk_file_chooser_default_get_default_size (GtkFileChooserEmbed *chooser_embed,
7766                                            gint                *default_width,
7767                                            gint                *default_height)
7768 {
7769   GtkFileChooserDefault *impl;
7770
7771   impl = GTK_FILE_CHOOSER_DEFAULT (chooser_embed);
7772   find_good_size_from_style (GTK_WIDGET (chooser_embed), default_width, default_height);
7773 }
7774
7775 static void
7776 gtk_file_chooser_default_get_resizable_hints (GtkFileChooserEmbed *chooser_embed,
7777                                               gboolean            *resize_horizontally,
7778                                               gboolean            *resize_vertically)
7779 {
7780   GtkFileChooserDefault *impl;
7781
7782   g_return_if_fail (resize_horizontally != NULL);
7783   g_return_if_fail (resize_vertically != NULL);
7784
7785   impl = GTK_FILE_CHOOSER_DEFAULT (chooser_embed);
7786
7787   *resize_horizontally = TRUE;
7788   *resize_vertically = TRUE;
7789
7790   if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE ||
7791       impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
7792     {
7793       if (! gtk_expander_get_expanded (GTK_EXPANDER (impl->save_expander)))
7794         {
7795           *resize_horizontally = FALSE;
7796           *resize_vertically = FALSE;
7797         }
7798     }
7799 }
7800
7801 struct switch_folder_closure {
7802   GtkFileChooserDefault *impl;
7803   const GtkFilePath *path;
7804   int num_selected;
7805 };
7806
7807 /* Used from gtk_tree_selection_selected_foreach() in switch_to_selected_folder() */
7808 static void
7809 switch_folder_foreach_cb (GtkTreeModel      *model,
7810                           GtkTreePath       *path,
7811                           GtkTreeIter       *iter,
7812                           gpointer           data)
7813 {
7814   struct switch_folder_closure *closure;
7815   GtkTreeIter child_iter;
7816
7817   closure = data;
7818
7819   gtk_tree_model_sort_convert_iter_to_child_iter (closure->impl->sort_model, &child_iter, iter);
7820
7821   closure->path = _gtk_file_system_model_get_path (closure->impl->browse_files_model, &child_iter);
7822   closure->num_selected++;
7823 }
7824
7825 /* Changes to the selected folder in the list view */
7826 static void
7827 switch_to_selected_folder (GtkFileChooserDefault *impl)
7828 {
7829   GtkTreeSelection *selection;
7830   struct switch_folder_closure closure;
7831
7832   /* We do this with foreach() rather than get_selected() as we may be in
7833    * multiple selection mode
7834    */
7835
7836   closure.impl = impl;
7837   closure.path = NULL;
7838   closure.num_selected = 0;
7839
7840   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
7841   gtk_tree_selection_selected_foreach (selection, switch_folder_foreach_cb, &closure);
7842
7843   g_assert (closure.path && closure.num_selected == 1);
7844
7845   change_folder_and_display_error (impl, closure.path, FALSE);
7846 }
7847
7848 /* Gets the GtkFileInfo for the selected row in the file list; assumes single
7849  * selection mode.
7850  */
7851 static const GtkFileInfo *
7852 get_selected_file_info_from_file_list (GtkFileChooserDefault *impl,
7853                                        gboolean              *had_selection)
7854 {
7855   GtkTreeSelection *selection;
7856   GtkTreeIter iter, child_iter;
7857   const GtkFileInfo *info;
7858
7859   g_assert (!impl->select_multiple);
7860   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
7861   if (!gtk_tree_selection_get_selected (selection, NULL, &iter))
7862     {
7863       *had_selection = FALSE;
7864       return NULL;
7865     }
7866
7867   *had_selection = TRUE;
7868
7869   gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model,
7870                                                   &child_iter,
7871                                                   &iter);
7872
7873   info = _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
7874   return info;
7875 }
7876
7877 /* Gets the display name of the selected file in the file list; assumes single
7878  * selection mode and that something is selected.
7879  */
7880 static const gchar *
7881 get_display_name_from_file_list (GtkFileChooserDefault *impl)
7882 {
7883   const GtkFileInfo *info;
7884   gboolean had_selection;
7885
7886   info = get_selected_file_info_from_file_list (impl, &had_selection);
7887   g_assert (had_selection);
7888   g_assert (info != NULL);
7889
7890   return gtk_file_info_get_display_name (info);
7891 }
7892
7893 static void
7894 add_custom_button_to_dialog (GtkDialog   *dialog,
7895                              const gchar *mnemonic_label,
7896                              const gchar *stock_id,
7897                              gint         response_id)
7898 {
7899   GtkWidget *button;
7900
7901   button = gtk_button_new_with_mnemonic (mnemonic_label);
7902   GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
7903   gtk_button_set_image (GTK_BUTTON (button),
7904                         gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_BUTTON));
7905   gtk_widget_show (button);
7906
7907   gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button, response_id);
7908 }
7909
7910 /* Presents an overwrite confirmation dialog; returns whether we should accept
7911  * the filename.
7912  */
7913 static gboolean
7914 confirm_dialog_should_accept_filename (GtkFileChooserDefault *impl,
7915                                        const gchar           *file_part,
7916                                        const gchar           *folder_display_name)
7917 {
7918   GtkWindow *toplevel;
7919   GtkWidget *dialog;
7920   int response;
7921
7922   toplevel = get_toplevel (GTK_WIDGET (impl));
7923
7924   dialog = gtk_message_dialog_new (toplevel,
7925                                    GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
7926                                    GTK_MESSAGE_QUESTION,
7927                                    GTK_BUTTONS_NONE,
7928                                    _("A file named \"%s\" already exists.  Do you want to replace it?"),
7929                                    file_part);
7930   gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
7931                                             _("The file already exists in \"%s\".  Replacing it will "
7932                                               "overwrite its contents."),
7933                                             folder_display_name);
7934
7935   gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
7936   add_custom_button_to_dialog (GTK_DIALOG (dialog), _("_Replace"), GTK_STOCK_SAVE_AS, GTK_RESPONSE_ACCEPT);
7937   gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
7938   
7939   if (toplevel->group)
7940     gtk_window_group_add_window (toplevel->group, GTK_WINDOW (dialog));
7941
7942   response = gtk_dialog_run (GTK_DIALOG (dialog));
7943
7944   gtk_widget_destroy (dialog);
7945
7946   return (response == GTK_RESPONSE_ACCEPT);
7947 }
7948
7949 struct GetDisplayNameData
7950 {
7951   GtkFileChooserDefault *impl;
7952   gchar *file_part;
7953 };
7954
7955 static void
7956 confirmation_confirm_get_info_cb (GtkFileSystemHandle *handle,
7957                                   const GtkFileInfo   *info,
7958                                   const GError        *error,
7959                                   gpointer             user_data)
7960 {
7961   gboolean cancelled = handle->cancelled;
7962   gboolean should_respond = FALSE;
7963   struct GetDisplayNameData *data = user_data;
7964
7965   if (handle != data->impl->should_respond_get_info_handle)
7966     goto out;
7967
7968   data->impl->should_respond_get_info_handle = NULL;
7969
7970   if (cancelled)
7971     goto out;
7972
7973   if (error)
7974     /* Huh?  Did the folder disappear?  Let the caller deal with it */
7975     should_respond = TRUE;
7976   else
7977     should_respond = confirm_dialog_should_accept_filename (data->impl, data->file_part, gtk_file_info_get_display_name (info));
7978
7979   set_busy_cursor (data->impl, FALSE);
7980   if (should_respond)
7981     g_signal_emit_by_name (data->impl, "response-requested");
7982
7983 out:
7984   g_object_unref (data->impl);
7985   g_free (data->file_part);
7986   g_free (data);
7987
7988   g_object_unref (handle);
7989 }
7990
7991 /* Does overwrite confirmation if appropriate, and returns whether the dialog
7992  * should respond.  Can get the file part from the file list or the save entry.
7993  */
7994 static gboolean
7995 should_respond_after_confirm_overwrite (GtkFileChooserDefault *impl,
7996                                         const gchar           *file_part,
7997                                         const GtkFilePath     *parent_path)
7998 {
7999   GtkFileChooserConfirmation conf;
8000
8001   if (!impl->do_overwrite_confirmation)
8002     return TRUE;
8003
8004   conf = GTK_FILE_CHOOSER_CONFIRMATION_CONFIRM;
8005
8006   g_signal_emit_by_name (impl, "confirm-overwrite", &conf);
8007
8008   switch (conf)
8009     {
8010     case GTK_FILE_CHOOSER_CONFIRMATION_CONFIRM:
8011       {
8012         struct GetDisplayNameData *data;
8013
8014         g_assert (file_part != NULL);
8015
8016         data = g_new0 (struct GetDisplayNameData, 1);
8017         data->impl = g_object_ref (impl);
8018         data->file_part = g_strdup (file_part);
8019
8020         if (impl->should_respond_get_info_handle)
8021           gtk_file_system_cancel_operation (impl->should_respond_get_info_handle);
8022
8023         impl->should_respond_get_info_handle =
8024           gtk_file_system_get_info (impl->file_system, parent_path,
8025                                     GTK_FILE_INFO_DISPLAY_NAME,
8026                                     confirmation_confirm_get_info_cb,
8027                                     data);
8028         set_busy_cursor (data->impl, TRUE);
8029         return FALSE;
8030       }
8031
8032     case GTK_FILE_CHOOSER_CONFIRMATION_ACCEPT_FILENAME:
8033       return TRUE;
8034
8035     case GTK_FILE_CHOOSER_CONFIRMATION_SELECT_AGAIN:
8036       return FALSE;
8037
8038     default:
8039       g_assert_not_reached ();
8040       return FALSE;
8041     }
8042 }
8043
8044 /* Gives the focus to the browse tree view only if it is visible */
8045 static void
8046 focus_browse_tree_view_if_possible (GtkFileChooserDefault *impl)
8047 {
8048   gboolean do_focus;
8049
8050   if ((impl->action == GTK_FILE_CHOOSER_ACTION_SAVE ||
8051        impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
8052       && !gtk_expander_get_expanded (GTK_EXPANDER (impl->save_expander)))
8053     do_focus = FALSE;
8054   else
8055     do_focus = TRUE;
8056
8057   if (do_focus)
8058     gtk_widget_grab_focus (impl->browse_files_tree_view);
8059 }
8060
8061 static void
8062 action_create_folder_cb (GtkFileSystemHandle *handle,
8063                          const GtkFilePath   *path,
8064                          const GError        *error,
8065                          gpointer             user_data)
8066 {
8067   gboolean cancelled = handle->cancelled;
8068   GtkFileChooserDefault *impl = user_data;
8069
8070   if (!g_slist_find (impl->pending_handles, handle))
8071     goto out;
8072
8073   impl->pending_handles = g_slist_remove (impl->pending_handles, handle);
8074
8075   set_busy_cursor (impl, FALSE);
8076
8077   if (cancelled)
8078     goto out;
8079
8080   if (error)
8081     error_creating_folder_dialog (impl, path, g_error_copy (error));
8082   else
8083     g_signal_emit_by_name (impl, "response-requested");
8084
8085 out:
8086   g_object_unref (impl);
8087   g_object_unref (handle);
8088 }
8089
8090 struct FileExistsData
8091 {
8092   GtkFileChooserDefault *impl;
8093   gboolean file_exists_and_is_not_folder;
8094   GtkFilePath *parent_path;
8095   GtkFilePath *path;
8096 };
8097
8098 static void
8099 save_entry_get_info_cb (GtkFileSystemHandle *handle,
8100                         const GtkFileInfo   *info,
8101                         const GError        *error,
8102                         gpointer             user_data)
8103 {
8104   gboolean parent_is_folder;
8105   gboolean cancelled = handle->cancelled;
8106   struct FileExistsData *data = user_data;
8107
8108   if (handle != data->impl->should_respond_get_info_handle)
8109     goto out;
8110
8111   data->impl->should_respond_get_info_handle = NULL;
8112
8113   set_busy_cursor (data->impl, FALSE);
8114
8115   if (cancelled)
8116     goto out;
8117
8118   if (!info)
8119     parent_is_folder = FALSE;
8120   else
8121     parent_is_folder = gtk_file_info_get_is_folder (info);
8122
8123   if (parent_is_folder)
8124     {
8125       if (data->impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
8126         {
8127           if (data->file_exists_and_is_not_folder)
8128             {
8129               gboolean retval;
8130               const char *file_part;
8131
8132               file_part = _gtk_file_chooser_entry_get_file_part (GTK_FILE_CHOOSER_ENTRY (data->impl->location_entry));
8133               retval = should_respond_after_confirm_overwrite (data->impl, file_part, data->parent_path);
8134
8135               if (retval)
8136                 g_signal_emit_by_name (data->impl, "response-requested");
8137             }
8138           else
8139             g_signal_emit_by_name (data->impl, "response-requested");
8140         }
8141       else /* GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER */
8142         {
8143           GtkFileSystemHandle *handle;
8144
8145           g_object_ref (data->impl);
8146           handle = gtk_file_system_create_folder (data->impl->file_system,
8147                                                   data->path,
8148                                                   action_create_folder_cb,
8149                                                   data->impl);
8150           data->impl->pending_handles = g_slist_append (data->impl->pending_handles, handle);
8151           set_busy_cursor (data->impl, TRUE);
8152         }
8153     }
8154   else
8155     {
8156       /* This will display an error, which is what we want */
8157       change_folder_and_display_error (data->impl, data->parent_path, FALSE);
8158     }
8159
8160 out:
8161   g_object_unref (data->impl);
8162   gtk_file_path_free (data->path);
8163   gtk_file_path_free (data->parent_path);
8164   g_free (data);
8165
8166   g_object_unref (handle);
8167 }
8168
8169 static void
8170 file_exists_get_info_cb (GtkFileSystemHandle *handle,
8171                          const GtkFileInfo   *info,
8172                          const GError        *error,
8173                          gpointer             user_data)
8174 {
8175   gboolean data_ownership_taken = FALSE;
8176   gboolean cancelled = handle->cancelled;
8177   gboolean file_exists_and_is_not_folder;
8178   struct FileExistsData *data = user_data;
8179
8180   if (handle != data->impl->file_exists_get_info_handle)
8181     goto out;
8182
8183   data->impl->file_exists_get_info_handle = NULL;
8184
8185   set_busy_cursor (data->impl, FALSE);
8186
8187   if (cancelled)
8188     goto out;
8189
8190   file_exists_and_is_not_folder = info && !gtk_file_info_get_is_folder (info);
8191
8192   if (data->impl->action == GTK_FILE_CHOOSER_ACTION_OPEN)
8193     /* user typed a filename; we are done */
8194     g_signal_emit_by_name (data->impl, "response-requested");
8195   else if (data->impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER
8196            && file_exists_and_is_not_folder)
8197     {
8198       /* Oops, the user typed the name of an existing path which is not
8199        * a folder
8200        */
8201       error_creating_folder_over_existing_file_dialog (data->impl, data->path,
8202                                                        g_error_copy (error));
8203     }
8204   else
8205     {
8206       /* check that everything up to the last component exists */
8207
8208       data->file_exists_and_is_not_folder = file_exists_and_is_not_folder;
8209       data_ownership_taken = TRUE;
8210
8211       if (data->impl->should_respond_get_info_handle)
8212         gtk_file_system_cancel_operation (data->impl->should_respond_get_info_handle);
8213
8214       data->impl->should_respond_get_info_handle =
8215         gtk_file_system_get_info (data->impl->file_system,
8216                                   data->parent_path,
8217                                   GTK_FILE_INFO_IS_FOLDER,
8218                                   save_entry_get_info_cb,
8219                                   data);
8220       set_busy_cursor (data->impl, TRUE);
8221     }
8222
8223 out:
8224   if (!data_ownership_taken)
8225     {
8226       g_object_unref (data->impl);
8227       gtk_file_path_free (data->path);
8228       gtk_file_path_free (data->parent_path);
8229       g_free (data);
8230     }
8231
8232   g_object_unref (handle);
8233 }
8234
8235 static void
8236 paste_text_received (GtkClipboard          *clipboard,
8237                      const gchar           *text,
8238                      GtkFileChooserDefault *impl)
8239 {
8240   GtkFilePath *path;
8241
8242   if (!text)
8243     return;
8244
8245   path = gtk_file_system_uri_to_path (impl->file_system, text);
8246   if (!path) 
8247     {
8248       if (!g_path_is_absolute (text)) 
8249         {
8250           location_popup_handler (impl, text);
8251           return;
8252         }
8253
8254       path = gtk_file_system_filename_to_path (impl->file_system, text);
8255       if (!path) 
8256         {
8257           location_popup_handler (impl, text);
8258           return;
8259         }
8260     }
8261
8262   if (!gtk_file_chooser_default_select_path (GTK_FILE_CHOOSER (impl), path, NULL))
8263     location_popup_handler (impl, text);
8264
8265   gtk_file_path_free (path);
8266 }
8267
8268 /* Handler for the "location-popup-on-paste" keybinding signal */
8269 static void
8270 location_popup_on_paste_handler (GtkFileChooserDefault *impl)
8271 {
8272   GtkClipboard *clipboard = gtk_widget_get_clipboard (GTK_WIDGET (impl),
8273                                                       GDK_SELECTION_CLIPBOARD);
8274   gtk_clipboard_request_text (clipboard,
8275                               (GtkClipboardTextReceivedFunc) paste_text_received,
8276                               impl);
8277 }
8278
8279
8280 /* Implementation for GtkFileChooserEmbed::should_respond() */
8281 static gboolean
8282 gtk_file_chooser_default_should_respond (GtkFileChooserEmbed *chooser_embed)
8283 {
8284   GtkFileChooserDefault *impl;
8285   GtkWidget *toplevel;
8286   GtkWidget *current_focus;
8287
8288   impl = GTK_FILE_CHOOSER_DEFAULT (chooser_embed);
8289
8290   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (impl));
8291   g_assert (GTK_IS_WINDOW (toplevel));
8292
8293   current_focus = gtk_window_get_focus (GTK_WINDOW (toplevel));
8294
8295   if (current_focus == impl->browse_files_tree_view)
8296     {
8297       /* The following array encodes what we do based on the impl->action and the
8298        * number of files selected.
8299        */
8300       typedef enum {
8301         NOOP,                   /* Do nothing (don't respond) */
8302         RESPOND,                /* Respond immediately */
8303         RESPOND_OR_SWITCH,      /* Respond immediately if the selected item is a file; switch to it if it is a folder */
8304         ALL_FILES,              /* Respond only if everything selected is a file */
8305         ALL_FOLDERS,            /* Respond only if everything selected is a folder */
8306         SAVE_ENTRY,             /* Go to the code for handling the save entry */
8307         NOT_REACHED             /* Sanity check */
8308       } ActionToTake;
8309       static const ActionToTake what_to_do[4][3] = {
8310         /*                                0 selected            1 selected              many selected */
8311         /* ACTION_OPEN */               { NOOP,                 RESPOND_OR_SWITCH,      ALL_FILES   },
8312         /* ACTION_SAVE */               { SAVE_ENTRY,           RESPOND_OR_SWITCH,      NOT_REACHED },
8313         /* ACTION_SELECT_FOLDER */      { RESPOND,              ALL_FOLDERS,            ALL_FOLDERS },
8314         /* ACTION_CREATE_FOLDER */      { SAVE_ENTRY,           ALL_FOLDERS,            NOT_REACHED }
8315       };
8316
8317       int num_selected;
8318       gboolean all_files, all_folders;
8319       int k;
8320       ActionToTake action;
8321
8322     file_list:
8323
8324       g_assert (impl->action >= GTK_FILE_CHOOSER_ACTION_OPEN && impl->action <= GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER);
8325
8326       if (impl->operation_mode == OPERATION_MODE_SEARCH)
8327         return search_should_respond (impl);
8328
8329       if (impl->operation_mode == OPERATION_MODE_RECENT)
8330         return recent_should_respond (impl);
8331
8332       selection_check (impl, &num_selected, &all_files, &all_folders);
8333
8334       if (num_selected > 2)
8335         k = 2;
8336       else
8337         k = num_selected;
8338
8339       action = what_to_do [impl->action] [k];
8340
8341       switch (action)
8342         {
8343         case NOOP:
8344           return FALSE;
8345
8346         case RESPOND:
8347           return TRUE;
8348
8349         case RESPOND_OR_SWITCH:
8350           g_assert (num_selected == 1);
8351
8352           if (all_folders)
8353             {
8354               switch_to_selected_folder (impl);
8355               return FALSE;
8356             }
8357           else if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
8358             return should_respond_after_confirm_overwrite (impl,
8359                                                            get_display_name_from_file_list (impl),
8360                                                            impl->current_folder);
8361           else
8362             return TRUE;
8363
8364         case ALL_FILES:
8365           return all_files;
8366
8367         case ALL_FOLDERS:
8368           return all_folders;
8369
8370         case SAVE_ENTRY:
8371           goto save_entry;
8372
8373         default:
8374           g_assert_not_reached ();
8375         }
8376     }
8377   else if ((impl->location_entry != NULL) && (current_focus == impl->location_entry))
8378     {
8379       GtkFilePath *path;
8380       gboolean is_well_formed, is_empty, is_file_part_empty;
8381       gboolean is_folder;
8382       gboolean retval;
8383       GtkFileChooserEntry *entry;
8384       GError *error;
8385
8386     save_entry:
8387
8388       g_assert (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
8389                 || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER
8390                 || ((impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
8391                      || impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
8392                     && impl->location_mode == LOCATION_MODE_FILENAME_ENTRY));
8393
8394       entry = GTK_FILE_CHOOSER_ENTRY (impl->location_entry);
8395       check_save_entry (impl, &path, &is_well_formed, &is_empty, &is_file_part_empty, &is_folder);
8396
8397       if (is_empty || !is_well_formed)
8398         return FALSE;
8399
8400       g_assert (path != NULL);
8401
8402       error = NULL;
8403       if (is_folder)
8404         {
8405           if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
8406               impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
8407             {
8408               change_folder_and_display_error (impl, path, TRUE);
8409               retval = FALSE;
8410             }
8411           else if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
8412                    impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
8413             {
8414               /* The folder already exists, so we do not need to create it.
8415                * Just respond to terminate the dialog.
8416                */
8417               retval = TRUE;
8418             }
8419           else
8420             {
8421               g_assert_not_reached ();
8422               retval = FALSE;
8423             }
8424         }
8425       else
8426         {
8427           struct FileExistsData *data;
8428
8429           /* We need to check whether path exists and is not a folder */
8430
8431           data = g_new0 (struct FileExistsData, 1);
8432           data->impl = g_object_ref (impl);
8433           data->path = gtk_file_path_copy (path);
8434           data->parent_path = gtk_file_path_copy (_gtk_file_chooser_entry_get_current_folder (entry));
8435
8436           if (impl->file_exists_get_info_handle)
8437             gtk_file_system_cancel_operation (impl->file_exists_get_info_handle);
8438
8439           impl->file_exists_get_info_handle =
8440             gtk_file_system_get_info (impl->file_system, path,
8441                                       GTK_FILE_INFO_IS_FOLDER,
8442                                       file_exists_get_info_cb,
8443                                       data);
8444
8445           set_busy_cursor (impl, TRUE);
8446           retval = FALSE;
8447
8448           if (error != NULL)
8449             g_error_free (error);
8450         }
8451
8452       gtk_file_path_free (path);
8453       return retval;
8454     }
8455   else if (impl->toplevel_last_focus_widget == impl->browse_shortcuts_tree_view)
8456     {
8457       /* The focus is on a dialog's action area button, *and* the widget that
8458        * was focused immediately before it is the shortcuts list.  Switch to the
8459        * selected shortcut and tell the caller not to respond.
8460        */
8461       GtkTreeIter iter;
8462
8463       if (shortcuts_get_selected (impl, &iter))
8464         {
8465           shortcuts_activate_iter (impl, &iter);
8466           
8467           focus_browse_tree_view_if_possible (impl);
8468         }
8469       else
8470         goto file_list;
8471
8472       return FALSE;
8473     }
8474   else if (impl->toplevel_last_focus_widget == impl->browse_files_tree_view)
8475     {
8476       /* The focus is on a dialog's action area button, *and* the widget that
8477        * was focused immediately before it is the file list.  
8478        */
8479       goto file_list;
8480     }
8481   else if (impl->operation_mode == OPERATION_MODE_SEARCH && impl->toplevel_last_focus_widget == impl->search_entry)
8482     {
8483       search_entry_activate_cb (GTK_ENTRY (impl->search_entry), impl);
8484       return FALSE;
8485     }
8486   else if (impl->location_entry && impl->toplevel_last_focus_widget == impl->location_entry)
8487     {
8488       /* The focus is on a dialog's action area button, *and* the widget that
8489        * was focused immediately before it is the location entry.
8490        */
8491       goto save_entry;
8492     }
8493   else
8494     /* The focus is on a dialog's action area button or something else */
8495     if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
8496         || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
8497       goto save_entry;
8498     else
8499       goto file_list; 
8500   
8501   g_assert_not_reached ();
8502   return FALSE;
8503 }
8504
8505 /* Implementation for GtkFileChooserEmbed::initial_focus() */
8506 static void
8507 gtk_file_chooser_default_initial_focus (GtkFileChooserEmbed *chooser_embed)
8508 {
8509   GtkFileChooserDefault *impl;
8510   GtkWidget *widget;
8511
8512   impl = GTK_FILE_CHOOSER_DEFAULT (chooser_embed);
8513
8514   if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
8515       impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
8516     {
8517       if (impl->location_mode == LOCATION_MODE_PATH_BAR)
8518         widget = impl->browse_files_tree_view;
8519       else
8520         widget = impl->location_entry;
8521     }
8522   else if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE ||
8523            impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
8524     widget = impl->location_entry;
8525   else
8526     {
8527       g_assert_not_reached ();
8528       widget = NULL;
8529     }
8530
8531   g_assert (widget != NULL);
8532   gtk_widget_grab_focus (widget);
8533 }
8534
8535 /* Callback used from gtk_tree_selection_selected_foreach(); gets the selected GtkFilePaths */
8536 static void
8537 search_selected_foreach_get_path_cb (GtkTreeModel *model,
8538                                      GtkTreePath  *path,
8539                                      GtkTreeIter  *iter,
8540                                      gpointer      data)
8541 {
8542   GSList **list;
8543   const GtkFilePath *file_path;
8544   GtkFilePath *file_path_copy;
8545
8546   list = data;
8547
8548   gtk_tree_model_get (model, iter, SEARCH_MODEL_COL_PATH, &file_path, -1);
8549   file_path_copy = gtk_file_path_copy (file_path);
8550   *list = g_slist_prepend (*list, file_path_copy);
8551 }
8552
8553 /* Constructs a list of the selected paths in search mode */
8554 static GSList *
8555 search_get_selected_paths (GtkFileChooserDefault *impl)
8556 {
8557   GSList *result;
8558   GtkTreeSelection *selection;
8559
8560   result = NULL;
8561
8562   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
8563   gtk_tree_selection_selected_foreach (selection, search_selected_foreach_get_path_cb, &result);
8564   result = g_slist_reverse (result);
8565
8566   return result;
8567 }
8568
8569 /* Called from ::should_respond().  We return whether there are selected files
8570  * in the search list.
8571  */
8572 static gboolean
8573 search_should_respond (GtkFileChooserDefault *impl)
8574 {
8575   GtkTreeSelection *selection;
8576
8577   g_assert (impl->operation_mode == OPERATION_MODE_SEARCH);
8578
8579   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
8580   return (gtk_tree_selection_count_selected_rows (selection) != 0);
8581 }
8582
8583 struct SearchHitInsertRequest
8584 {
8585   GtkFileChooserDefault *impl;
8586   GtkFilePath *path;
8587   GtkTreeRowReference *row_ref;
8588 };
8589
8590 static void
8591 search_hit_get_info_cb (GtkFileSystemHandle *handle,
8592                         const GtkFileInfo   *info,
8593                         const GError        *error,
8594                         gpointer             data)
8595 {
8596   gboolean cancelled = handle->cancelled;
8597   GdkPixbuf *pixbuf = NULL;
8598   GtkTreePath *path;
8599   GtkTreeIter iter;
8600   GtkFileSystemHandle *model_handle;
8601   gboolean is_folder = FALSE;
8602   char *mime_type;
8603   char *display_name;
8604   struct SearchHitInsertRequest *request = data;
8605
8606   path = gtk_tree_row_reference_get_path (request->row_ref);
8607   if (!path)
8608     goto out;
8609
8610   gtk_tree_model_get_iter (GTK_TREE_MODEL (request->impl->search_model),
8611                            &iter, path);
8612   gtk_tree_path_free (path);
8613
8614   gtk_tree_model_get (GTK_TREE_MODEL (request->impl->search_model), &iter,
8615                       SEARCH_MODEL_COL_HANDLE, &model_handle,
8616                       -1);
8617   if (handle != model_handle)
8618     goto out;
8619
8620   /* set the handle to NULL in the model */
8621   gtk_list_store_set (request->impl->search_model, &iter,
8622                       SEARCH_MODEL_COL_HANDLE, NULL,
8623                       -1);
8624
8625   if (cancelled)
8626     goto out;
8627
8628   if (!info)
8629     {
8630       gtk_list_store_remove (request->impl->search_model, &iter);
8631       goto out;
8632     }
8633
8634   display_name = g_strdup (gtk_file_info_get_display_name (info));
8635   mime_type = g_strdup (gtk_file_info_get_mime_type (info));
8636   is_folder = gtk_file_info_get_is_folder (info);
8637   pixbuf = gtk_file_info_render_icon (info, GTK_WIDGET (request->impl),
8638                                       request->impl->icon_size, NULL);
8639
8640   gtk_list_store_set (request->impl->search_model, &iter,
8641                       SEARCH_MODEL_COL_PIXBUF, pixbuf,
8642                       SEARCH_MODEL_COL_DISPLAY_NAME, display_name,
8643                       SEARCH_MODEL_COL_MIME_TYPE, mime_type,
8644                       SEARCH_MODEL_COL_IS_FOLDER, is_folder,
8645                       -1);
8646
8647   if (pixbuf)
8648     g_object_unref (pixbuf);
8649
8650 out:
8651   g_object_unref (request->impl);
8652   gtk_file_path_free (request->path);
8653   gtk_tree_row_reference_free (request->row_ref);
8654   g_free (request);
8655
8656   g_object_unref (handle);
8657 }
8658
8659 /* Adds one hit from the search engine to the search_model */
8660 static void
8661 search_add_hit (GtkFileChooserDefault *impl,
8662                 gchar                 *uri)
8663 {
8664   GtkFilePath *path;
8665   char *filename;
8666   char *tmp;
8667   char *collation_key;
8668   struct stat statbuf;
8669   struct stat *statbuf_copy;
8670   GtkTreeIter iter;
8671   GtkTreePath *p;
8672   GtkFileSystemHandle *handle;
8673   struct SearchHitInsertRequest *request;
8674
8675   path = gtk_file_system_uri_to_path (impl->file_system, uri);
8676   if (!path)
8677     return;
8678
8679   filename = gtk_file_system_path_to_filename (impl->file_system, path);
8680   if (!filename)
8681     {
8682       gtk_file_path_free (path);
8683       return;
8684     }
8685
8686   if (stat (filename, &statbuf) != 0)
8687     {
8688       gtk_file_path_free (path);
8689       g_free (filename);
8690       return;
8691     }
8692
8693   statbuf_copy = g_new (struct stat, 1);
8694   *statbuf_copy = statbuf;
8695
8696   tmp = g_filename_display_name (filename);
8697   collation_key = g_utf8_collate_key_for_filename (tmp, -1);
8698   g_free (tmp);
8699
8700   request = g_new0 (struct SearchHitInsertRequest, 1);
8701   request->impl = g_object_ref (impl);
8702   request->path = gtk_file_path_copy (path);
8703
8704   gtk_list_store_append (impl->search_model, &iter);
8705   p = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->search_model), &iter);
8706   
8707   request->row_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (impl->search_model), p);
8708   gtk_tree_path_free (p);
8709
8710   handle = gtk_file_system_get_info (impl->file_system, path,
8711                                      GTK_FILE_INFO_IS_FOLDER | GTK_FILE_INFO_ICON | GTK_FILE_INFO_MIME_TYPE | GTK_FILE_INFO_DISPLAY_NAME,
8712                                      search_hit_get_info_cb,
8713                                      request);
8714
8715   gtk_list_store_set (impl->search_model, &iter,
8716                       SEARCH_MODEL_COL_PATH, path,
8717                       SEARCH_MODEL_COL_COLLATION_KEY, collation_key,
8718                       SEARCH_MODEL_COL_STAT, statbuf_copy,
8719                       SEARCH_MODEL_COL_HANDLE, handle,
8720                       -1);
8721 }
8722
8723 /* Callback used from GtkSearchEngine when we get new hits */
8724 static void
8725 search_engine_hits_added_cb (GtkSearchEngine *engine,
8726                              GList           *hits,
8727                              gpointer         data)
8728 {
8729   GtkFileChooserDefault *impl;
8730   GList *l;
8731   
8732   impl = GTK_FILE_CHOOSER_DEFAULT (data);
8733
8734   for (l = hits; l; l = l->next)
8735     search_add_hit (impl, (gchar*)l->data);
8736 }
8737
8738 /* Callback used from GtkSearchEngine when the query is done running */
8739 static void
8740 search_engine_finished_cb (GtkSearchEngine *engine,
8741                            gpointer         data)
8742 {
8743   GtkFileChooserDefault *impl;
8744   
8745   impl = GTK_FILE_CHOOSER_DEFAULT (data);
8746   
8747 #if 0
8748   /* EB: setting the model here will avoid loads of row events,
8749    * but it'll make the search look like blocked.
8750    */
8751   gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view),
8752                            GTK_TREE_MODEL (impl->search_model_filter));
8753 #endif
8754
8755   /* FMQ: if search was empty, say that we got no hits */
8756   set_busy_cursor (impl, FALSE);
8757 }
8758
8759 /* Displays a generic error when we cannot create a GtkSearchEngine.  
8760  * It would be better if _gtk_search_engine_new() gave us a GError 
8761  * with a better message, but it doesn't do that right now.
8762  */
8763 static void
8764 search_error_could_not_create_client (GtkFileChooserDefault *impl)
8765 {
8766   error_message (impl,
8767                  _("Could not start the search process"),
8768                  _("The program was not able to create a connection to the indexer "
8769                    "daemon.  Please make sure it is running."));
8770 }
8771
8772 static void
8773 search_engine_error_cb (GtkSearchEngine *engine,
8774                         const gchar     *message,
8775                         gpointer         data)
8776 {
8777   GtkFileChooserDefault *impl;
8778   
8779   impl = GTK_FILE_CHOOSER_DEFAULT (data);
8780
8781   search_stop_searching (impl, TRUE);
8782   error_message (impl, _("Could not send the search request"), message);
8783
8784   set_busy_cursor (impl, FALSE);
8785 }
8786
8787 /* Frees the data in the search_model */
8788 static void
8789 search_clear_model (GtkFileChooserDefault *impl, 
8790                     gboolean               remove_from_treeview)
8791 {
8792   GtkTreeModel *model;
8793   GtkTreeIter iter;
8794
8795   if (!impl->search_model)
8796     return;
8797
8798   model = GTK_TREE_MODEL (impl->search_model);
8799
8800   if (gtk_tree_model_get_iter_first (model, &iter))
8801     do
8802       {
8803         GtkFilePath *path;
8804         gchar *display_name;
8805         gchar *collation_key;
8806         struct stat *statbuf;
8807         GtkFileSystemHandle *handle;
8808
8809         gtk_tree_model_get (model, &iter,
8810                             SEARCH_MODEL_COL_PATH, &path,
8811                             SEARCH_MODEL_COL_DISPLAY_NAME, &display_name,
8812                             SEARCH_MODEL_COL_COLLATION_KEY, &collation_key,
8813                             SEARCH_MODEL_COL_STAT, &statbuf,
8814                             SEARCH_MODEL_COL_HANDLE, &handle,
8815                             -1);
8816         
8817         if (handle)
8818           gtk_file_system_cancel_operation (handle);
8819
8820         gtk_file_path_free (path);
8821         g_free (display_name);
8822         g_free (collation_key);
8823         g_free (statbuf);
8824       }
8825     while (gtk_tree_model_iter_next (model, &iter));
8826
8827   g_object_unref (impl->search_model);
8828   impl->search_model = NULL;
8829   
8830   g_object_unref (impl->search_model_filter);
8831   impl->search_model_filter = NULL;
8832
8833   if (remove_from_treeview)
8834     gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view), NULL);
8835 }
8836
8837 /* Stops any ongoing searches; does not touch the search_model */
8838 static void
8839 search_stop_searching (GtkFileChooserDefault *impl,
8840                        gboolean               remove_query)
8841 {
8842   if (remove_query && impl->search_query)
8843     {
8844       g_object_unref (impl->search_query);
8845       impl->search_query = NULL;
8846     }
8847   
8848   if (impl->search_engine)
8849     {
8850       g_object_unref (impl->search_engine);
8851       impl->search_engine = NULL;
8852     }
8853 }
8854
8855 /* Stops any pending searches, clears the file list, and switches back to OPERATION_MODE_BROWSE */
8856 static void
8857 search_switch_to_browse_mode (GtkFileChooserDefault *impl)
8858 {
8859   g_assert (impl->operation_mode != OPERATION_MODE_BROWSE);
8860
8861   search_stop_searching (impl, FALSE);
8862   search_clear_model (impl, TRUE);
8863
8864   gtk_widget_destroy (impl->search_hbox);
8865   impl->search_hbox = NULL;
8866   impl->search_entry = NULL;
8867
8868   gtk_widget_show (impl->browse_path_bar);
8869   gtk_widget_show (impl->browse_new_folder_button);
8870
8871   if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
8872       impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
8873     {
8874       gtk_widget_show (impl->location_button);
8875
8876       if (impl->location_mode == LOCATION_MODE_FILENAME_ENTRY)
8877         gtk_widget_show (impl->location_entry_box);
8878     }
8879
8880   impl->operation_mode = OPERATION_MODE_BROWSE;
8881
8882   file_list_set_sort_column_ids (impl);
8883 }
8884
8885 /* Sort callback from the path column */
8886 static gint
8887 search_column_path_sort_func (GtkTreeModel *model,
8888                               GtkTreeIter  *a,
8889                               GtkTreeIter  *b,
8890                               gpointer      user_data)
8891 {
8892   const char *collation_key_a, *collation_key_b;
8893   gboolean is_folder_a, is_folder_b;
8894
8895   gtk_tree_model_get (model, a,
8896                       SEARCH_MODEL_COL_IS_FOLDER, &is_folder_a,
8897                       SEARCH_MODEL_COL_COLLATION_KEY, &collation_key_a,
8898                       -1);
8899   gtk_tree_model_get (model, b,
8900                       SEARCH_MODEL_COL_IS_FOLDER, &is_folder_b,
8901                       SEARCH_MODEL_COL_COLLATION_KEY, &collation_key_b,
8902                       -1);
8903
8904   /* always show folders first */
8905   if (is_folder_a != is_folder_b)
8906     return is_folder_a ? 1 : -1;
8907
8908   return strcmp (collation_key_a, collation_key_b);
8909 }
8910
8911 /* Sort callback from the modification time column */
8912 static gint
8913 search_column_mtime_sort_func (GtkTreeModel *model,
8914                                GtkTreeIter  *a,
8915                                GtkTreeIter  *b,
8916                                gpointer      user_data)
8917 {
8918   const struct stat *statbuf_a, *statbuf_b;
8919   gboolean is_folder_a, is_folder_b;
8920
8921   /* Note that although we store a whole struct stat in the model, we only
8922    * compare the mtime here.  If we add another column relative to a struct stat
8923    * (e.g. a file size column), we'll want another sort callback similar to this
8924    * one as well.
8925    */
8926
8927   gtk_tree_model_get (model, a,
8928                       SEARCH_MODEL_COL_IS_FOLDER, &is_folder_a,
8929                       SEARCH_MODEL_COL_STAT, &statbuf_a,
8930                       -1);
8931   gtk_tree_model_get (model, b,
8932                       SEARCH_MODEL_COL_IS_FOLDER, &is_folder_b,
8933                       SEARCH_MODEL_COL_STAT, &statbuf_b,
8934                       -1);
8935
8936   if (is_folder_a != is_folder_b)
8937     return is_folder_a ? 1 : -1;
8938
8939   if (statbuf_a->st_mtime < statbuf_b->st_mtime)
8940     return -1;
8941   else if (statbuf_a->st_mtime > statbuf_b->st_mtime)
8942     return 1;
8943   else
8944     return 0;
8945 }
8946
8947 static gboolean
8948 search_get_is_filtered (GtkFileChooserDefault *impl,
8949                         const GtkFilePath     *path,
8950                         const gchar           *display_name,
8951                         const gchar           *mime_type)
8952 {
8953   GtkFileFilterInfo filter_info;
8954   GtkFileFilterFlags needed;
8955   gboolean result;
8956
8957   if (!impl->current_filter)
8958     return FALSE;
8959
8960   filter_info.contains = GTK_FILE_FILTER_DISPLAY_NAME | GTK_FILE_FILTER_MIME_TYPE;
8961   needed = gtk_file_filter_get_needed (impl->current_filter);
8962
8963   filter_info.display_name = display_name;
8964   filter_info.mime_type = mime_type;
8965
8966   if (needed & GTK_FILE_FILTER_FILENAME)
8967     {
8968       filter_info.filename = gtk_file_system_path_to_filename (impl->file_system, path);
8969       if (filter_info.filename)
8970         filter_info.contains |= GTK_FILE_FILTER_FILENAME;
8971     }
8972   else
8973     filter_info.filename = NULL;
8974
8975   if (needed & GTK_FILE_FILTER_URI)
8976     {
8977       filter_info.uri = gtk_file_system_path_to_uri (impl->file_system, path);
8978       if (filter_info.uri)
8979         filter_info.contains |= GTK_FILE_FILTER_URI;
8980     }
8981   else
8982     filter_info.uri = NULL;
8983
8984   result = gtk_file_filter_filter (impl->current_filter, &filter_info);
8985
8986   if (filter_info.filename)
8987     g_free ((gchar *) filter_info.filename);
8988   if (filter_info.uri)
8989     g_free ((gchar *) filter_info.uri);
8990
8991   return !result;
8992
8993 }
8994
8995 /* Visibility function for the recent filter model */
8996 static gboolean
8997 search_model_visible_func (GtkTreeModel *model,
8998                            GtkTreeIter  *iter,
8999                            gpointer      user_data)
9000 {
9001   GtkFileChooserDefault *impl = user_data;
9002   GtkFilePath *file_path;
9003   gchar *display_name, *mime_type;
9004   gboolean is_folder;
9005
9006   if (!impl->current_filter)
9007     return TRUE;
9008
9009   gtk_tree_model_get (model, iter,
9010                       SEARCH_MODEL_COL_PATH, &file_path,
9011                       SEARCH_MODEL_COL_IS_FOLDER, &is_folder,
9012                       SEARCH_MODEL_COL_DISPLAY_NAME, &display_name,
9013                       SEARCH_MODEL_COL_MIME_TYPE, &mime_type,
9014                       -1);
9015
9016   if (!display_name)
9017     return TRUE;
9018
9019   if (is_folder)
9020     return TRUE;
9021
9022   return !search_get_is_filtered (impl, file_path, display_name, mime_type);
9023 }
9024
9025 /* Creates the search_model and puts it in the tree view */
9026 static void
9027 search_setup_model (GtkFileChooserDefault *impl)
9028 {
9029   g_assert (impl->search_model == NULL);
9030   g_assert (impl->search_model_filter == NULL);
9031
9032   /* We store these columns in the search model:
9033    *
9034    * SEARCH_MODEL_COL_PATH - a GtkFilePath for the hit's URI, stored as a
9035    *   pointer not as a GTK_TYPE_FILE_PATH
9036    * SEARCH_MODEL_COL_DISPLAY_NAME - a string with the display name, stored
9037    *   as a pointer not as a G_TYPE_STRING
9038    * SEARCH_MODEL_COL_COLLATION_KEY - collation key for the filename, stored
9039    *   as a pointer not as a G_TYPE_STRING
9040    * SEARCH_MODEL_COL_STAT - pointer to a struct stat
9041    * SEARCH_MODEL_COL_HANDLE - handle used when getting the hit's info
9042    * SEARCH_MODEL_COL_PIXBUF - GdkPixbuf for the hit's icon
9043    * SEARCH_MODEL_COL_MIME_TYPE - a string with the hit's MIME type
9044    * SEARCH_MODEL_COL_IS_FOLDER - a boolean flag for folders
9045    *
9046    * Keep this in sync with the enumeration defined near the beginning
9047    * of this file.
9048    */
9049   impl->search_model = gtk_list_store_new (SEARCH_MODEL_COL_NUM_COLUMNS,
9050                                            G_TYPE_POINTER,
9051                                            G_TYPE_POINTER,
9052                                            G_TYPE_POINTER,
9053                                            G_TYPE_POINTER,
9054                                            G_TYPE_POINTER,
9055                                            GDK_TYPE_PIXBUF,
9056                                            G_TYPE_POINTER,
9057                                            G_TYPE_BOOLEAN);
9058   gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->search_model),
9059                                    SEARCH_MODEL_COL_PATH,
9060                                    search_column_path_sort_func,
9061                                    impl,
9062                                    NULL);
9063   gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->search_model),
9064                                    SEARCH_MODEL_COL_STAT,
9065                                    search_column_mtime_sort_func,
9066                                    impl,
9067                                    NULL);
9068
9069   gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (impl->search_model),
9070                                         SEARCH_MODEL_COL_STAT,
9071                                         GTK_SORT_DESCENDING);
9072   
9073   impl->search_model_filter =
9074     GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (GTK_TREE_MODEL (impl->search_model), NULL));
9075   gtk_tree_model_filter_set_visible_func (impl->search_model_filter,
9076                                           search_model_visible_func,
9077                                           impl, NULL);
9078
9079   /* EB: setting the model here will make the hits list update feel
9080    * more "alive" than setting the model at the end of the search
9081    * run
9082    */
9083   gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view),
9084                            GTK_TREE_MODEL (impl->search_model_filter));
9085 }
9086
9087 /* Creates a new query with the specified text and launches it */
9088 static void
9089 search_start_query (GtkFileChooserDefault *impl,
9090                     const gchar           *query_text)
9091 {
9092   search_stop_searching (impl, FALSE);
9093   search_clear_model (impl, TRUE);
9094   search_setup_model (impl);
9095   set_busy_cursor (impl, TRUE);
9096
9097   if (impl->search_engine == NULL)
9098     impl->search_engine = _gtk_search_engine_new ();
9099
9100   if (!impl->search_engine)
9101     {
9102       set_busy_cursor (impl, FALSE);
9103       search_error_could_not_create_client (impl); /* lame; we don't get an error code or anything */
9104       return;
9105     }
9106
9107   if (!impl->search_query)
9108     {
9109       impl->search_query = _gtk_query_new ();
9110       _gtk_query_set_text (impl->search_query, query_text);
9111     }
9112   
9113   _gtk_search_engine_set_query (impl->search_engine, impl->search_query);
9114
9115   g_signal_connect (impl->search_engine, "hits-added",
9116                     G_CALLBACK (search_engine_hits_added_cb), impl);
9117   g_signal_connect (impl->search_engine, "finished",
9118                     G_CALLBACK (search_engine_finished_cb), impl);
9119   g_signal_connect (impl->search_engine, "error",
9120                     G_CALLBACK (search_engine_error_cb), impl);
9121
9122   _gtk_search_engine_start (impl->search_engine);
9123 }
9124
9125 /* Callback used when the user presses Enter while typing on the search
9126  * entry; starts the query
9127  */
9128 static void
9129 search_entry_activate_cb (GtkEntry *entry,
9130                           gpointer data)
9131 {
9132   GtkFileChooserDefault *impl;
9133   const char *text;
9134
9135   impl = GTK_FILE_CHOOSER_DEFAULT (data);
9136
9137   text = gtk_entry_get_text (GTK_ENTRY (impl->search_entry));
9138   if (strlen (text) == 0)
9139     return;
9140
9141   /* reset any existing query object */
9142   if (impl->search_query)
9143     {
9144       g_object_unref (impl->search_query);
9145       impl->search_query = NULL;
9146     }
9147
9148   search_start_query (impl, text);
9149 }
9150
9151 /* Hides the path bar and creates the search entry */
9152 static void
9153 search_setup_widgets (GtkFileChooserDefault *impl)
9154 {
9155   GtkWidget *label;
9156
9157   impl->search_hbox = gtk_hbox_new (FALSE, 12);
9158
9159   /* Label */
9160
9161   label = gtk_label_new_with_mnemonic (_("_Search:"));
9162   gtk_box_pack_start (GTK_BOX (impl->search_hbox), label, FALSE, FALSE, 0);
9163
9164   /* Entry */
9165
9166   impl->search_entry = gtk_entry_new ();
9167   gtk_label_set_mnemonic_widget (GTK_LABEL (label), impl->search_entry);
9168   g_signal_connect (impl->search_entry, "activate",
9169                     G_CALLBACK (search_entry_activate_cb),
9170                     impl);
9171   gtk_box_pack_start (GTK_BOX (impl->search_hbox), impl->search_entry, TRUE, TRUE, 0);
9172
9173   /* if there already is a query, restart it */
9174   if (impl->search_query)
9175     {
9176       gchar *query = _gtk_query_get_text (impl->search_query);
9177
9178       if (query)
9179         {
9180           gtk_entry_set_text (GTK_ENTRY (impl->search_entry), query);
9181           search_start_query (impl, query);
9182
9183           g_free (query);
9184         }
9185       else
9186         {
9187           g_object_unref (impl->search_query);
9188           impl->search_query = NULL;
9189         }
9190     }
9191
9192   gtk_widget_hide (impl->browse_path_bar);
9193   gtk_widget_hide (impl->browse_new_folder_button);
9194
9195   /* Box for search widgets */
9196   gtk_box_pack_start (GTK_BOX (impl->browse_path_bar_hbox), impl->search_hbox, TRUE, TRUE, 0);
9197   gtk_widget_show_all (impl->search_hbox);
9198
9199   /* Hide the location widgets temporarily */
9200
9201   if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
9202       impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
9203     {
9204       gtk_widget_hide (impl->location_button);
9205       gtk_widget_hide (impl->location_entry_box);
9206     }
9207
9208   gtk_widget_grab_focus (impl->search_entry);
9209
9210   /* FMQ: hide the filter combo? */
9211 }
9212
9213 /* Main entry point to the searching functions; this gets called when the user
9214  * activates the Search shortcut.
9215  */
9216 static void
9217 search_activate (GtkFileChooserDefault *impl)
9218 {
9219   OperationMode previous_mode;
9220   
9221   if (impl->operation_mode == OPERATION_MODE_SEARCH)
9222     {
9223       gtk_widget_grab_focus (impl->search_entry);
9224       return;
9225     }
9226
9227   previous_mode = impl->operation_mode;
9228   impl->operation_mode = OPERATION_MODE_SEARCH;
9229
9230   switch (previous_mode)
9231     {
9232     case OPERATION_MODE_RECENT:
9233       recent_stop_loading (impl);
9234       recent_clear_model (impl, TRUE);
9235       break;
9236
9237     case OPERATION_MODE_BROWSE:
9238       stop_loading_and_clear_list_model (impl);
9239       break;
9240
9241     case OPERATION_MODE_SEARCH:
9242       g_assert_not_reached ();
9243       break;
9244     }
9245
9246   g_assert (impl->search_hbox == NULL);
9247   g_assert (impl->search_entry == NULL);
9248   g_assert (impl->search_model == NULL);
9249   g_assert (impl->search_model_filter == NULL);
9250
9251   search_setup_widgets (impl);
9252   file_list_set_sort_column_ids (impl);
9253 }
9254
9255 /*
9256  * Recent files support
9257  */
9258
9259 /* Frees the data in the recent_model */
9260 static void
9261 recent_clear_model (GtkFileChooserDefault *impl,
9262                     gboolean               remove_from_treeview)
9263 {
9264   GtkTreeModel *model;
9265   GtkTreeIter iter;
9266
9267   if (!impl->recent_model)
9268     return;
9269
9270   model = GTK_TREE_MODEL (impl->recent_model);
9271
9272   if (gtk_tree_model_get_iter_first (model, &iter))
9273     {
9274       do
9275         {
9276           GtkFilePath *file_path;
9277           GtkFileSystemHandle *handle;
9278           GtkRecentInfo *recent_info;
9279           gchar *display_name;
9280
9281           gtk_tree_model_get (model, &iter,
9282                               RECENT_MODEL_COL_DISPLAY_NAME, &display_name,
9283                               RECENT_MODEL_COL_PATH, &file_path,
9284                               RECENT_MODEL_COL_HANDLE, &handle,
9285                               RECENT_MODEL_COL_INFO, &recent_info,
9286                               -1);
9287           
9288           if (handle)
9289             gtk_file_system_cancel_operation (handle);
9290
9291           gtk_file_path_free (file_path);
9292           gtk_recent_info_unref (recent_info);
9293           g_free (display_name);
9294         }
9295       while (gtk_tree_model_iter_next (model, &iter));
9296     }
9297
9298   g_object_unref (impl->recent_model);
9299   impl->recent_model = NULL;
9300
9301   g_object_unref (impl->recent_model_filter);
9302   impl->recent_model_filter = NULL;
9303
9304   if (remove_from_treeview)
9305     gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view), NULL);
9306 }
9307
9308 /* Stops any ongoing loading of the recent files list; does
9309  * not touch the recent_model
9310  */
9311 static void
9312 recent_stop_loading (GtkFileChooserDefault *impl)
9313 {
9314   if (impl->load_recent_id)
9315     {
9316       g_source_remove (impl->load_recent_id);
9317       impl->load_recent_id = 0;
9318     }
9319 }
9320
9321 /* Stops any pending load, clears the file list, and switches
9322  * back to OPERATION_MODE_BROWSE
9323  */
9324 static void
9325 recent_switch_to_browse_mode (GtkFileChooserDefault *impl)
9326 {
9327   g_assert (impl->operation_mode != OPERATION_MODE_BROWSE);
9328
9329   recent_stop_loading (impl);
9330   recent_clear_model (impl, TRUE);
9331
9332   gtk_widget_show (impl->browse_path_bar);
9333   gtk_widget_show (impl->browse_new_folder_button);
9334
9335   if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
9336       impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
9337     {
9338       gtk_widget_show (impl->location_button);
9339
9340       if (impl->location_mode == LOCATION_MODE_FILENAME_ENTRY)
9341         gtk_widget_show (impl->location_entry_box);
9342     }
9343
9344   impl->operation_mode = OPERATION_MODE_BROWSE;
9345
9346   file_list_set_sort_column_ids (impl);
9347 }
9348
9349 /* Sort callback from the modification time column */
9350 static gint
9351 recent_column_mtime_sort_func (GtkTreeModel *model,
9352                                GtkTreeIter  *a,
9353                                GtkTreeIter  *b,
9354                                gpointer      user_data)
9355 {
9356   GtkRecentInfo *info_a, *info_b;
9357   gboolean is_folder_a, is_folder_b;
9358
9359   gtk_tree_model_get (model, a,
9360                       RECENT_MODEL_COL_IS_FOLDER, &is_folder_a,
9361                       RECENT_MODEL_COL_INFO, &info_a,
9362                       -1);
9363   gtk_tree_model_get (model, b,
9364                       RECENT_MODEL_COL_IS_FOLDER, &is_folder_b,
9365                       RECENT_MODEL_COL_INFO, &info_b,
9366                       -1);
9367
9368   /* folders always go first */
9369   if (is_folder_a != is_folder_b)
9370     return is_folder_a ? 1 : -1;
9371
9372   if (gtk_recent_info_get_modified (info_a) < gtk_recent_info_get_modified (info_b))
9373     return -1;
9374   else if (gtk_recent_info_get_modified (info_a) > gtk_recent_info_get_modified (info_b))
9375     return 1;
9376   else
9377     return 0;
9378 }
9379
9380 static gboolean
9381 recent_get_is_filtered (GtkFileChooserDefault *impl,
9382                         const GtkFilePath     *path,
9383                         GtkRecentInfo         *recent_info)
9384 {
9385   GtkFileFilterInfo filter_info;
9386   GtkFileFilterFlags needed;
9387   gboolean result;
9388
9389   if (!impl->current_filter)
9390     return FALSE;
9391
9392   filter_info.contains = GTK_FILE_FILTER_DISPLAY_NAME | GTK_FILE_FILTER_MIME_TYPE;
9393   needed = gtk_file_filter_get_needed (impl->current_filter);
9394
9395   filter_info.display_name = gtk_recent_info_get_display_name (recent_info);
9396   filter_info.mime_type = gtk_recent_info_get_mime_type (recent_info);
9397
9398   if (needed & GTK_FILE_FILTER_FILENAME)
9399     {
9400       filter_info.filename = gtk_file_system_path_to_filename (impl->file_system, path);
9401       if (filter_info.filename)
9402         filter_info.contains |= GTK_FILE_FILTER_FILENAME;
9403     }
9404   else
9405     filter_info.filename = NULL;
9406
9407   if (needed & GTK_FILE_FILTER_URI)
9408     {
9409       filter_info.uri = gtk_file_system_path_to_uri (impl->file_system, path);
9410       if (filter_info.uri)
9411         filter_info.contains |= GTK_FILE_FILTER_URI;
9412     }
9413   else
9414     filter_info.uri = NULL;
9415
9416   result = gtk_file_filter_filter (impl->current_filter, &filter_info);
9417
9418   if (filter_info.filename)
9419     g_free ((gchar *) filter_info.filename);
9420   if (filter_info.uri)
9421     g_free ((gchar *) filter_info.uri);
9422
9423   return !result;
9424 }
9425
9426 /* Visibility function for the recent filter model */
9427 static gboolean
9428 recent_model_visible_func (GtkTreeModel *model,
9429                            GtkTreeIter  *iter,
9430                            gpointer      user_data)
9431 {
9432   GtkFileChooserDefault *impl = user_data;
9433   GtkFilePath *file_path;
9434   GtkRecentInfo *recent_info;
9435   gboolean is_folder;
9436
9437   if (!impl->current_filter)
9438     return TRUE;
9439
9440   gtk_tree_model_get (model, iter,
9441                       RECENT_MODEL_COL_INFO, &recent_info,
9442                       RECENT_MODEL_COL_PATH, &file_path,
9443                       RECENT_MODEL_COL_IS_FOLDER, &is_folder,
9444                       -1);
9445
9446   if (!recent_info)
9447     return TRUE;
9448
9449   if (is_folder)
9450     return TRUE;
9451
9452   return !recent_get_is_filtered (impl, file_path, recent_info);
9453 }
9454
9455 static void
9456 recent_setup_model (GtkFileChooserDefault *impl)
9457 {
9458   g_assert (impl->recent_model == NULL);
9459   g_assert (impl->recent_model_filter == NULL);
9460
9461   /* We store these columns in the search model:
9462    *
9463    * RECENT_MODEL_COL_PATH - a pointer to GtkFilePath for the hit's URI,
9464    *   stored as a pointer and not as a GTK_TYPE_FILE_PATH;
9465    * RECENT_MODEL_COL_DISPLAY_NAME - a string with the display name,
9466    *   stored as a pointer and not as a G_TYPE_STRING;
9467    * RECENT_MODEL_COL_INFO - GtkRecentInfo, stored as a pointer and not
9468    *   as a GTK_TYPE_RECENT_INFO;
9469    * RECENT_MODEL_COL_IS_FOLDER - boolean flag;
9470    * RECENT_MODEL_COL_HANDLE - GtkFileSystemHandle, stored as a pointer
9471    *   and not as a GTK_TYPE_FILE_SYSTEM_HANDLE;
9472    *
9473    * Keep this in sync with the enumeration defined near the beginning of
9474    * this file.
9475    */
9476   impl->recent_model = gtk_list_store_new (RECENT_MODEL_COL_NUM_COLUMNS,
9477                                            G_TYPE_POINTER,
9478                                            G_TYPE_POINTER,
9479                                            G_TYPE_POINTER,
9480                                            G_TYPE_BOOLEAN,
9481                                            G_TYPE_POINTER);
9482   
9483   gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->recent_model),
9484                                    RECENT_MODEL_COL_INFO,
9485                                    recent_column_mtime_sort_func,
9486                                    impl,
9487                                    NULL);
9488   gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (impl->recent_model),
9489                                         RECENT_MODEL_COL_INFO,
9490                                         GTK_SORT_DESCENDING);
9491
9492   impl->recent_model_filter =
9493     GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (GTK_TREE_MODEL (impl->recent_model), NULL));
9494   gtk_tree_model_filter_set_visible_func (impl->recent_model_filter,
9495                                           recent_model_visible_func,
9496                                           impl,
9497                                           NULL);
9498 }
9499
9500 typedef struct
9501 {
9502   GtkFileChooserDefault *impl;
9503   GList *items;
9504   gint n_items;
9505   gint n_loaded_items;
9506 } RecentLoadData;
9507
9508 static void
9509 recent_idle_cleanup (gpointer data)
9510 {
9511   RecentLoadData *load_data = data;
9512   GtkFileChooserDefault *impl = load_data->impl;
9513
9514   gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view),
9515                            GTK_TREE_MODEL (impl->recent_model_filter));
9516   
9517   set_busy_cursor (impl, FALSE);
9518   
9519   impl->load_recent_id = 0;
9520   
9521   if (load_data->items)
9522     {
9523       g_list_foreach (load_data->items, (GFunc) gtk_recent_info_unref, NULL);
9524       g_list_free (load_data->items);
9525     }
9526
9527   g_free (load_data);
9528 }
9529
9530 struct RecentItemInsertRequest
9531 {
9532   GtkFileChooserDefault *impl;
9533   GtkFilePath *path;
9534   GtkTreeRowReference *row_ref;
9535 };
9536
9537 static void
9538 recent_item_get_info_cb (GtkFileSystemHandle *handle,
9539                          const GtkFileInfo   *info,
9540                          const GError        *error,
9541                          gpointer             data)
9542 {
9543   gboolean cancelled = handle->cancelled;
9544   GtkTreePath *path;
9545   GtkTreeIter iter;
9546   GtkFileSystemHandle *model_handle;
9547   gboolean is_folder = FALSE;
9548   struct RecentItemInsertRequest *request = data;
9549
9550   path = gtk_tree_row_reference_get_path (request->row_ref);
9551   if (!path)
9552     goto out;
9553
9554   gtk_tree_model_get_iter (GTK_TREE_MODEL (request->impl->recent_model),
9555                            &iter, path);
9556   gtk_tree_path_free (path);
9557
9558   gtk_tree_model_get (GTK_TREE_MODEL (request->impl->recent_model), &iter,
9559                       RECENT_MODEL_COL_HANDLE, &model_handle,
9560                       -1);
9561   if (handle != model_handle)
9562     goto out;
9563
9564   gtk_list_store_set (request->impl->recent_model, &iter,
9565                       RECENT_MODEL_COL_HANDLE, NULL,
9566                       -1);
9567
9568   if (cancelled)
9569     goto out;
9570
9571   if (!info)
9572     {
9573       gtk_list_store_remove (request->impl->recent_model, &iter);
9574       goto out;
9575     }
9576
9577   is_folder = gtk_file_info_get_is_folder (info);
9578
9579   gtk_list_store_set (request->impl->recent_model, &iter,
9580                       RECENT_MODEL_COL_IS_FOLDER, is_folder,
9581                       -1);
9582
9583 out:
9584   g_object_unref (request->impl);
9585   gtk_file_path_free (request->path);
9586   gtk_tree_row_reference_free (request->row_ref);
9587   g_free (request);
9588
9589   g_object_unref (handle);
9590 }
9591
9592 static gboolean
9593 recent_idle_load (gpointer data)
9594 {
9595   RecentLoadData *load_data = data;
9596   GtkFileChooserDefault *impl = load_data->impl;
9597   GtkTreeIter iter;
9598   GtkTreePath *p;
9599   GtkRecentInfo *info;
9600   const gchar *uri, *display_name;
9601   GtkFilePath *path;
9602   GtkFileSystemHandle *handle;
9603   struct RecentItemInsertRequest *request;
9604
9605   if (!impl->recent_manager)
9606     return FALSE;
9607
9608   if (!load_data->items)
9609     {
9610       load_data->items = gtk_recent_manager_get_items (impl->recent_manager);
9611       load_data->n_items = g_list_length (load_data->items);
9612       load_data->n_loaded_items = 0;
9613
9614       return TRUE;
9615     }
9616
9617   info = g_list_nth_data (load_data->items, load_data->n_loaded_items);
9618   g_assert (info != NULL);
9619
9620   uri = gtk_recent_info_get_uri (info);
9621   display_name = gtk_recent_info_get_display_name (info);
9622   path = gtk_file_system_uri_to_path (impl->file_system, uri);
9623   if (!path)
9624     goto load_next;
9625
9626   gtk_list_store_append (impl->recent_model, &iter);
9627   p = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->recent_model), &iter);
9628
9629   request = g_new0 (struct RecentItemInsertRequest, 1);
9630   request->impl = g_object_ref (impl);
9631   request->path = gtk_file_path_copy (path);
9632   request->row_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (impl->recent_model), p);
9633   gtk_tree_path_free (p);
9634
9635   handle = gtk_file_system_get_info (impl->file_system, path,
9636                                      GTK_FILE_INFO_IS_FOLDER,
9637                                      recent_item_get_info_cb,
9638                                      request);
9639
9640   gtk_list_store_set (impl->recent_model, &iter,
9641                       RECENT_MODEL_COL_PATH, path,
9642                       RECENT_MODEL_COL_DISPLAY_NAME, g_strdup (display_name),
9643                       RECENT_MODEL_COL_INFO, gtk_recent_info_ref (info),
9644                       RECENT_MODEL_COL_HANDLE, handle,
9645                       -1);
9646
9647 load_next:
9648
9649   load_data->n_loaded_items += 1;
9650
9651   /* finished loading items */
9652   if (load_data->n_loaded_items == load_data->n_items)
9653     {
9654       g_list_foreach (load_data->items, (GFunc) gtk_recent_info_unref, NULL);
9655       g_list_free (load_data->items);
9656       load_data->items = NULL;
9657
9658       return FALSE;
9659     }
9660
9661   return TRUE;
9662 }
9663
9664 static void
9665 recent_start_loading (GtkFileChooserDefault *impl)
9666 {
9667   RecentLoadData *load_data;
9668
9669   recent_stop_loading (impl);
9670   recent_clear_model (impl, TRUE);
9671   recent_setup_model (impl);
9672   set_busy_cursor (impl, TRUE);
9673
9674   if (!impl->recent_manager)
9675     recent_manager_update (impl);
9676
9677   g_assert (impl->load_recent_id == 0);
9678
9679   load_data = g_new (RecentLoadData, 1);
9680   load_data->impl = impl;
9681   load_data->items = NULL;
9682   load_data->n_items = 0;
9683   load_data->n_loaded_items = 0;
9684
9685   /* begin lazy loading the recent files into the model */
9686   impl->load_recent_id = gdk_threads_add_idle_full (G_PRIORITY_HIGH_IDLE + 30,
9687                                                     recent_idle_load,
9688                                                     load_data,
9689                                                     recent_idle_cleanup);
9690 }
9691
9692 static void
9693 recent_selected_foreach_get_path_cb (GtkTreeModel *model,
9694                                      GtkTreePath  *path,
9695                                      GtkTreeIter  *iter,
9696                                      gpointer      data)
9697 {
9698   GSList **list;
9699   const GtkFilePath *file_path;
9700   GtkFilePath *file_path_copy;
9701
9702   list = data;
9703
9704   gtk_tree_model_get (model, iter, RECENT_MODEL_COL_PATH, &file_path, -1);
9705   file_path_copy = gtk_file_path_copy (file_path);
9706   *list = g_slist_prepend (*list, file_path_copy);
9707 }
9708
9709 /* Constructs a list of the selected paths in recent files mode */
9710 static GSList *
9711 recent_get_selected_paths (GtkFileChooserDefault *impl)
9712 {
9713   GSList *result;
9714   GtkTreeSelection *selection;
9715
9716   result = NULL;
9717
9718   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
9719   gtk_tree_selection_selected_foreach (selection, recent_selected_foreach_get_path_cb, &result);
9720   result = g_slist_reverse (result);
9721
9722   return result;
9723 }
9724
9725 /* Called from ::should_respond().  We return whether there are selected
9726  * files in the recent files list.
9727  */
9728 static gboolean
9729 recent_should_respond (GtkFileChooserDefault *impl)
9730 {
9731   GtkTreeSelection *selection;
9732
9733   g_assert (impl->operation_mode == OPERATION_MODE_RECENT);
9734
9735   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
9736   return (gtk_tree_selection_count_selected_rows (selection) != 0);
9737 }
9738
9739 /* Hide the location widgets temporarily */
9740 static void
9741 recent_hide_entry (GtkFileChooserDefault *impl)
9742 {
9743   gtk_widget_hide (impl->browse_path_bar);
9744   gtk_widget_hide (impl->browse_new_folder_button);
9745   
9746   if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
9747       impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
9748     {
9749       gtk_widget_hide (impl->location_button);
9750       gtk_widget_hide (impl->location_entry_box);
9751     }
9752
9753   /* EB: hide the filter combo? */
9754 }
9755
9756 /* Main entry point to the recent files functions; this gets called when
9757  * the user activates the Recently Used shortcut.
9758  */
9759 static void
9760 recent_activate (GtkFileChooserDefault *impl)
9761 {
9762   OperationMode previous_mode;
9763
9764   if (impl->operation_mode == OPERATION_MODE_RECENT)
9765     return;
9766
9767   previous_mode = impl->operation_mode;
9768   impl->operation_mode = OPERATION_MODE_RECENT;
9769
9770   switch (previous_mode)
9771     {
9772     case OPERATION_MODE_SEARCH:
9773       search_stop_searching (impl, FALSE);
9774       search_clear_model (impl, TRUE);
9775
9776       gtk_widget_destroy (impl->search_hbox);
9777       impl->search_hbox = NULL;
9778       impl->search_entry = NULL;
9779       break;
9780
9781     case OPERATION_MODE_BROWSE:
9782       stop_loading_and_clear_list_model (impl);
9783       break;
9784
9785     case OPERATION_MODE_RECENT:
9786       g_assert_not_reached ();
9787       break;
9788     }
9789
9790   recent_hide_entry (impl);
9791   file_list_set_sort_column_ids (impl);
9792   recent_start_loading (impl);
9793 }
9794
9795
9796 static void
9797 set_current_filter (GtkFileChooserDefault *impl,
9798                     GtkFileFilter         *filter)
9799 {
9800   if (impl->current_filter != filter)
9801     {
9802       int filter_index;
9803
9804       /* NULL filters are allowed to reset to non-filtered status
9805        */
9806       filter_index = g_slist_index (impl->filters, filter);
9807       if (impl->filters && filter && filter_index < 0)
9808         return;
9809
9810       if (impl->current_filter)
9811         g_object_unref (impl->current_filter);
9812       impl->current_filter = filter;
9813       if (impl->current_filter)
9814         {
9815           g_object_ref_sink (impl->current_filter);
9816         }
9817
9818       if (impl->filters)
9819         gtk_combo_box_set_active (GTK_COMBO_BOX (impl->filter_combo),
9820                                   filter_index);
9821
9822       if (impl->browse_files_model)
9823         install_list_model_filter (impl);
9824
9825       if (impl->search_model_filter)
9826         gtk_tree_model_filter_refilter (impl->search_model_filter);
9827
9828       if (impl->recent_model_filter)
9829         gtk_tree_model_filter_refilter (impl->recent_model_filter);
9830
9831       g_object_notify (G_OBJECT (impl), "filter");
9832     }
9833 }
9834
9835 static void
9836 filter_combo_changed (GtkComboBox           *combo_box,
9837                       GtkFileChooserDefault *impl)
9838 {
9839   gint new_index = gtk_combo_box_get_active (combo_box);
9840   GtkFileFilter *new_filter = g_slist_nth_data (impl->filters, new_index);
9841
9842   set_current_filter (impl, new_filter);
9843 }
9844
9845 static void
9846 check_preview_change (GtkFileChooserDefault *impl)
9847 {
9848   GtkTreePath *cursor_path;
9849   const GtkFilePath *new_path;
9850   const char *new_display_name;
9851
9852   gtk_tree_view_get_cursor (GTK_TREE_VIEW (impl->browse_files_tree_view), &cursor_path, NULL);
9853   new_path = NULL;
9854   new_display_name = NULL;
9855   if (cursor_path)
9856     {
9857       GtkTreeIter child_iter;
9858
9859       if (impl->operation_mode == OPERATION_MODE_BROWSE)
9860         {
9861           if (impl->sort_model)
9862             {
9863               GtkTreeIter iter;
9864               const GtkFileInfo *new_info;
9865
9866               gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->sort_model), &iter, cursor_path);
9867               gtk_tree_path_free (cursor_path);
9868
9869               gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model, &child_iter, &iter);
9870
9871               new_path = _gtk_file_system_model_get_path (impl->browse_files_model, &child_iter);
9872               new_info = _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
9873               if (new_info)
9874                 new_display_name = gtk_file_info_get_display_name (new_info);
9875             }
9876         }
9877       else if (impl->operation_mode == OPERATION_MODE_SEARCH)
9878         {
9879           GtkTreeIter iter;
9880
9881           gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->search_model_filter),
9882                                    &iter, cursor_path);
9883           gtk_tree_path_free (cursor_path);
9884
9885           gtk_tree_model_filter_convert_iter_to_child_iter (impl->search_model_filter,
9886                                                             &child_iter, &iter);
9887           gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &child_iter,
9888                               SEARCH_MODEL_COL_PATH, &new_path,
9889                               SEARCH_MODEL_COL_DISPLAY_NAME, &new_display_name,
9890                               -1);
9891         }
9892       else if (impl->operation_mode == OPERATION_MODE_RECENT)
9893         {
9894           GtkTreeIter iter;
9895
9896           gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->recent_model_filter),
9897                                    &iter, cursor_path);
9898           gtk_tree_path_free (cursor_path);
9899
9900           gtk_tree_model_filter_convert_iter_to_child_iter (impl->recent_model_filter,
9901                                                             &child_iter, &iter);
9902
9903           gtk_tree_model_get (GTK_TREE_MODEL (impl->recent_model), &child_iter,
9904                               RECENT_MODEL_COL_PATH, &new_path,
9905                               RECENT_MODEL_COL_DISPLAY_NAME, &new_display_name,
9906                               -1);
9907         }
9908     }
9909
9910   if (new_path != impl->preview_path &&
9911       !(new_path && impl->preview_path &&
9912         gtk_file_path_compare (new_path, impl->preview_path) == 0))
9913     {
9914       if (impl->preview_path)
9915         {
9916           gtk_file_path_free (impl->preview_path);
9917           g_free (impl->preview_display_name);
9918         }
9919
9920       if (new_path)
9921         {
9922           impl->preview_path = gtk_file_path_copy (new_path);
9923           impl->preview_display_name = g_strdup (new_display_name);
9924         }
9925       else
9926         {
9927           impl->preview_path = NULL;
9928           impl->preview_display_name = NULL;
9929         }
9930
9931       if (impl->use_preview_label && impl->preview_label)
9932         gtk_label_set_text (GTK_LABEL (impl->preview_label), impl->preview_display_name);
9933
9934       g_signal_emit_by_name (impl, "update-preview");
9935     }
9936 }
9937
9938 static void
9939 shortcuts_activate_volume_mount_cb (GtkFileSystemHandle *handle,
9940                                     GtkFileSystemVolume *volume,
9941                                     const GError        *error,
9942                                     gpointer             data)
9943 {
9944   GtkFilePath *path;
9945   gboolean cancelled = handle->cancelled;
9946   GtkFileChooserDefault *impl = data;
9947
9948   if (handle != impl->shortcuts_activate_iter_handle)
9949     goto out;
9950
9951   impl->shortcuts_activate_iter_handle = NULL;
9952
9953   set_busy_cursor (impl, FALSE);
9954
9955   if (cancelled)
9956     goto out;
9957
9958   if (error)
9959     {
9960       char *msg;
9961
9962       msg = g_strdup_printf (_("Could not mount %s"),
9963                              gtk_file_system_volume_get_display_name (impl->file_system, volume));
9964       error_message (impl, msg, error->message);
9965       g_free (msg);
9966
9967       goto out;
9968     }
9969
9970   path = gtk_file_system_volume_get_base_path (impl->file_system, volume);
9971   if (path != NULL)
9972     {
9973       change_folder_and_display_error (impl, path, FALSE);
9974       focus_browse_tree_view_if_possible (impl);
9975       
9976       gtk_file_path_free (path);
9977     }
9978
9979 out:
9980   g_object_unref (impl);
9981   g_object_unref (handle);
9982 }
9983
9984
9985 /* Activates a volume by mounting it if necessary and then switching to its
9986  * base path.
9987  */
9988 static void
9989 shortcuts_activate_volume (GtkFileChooserDefault *impl,
9990                            GtkFileSystemVolume   *volume)
9991 {
9992   GtkFilePath *path;
9993
9994   switch (impl->operation_mode)
9995     {
9996     case OPERATION_MODE_BROWSE:
9997       break;
9998     case OPERATION_MODE_SEARCH:
9999       search_switch_to_browse_mode (impl);
10000       break;
10001     case OPERATION_MODE_RECENT:
10002       recent_switch_to_browse_mode (impl);
10003       break;
10004     }
10005
10006   /* We ref the file chooser since volume_mount() may run a main loop, and the
10007    * user could close the file chooser window in the meantime.
10008    */
10009   g_object_ref (impl);
10010
10011   if (!gtk_file_system_volume_get_is_mounted (impl->file_system, volume))
10012     {
10013       set_busy_cursor (impl, TRUE);
10014
10015       impl->shortcuts_activate_iter_handle =
10016         gtk_file_system_volume_mount (impl->file_system, volume,
10017                                       shortcuts_activate_volume_mount_cb,
10018                                       g_object_ref (impl));
10019     }
10020   else
10021     {
10022       path = gtk_file_system_volume_get_base_path (impl->file_system, volume);
10023       if (path != NULL)
10024         {
10025           change_folder_and_display_error (impl, path, FALSE);
10026           gtk_file_path_free (path);
10027         }
10028     }
10029
10030   g_object_unref (impl);
10031 }
10032
10033 /* Opens the folder or volume at the specified iter in the shortcuts model */
10034 struct ShortcutsActivateData
10035 {
10036   GtkFileChooserDefault *impl;
10037   GtkFilePath *path;
10038 };
10039
10040 static void
10041 shortcuts_activate_get_info_cb (GtkFileSystemHandle *handle,
10042                                 const GtkFileInfo   *info,
10043                                 const GError        *error,
10044                                 gpointer             user_data)
10045 {
10046   gboolean cancelled = handle->cancelled;
10047   struct ShortcutsActivateData *data = user_data;
10048
10049   if (handle != data->impl->shortcuts_activate_iter_handle)
10050     goto out;
10051
10052   data->impl->shortcuts_activate_iter_handle = NULL;
10053
10054   if (cancelled)
10055     goto out;
10056
10057   if (!error && gtk_file_info_get_is_folder (info))
10058     {
10059       change_folder_and_display_error (data->impl, data->path, FALSE);
10060       focus_browse_tree_view_if_possible (data->impl);
10061     }
10062   else
10063     gtk_file_chooser_default_select_path (GTK_FILE_CHOOSER (data->impl),
10064                                           data->path,
10065                                           NULL);
10066
10067 out:
10068   g_object_unref (data->impl);
10069   gtk_file_path_free (data->path);
10070   g_free (data);
10071
10072   g_object_unref (handle);
10073 }
10074
10075 static void
10076 shortcuts_activate_iter (GtkFileChooserDefault *impl,
10077                          GtkTreeIter           *iter)
10078 {
10079   gpointer col_data;
10080   ShortcutType shortcut_type;
10081
10082   if (impl->location_mode == LOCATION_MODE_FILENAME_ENTRY && impl->action != GTK_FILE_CHOOSER_ACTION_SAVE)
10083     _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), "");
10084
10085   gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), iter,
10086                       SHORTCUTS_COL_DATA, &col_data,
10087                       SHORTCUTS_COL_TYPE, &shortcut_type,
10088                       -1);
10089
10090   if (impl->shortcuts_activate_iter_handle)
10091     {
10092       gtk_file_system_cancel_operation (impl->shortcuts_activate_iter_handle);
10093       impl->shortcuts_activate_iter_handle = NULL;
10094     }
10095
10096   if (shortcut_type == SHORTCUT_TYPE_SEPARATOR)
10097     return;
10098   else if (shortcut_type == SHORTCUT_TYPE_VOLUME)
10099     {
10100       GtkFileSystemVolume *volume;
10101
10102       volume = col_data;
10103
10104       shortcuts_activate_volume (impl, volume);
10105     }
10106   else if (shortcut_type == SHORTCUT_TYPE_PATH)
10107     {
10108       struct ShortcutsActivateData *data;
10109
10110       data = g_new0 (struct ShortcutsActivateData, 1);
10111       data->impl = g_object_ref (impl);
10112       data->path = gtk_file_path_copy (col_data);
10113
10114       impl->shortcuts_activate_iter_handle =
10115         gtk_file_system_get_info (impl->file_system, data->path,
10116                                   GTK_FILE_INFO_IS_FOLDER,
10117                                   shortcuts_activate_get_info_cb, data);
10118     }
10119   else if (shortcut_type == SHORTCUT_TYPE_SEARCH)
10120     {
10121       search_activate (impl);
10122     }
10123   else if (shortcut_type == SHORTCUT_TYPE_RECENT)
10124     {
10125       recent_activate (impl);
10126     }
10127 }
10128
10129 /* Callback used when a row in the shortcuts list is activated */
10130 static void
10131 shortcuts_row_activated_cb (GtkTreeView           *tree_view,
10132                             GtkTreePath           *path,
10133                             GtkTreeViewColumn     *column,
10134                             GtkFileChooserDefault *impl)
10135 {
10136   GtkTreeIter iter;
10137   GtkTreeIter child_iter;
10138
10139   if (!gtk_tree_model_get_iter (impl->shortcuts_pane_filter_model, &iter, path))
10140     return;
10141
10142   gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (impl->shortcuts_pane_filter_model),
10143                                                     &child_iter,
10144                                                     &iter);
10145   shortcuts_activate_iter (impl, &child_iter);
10146 }
10147
10148 /* Handler for GtkWidget::key-press-event on the shortcuts list */
10149 static gboolean
10150 shortcuts_key_press_event_cb (GtkWidget             *widget,
10151                               GdkEventKey           *event,
10152                               GtkFileChooserDefault *impl)
10153 {
10154   guint modifiers;
10155
10156   modifiers = gtk_accelerator_get_default_mod_mask ();
10157
10158   if ((event->keyval == GDK_BackSpace
10159       || event->keyval == GDK_Delete
10160       || event->keyval == GDK_KP_Delete)
10161       && (event->state & modifiers) == 0)
10162     {
10163       remove_selected_bookmarks (impl);
10164       return TRUE;
10165     }
10166
10167   if ((event->keyval == GDK_F2)
10168       && (event->state & modifiers) == 0)
10169     {
10170       rename_selected_bookmark (impl);
10171       return TRUE;
10172     }
10173
10174   return FALSE;
10175 }
10176
10177 static gboolean
10178 shortcuts_select_func  (GtkTreeSelection  *selection,
10179                         GtkTreeModel      *model,
10180                         GtkTreePath       *path,
10181                         gboolean           path_currently_selected,
10182                         gpointer           data)
10183 {
10184   GtkFileChooserDefault *impl = data;
10185   GtkTreeIter filter_iter;
10186   ShortcutType shortcut_type;
10187
10188   if (!gtk_tree_model_get_iter (impl->shortcuts_pane_filter_model, &filter_iter, path))
10189     g_assert_not_reached ();
10190
10191   gtk_tree_model_get (impl->shortcuts_pane_filter_model, &filter_iter, SHORTCUTS_COL_TYPE, &shortcut_type, -1);
10192
10193   return shortcut_type != SHORTCUT_TYPE_SEPARATOR;
10194 }
10195
10196 static gboolean
10197 list_select_func  (GtkTreeSelection  *selection,
10198                    GtkTreeModel      *model,
10199                    GtkTreePath       *path,
10200                    gboolean           path_currently_selected,
10201                    gpointer           data)
10202 {
10203   GtkFileChooserDefault *impl = data;
10204
10205   if (impl->operation_mode == OPERATION_MODE_SEARCH)
10206     return TRUE;
10207
10208   if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
10209       impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
10210     {
10211       GtkTreeIter iter, child_iter;
10212       const GtkFileInfo *info;
10213
10214       if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->sort_model), &iter, path))
10215         return FALSE;
10216       
10217       gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model, &child_iter, &iter);
10218
10219       info = _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
10220
10221       if (info && !gtk_file_info_get_is_folder (info))
10222         return FALSE;
10223     }
10224     
10225   return TRUE;
10226 }
10227
10228 static void
10229 list_selection_changed (GtkTreeSelection      *selection,
10230                         GtkFileChooserDefault *impl)
10231 {
10232   /* See if we are in the new folder editable row for Save mode */
10233   if (impl->operation_mode == OPERATION_MODE_BROWSE &&
10234       impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
10235     {
10236       const GtkFileInfo *info;
10237       gboolean had_selection;
10238
10239       info = get_selected_file_info_from_file_list (impl, &had_selection);
10240       if (!had_selection)
10241         goto out; /* normal processing */
10242
10243       if (!info)
10244         return; /* We are on the editable row for New Folder */
10245     }
10246
10247  out:
10248
10249   /* TODO - Change the following functions to make them accept MODE_SEARCH */
10250   if (impl->location_entry)
10251     update_chooser_entry (impl);
10252
10253   check_preview_change (impl);
10254   bookmarks_check_add_sensitivity (impl);
10255
10256   g_signal_emit_by_name (impl, "selection-changed", 0);
10257 }
10258
10259 /* Callback used when a row in the file list is activated */
10260 static void
10261 list_row_activated (GtkTreeView           *tree_view,
10262                     GtkTreePath           *path,
10263                     GtkTreeViewColumn     *column,
10264                     GtkFileChooserDefault *impl)
10265 {
10266   GtkTreeIter iter;
10267   GtkTreeIter child_iter;
10268
10269   switch (impl->operation_mode)
10270     {
10271     case OPERATION_MODE_SEARCH:
10272       {
10273         GtkFilePath *file_path;
10274         gboolean is_folder;
10275
10276         if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->search_model_filter), &iter, path))
10277           return;
10278
10279         gtk_tree_model_filter_convert_iter_to_child_iter (impl->search_model_filter,
10280                                                           &child_iter, &iter);
10281         gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &child_iter,
10282                             SEARCH_MODEL_COL_PATH, &file_path,
10283                             SEARCH_MODEL_COL_IS_FOLDER, &is_folder,
10284                             -1);
10285         
10286         if (is_folder)
10287           {
10288             change_folder_and_display_error (impl, file_path, FALSE);
10289             return;
10290           }
10291
10292         g_signal_emit_by_name (impl, "file-activated");
10293       }
10294       break;
10295
10296     case OPERATION_MODE_RECENT:
10297       {
10298         GtkFilePath *file_path;
10299         gboolean is_folder;
10300
10301         if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->recent_model_filter), &iter, path))
10302           return;
10303         
10304         gtk_tree_model_filter_convert_iter_to_child_iter (impl->recent_model_filter,
10305                                                           &child_iter, &iter);
10306
10307         gtk_tree_model_get (GTK_TREE_MODEL (impl->recent_model), &child_iter,
10308                             RECENT_MODEL_COL_PATH, &file_path,
10309                             RECENT_MODEL_COL_IS_FOLDER, &is_folder,
10310                             -1);
10311
10312         if (is_folder)
10313           {
10314             change_folder_and_display_error (impl, file_path, FALSE);
10315             return;
10316           }
10317         
10318         g_signal_emit_by_name (impl, "file-activated");
10319       }
10320       break;
10321     
10322     case OPERATION_MODE_BROWSE:
10323       {
10324         const GtkFileInfo *info;
10325
10326         if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->sort_model), &iter, path))
10327           return;
10328         
10329         gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model,
10330                                                         &child_iter, &iter);
10331         info = _gtk_file_system_model_get_info (impl->browse_files_model,
10332                                                 &child_iter);
10333
10334         if (gtk_file_info_get_is_folder (info))
10335           {
10336             const GtkFilePath *file_path;
10337             
10338             file_path = _gtk_file_system_model_get_path (impl->browse_files_model, &child_iter);
10339             change_folder_and_display_error (impl, file_path, FALSE);
10340             return;
10341           }
10342
10343         if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
10344             impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
10345           g_signal_emit_by_name (impl, "file-activated");
10346       }
10347       break;
10348     }
10349 }
10350
10351 static void
10352 path_bar_clicked (GtkPathBar            *path_bar,
10353                   GtkFilePath           *file_path,
10354                   GtkFilePath           *child_path,
10355                   gboolean               child_is_hidden,
10356                   GtkFileChooserDefault *impl)
10357 {
10358   if (child_path)
10359     pending_select_paths_add (impl, child_path);
10360
10361   if (!change_folder_and_display_error (impl, file_path, FALSE))
10362     return;
10363
10364   /* Say we have "/foo/bar/[.baz]" and the user clicks on "bar".  We should then
10365    * show hidden files so that ".baz" appears in the file list, as it will still
10366    * be shown in the path bar: "/foo/[bar]/.baz"
10367    */
10368   if (child_is_hidden)
10369     g_object_set (impl, "show-hidden", TRUE, NULL);
10370 }
10371
10372 static const GtkFileInfo *
10373 get_list_file_info (GtkFileChooserDefault *impl,
10374                     GtkTreeIter           *iter)
10375 {
10376   GtkTreeIter child_iter;
10377
10378   gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model,
10379                                                   &child_iter,
10380                                                   iter);
10381
10382   return _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
10383 }
10384
10385 static void
10386 list_icon_data_func (GtkTreeViewColumn *tree_column,
10387                      GtkCellRenderer   *cell,
10388                      GtkTreeModel      *tree_model,
10389                      GtkTreeIter       *iter,
10390                      gpointer           data)
10391 {
10392   GtkFileChooserDefault *impl = data;
10393   GtkTreeIter child_iter;
10394   GdkPixbuf *pixbuf = NULL;
10395   gboolean sensitive = TRUE;
10396
10397   profile_start ("start", NULL);
10398   
10399   switch (impl->operation_mode)
10400     {
10401     case OPERATION_MODE_SEARCH:
10402       {
10403         GtkTreeIter child_iter;
10404
10405         gtk_tree_model_filter_convert_iter_to_child_iter (impl->search_model_filter,
10406                                                           &child_iter, iter);
10407         gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &child_iter,
10408                             SEARCH_MODEL_COL_PIXBUF, &pixbuf,
10409                             -1);
10410         sensitive = TRUE;
10411       }
10412       break;
10413
10414     case OPERATION_MODE_RECENT:
10415       {
10416         GtkTreeIter child_iter;
10417         GtkRecentInfo *info;
10418
10419         gtk_tree_model_filter_convert_iter_to_child_iter (impl->recent_model_filter,
10420                                                           &child_iter, iter);
10421
10422         gtk_tree_model_get (GTK_TREE_MODEL (impl->recent_model), &child_iter,
10423                             RECENT_MODEL_COL_INFO, &info,
10424                             -1);
10425         
10426         pixbuf = gtk_recent_info_get_icon (info, impl->icon_size);
10427         
10428         if (impl->local_only && !gtk_recent_info_is_local (info))
10429           sensitive = FALSE;
10430       }
10431       break;
10432     
10433     case OPERATION_MODE_BROWSE:
10434       {
10435         const GtkFileInfo *info;
10436         const GtkFilePath *path;
10437
10438         info = get_list_file_info (impl, iter);
10439
10440         gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model,
10441                                                         &child_iter,
10442                                                         iter);
10443         path = _gtk_file_system_model_get_path (impl->browse_files_model, &child_iter);
10444         if (path)
10445           {
10446             if (info)
10447               {
10448                 /* FIXME: NULL GError */
10449                 pixbuf = gtk_file_info_render_icon (info, GTK_WIDGET (impl),
10450                                                     impl->icon_size, NULL);
10451               }
10452           }
10453         else
10454           {
10455             /* We are on the editable row */
10456             pixbuf = NULL;
10457           }
10458
10459         if (info &&
10460             (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
10461              impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER))
10462           sensitive =  gtk_file_info_get_is_folder (info);
10463       }
10464       break;
10465     }
10466     
10467   g_object_set (cell,
10468                 "pixbuf", pixbuf,
10469                 "sensitive", sensitive,
10470                 NULL);
10471     
10472   if (pixbuf)
10473     g_object_unref (pixbuf);
10474
10475   profile_end ("end", NULL);
10476 }
10477
10478 static void
10479 list_name_data_func (GtkTreeViewColumn *tree_column,
10480                      GtkCellRenderer   *cell,
10481                      GtkTreeModel      *tree_model,
10482                      GtkTreeIter       *iter,
10483                      gpointer           data)
10484 {
10485   GtkFileChooserDefault *impl = data;
10486   const GtkFileInfo *info;
10487   gboolean sensitive;
10488
10489   if (impl->operation_mode == OPERATION_MODE_SEARCH)
10490     {
10491       GtkTreeIter child_iter;
10492       GtkFilePath *file_path;
10493       gchar *display_name, *tmp;
10494       gchar *text;
10495
10496       gtk_tree_model_filter_convert_iter_to_child_iter (impl->search_model_filter, &child_iter, iter);
10497       gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &child_iter,
10498                           SEARCH_MODEL_COL_PATH, &file_path,
10499                           SEARCH_MODEL_COL_DISPLAY_NAME, &display_name,
10500                           -1);
10501
10502       tmp = gtk_file_system_path_to_filename (impl->file_system, file_path);
10503       text = g_strdup_printf ("<b>%s</b>\n%s", display_name, tmp);
10504       g_free (tmp);
10505
10506       g_object_set (cell,
10507                     "markup", text,
10508                     "sensitive", TRUE,
10509                     "ellipsize", PANGO_ELLIPSIZE_END,
10510                     NULL);
10511       
10512       g_free (text);
10513
10514       return;
10515     }
10516
10517   if (impl->operation_mode == OPERATION_MODE_RECENT)
10518     {
10519       GtkTreeIter child_iter;
10520       GtkRecentInfo *recent_info;
10521       char *tmp, *text;
10522
10523       gtk_tree_model_filter_convert_iter_to_child_iter (impl->recent_model_filter, &child_iter, iter);
10524
10525       gtk_tree_model_get (GTK_TREE_MODEL (impl->recent_model), &child_iter,
10526                           RECENT_MODEL_COL_INFO, &recent_info,
10527                           -1);
10528       
10529       tmp = gtk_recent_info_get_short_name (recent_info);
10530       text = g_strdup_printf ("<b>%s</b>\n%s",
10531                               tmp,
10532                               gtk_recent_info_get_uri_display (recent_info));
10533       g_free (tmp);
10534
10535       g_object_set (cell,
10536                     "markup", text,
10537                     "sensitive", TRUE,
10538                     "ellipsize", PANGO_ELLIPSIZE_END,
10539                     NULL);
10540       g_free (text);
10541
10542       return;
10543     }
10544
10545   info = get_list_file_info (impl, iter);
10546   sensitive = TRUE;
10547
10548   if (!info)
10549     {
10550       g_object_set (cell,
10551                     "text", _("Type name of new folder"),
10552                     "sensitive", TRUE,
10553                     "ellipsize", PANGO_ELLIPSIZE_NONE,
10554                     NULL);
10555
10556       return;
10557     }
10558
10559
10560   if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
10561       impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
10562     {
10563       sensitive = gtk_file_info_get_is_folder (info);
10564     } 
10565     
10566   g_object_set (cell,
10567                 "text", gtk_file_info_get_display_name (info),
10568                 "sensitive", sensitive,
10569                 "ellipsize", PANGO_ELLIPSIZE_END,
10570                 NULL);
10571 }
10572
10573 #if 0
10574 static void
10575 list_size_data_func (GtkTreeViewColumn *tree_column,
10576                      GtkCellRenderer   *cell,
10577                      GtkTreeModel      *tree_model,
10578                      GtkTreeIter       *iter,
10579                      gpointer           data)
10580 {
10581   GtkFileChooserDefault *impl = data;
10582   const GtkFileInfo *info = get_list_file_info (impl, iter);
10583   gint64 size;
10584   gchar *str;
10585   gboolean sensitive = TRUE;
10586
10587   if (!info || gtk_file_info_get_is_folder (info)) 
10588     {
10589       g_object_set (cell,
10590                     "text", NULL,
10591                     "sensitive", sensitive,
10592                     NULL);
10593       return;
10594     }
10595
10596   size = gtk_file_info_get_size (info);
10597 #if 0
10598   if (size < (gint64)1024)
10599     str = g_strdup_printf (ngettext ("%d byte", "%d bytes", (gint)size), (gint)size);
10600   else if (size < (gint64)1024*1024)
10601     str = g_strdup_printf (_("%.1f KB"), size / (1024.));
10602   else if (size < (gint64)1024*1024*1024)
10603     str = g_strdup_printf (_("%.1f MB"), size / (1024.*1024.));
10604   else
10605     str = g_strdup_printf (_("%.1f GB"), size / (1024.*1024.*1024.));
10606 #endif
10607   str = g_strdup_printf ("%" G_GINT64_FORMAT, size);
10608   if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
10609       impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
10610     sensitive = FALSE;
10611
10612   g_object_set (cell,
10613                 "text", str,
10614                 "sensitive", sensitive,
10615                 "alignment", PANGO_ALIGN_RIGHT,
10616                 NULL);
10617
10618   g_free (str);
10619 }
10620 #endif
10621
10622 /* Tree column data callback for the file list; fetches the mtime of a file */
10623 static void
10624 list_mtime_data_func (GtkTreeViewColumn *tree_column,
10625                       GtkCellRenderer   *cell,
10626                       GtkTreeModel      *tree_model,
10627                       GtkTreeIter       *iter,
10628                       gpointer           data)
10629 {
10630   GtkFileChooserDefault *impl;
10631   GtkFileTime time_mtime;
10632   GDate mtime, now;
10633   int days_diff;
10634   char buf[256];
10635   gboolean sensitive = TRUE;
10636
10637   impl = data;
10638
10639   if (impl->operation_mode == OPERATION_MODE_SEARCH)
10640     {
10641       GtkTreeIter child_iter;
10642       struct stat *statbuf;
10643
10644       gtk_tree_model_filter_convert_iter_to_child_iter (impl->search_model_filter, &child_iter, iter);
10645       gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &child_iter,
10646                           SEARCH_MODEL_COL_STAT, &statbuf,
10647                           -1);
10648       time_mtime = statbuf->st_mtime;
10649     }
10650   else if (impl->operation_mode == OPERATION_MODE_RECENT)
10651     {
10652       GtkTreeIter child_iter;
10653       GtkRecentInfo *info;
10654
10655       gtk_tree_model_filter_convert_iter_to_child_iter (impl->recent_model_filter, &child_iter, iter);
10656       gtk_tree_model_get (GTK_TREE_MODEL (impl->recent_model), &child_iter,
10657                           RECENT_MODEL_COL_INFO, &info,
10658                           -1);
10659       time_mtime = (GtkFileTime) gtk_recent_info_get_modified (info);
10660
10661       if (impl->local_only && !gtk_recent_info_is_local (info))
10662         sensitive = FALSE;
10663     }
10664   else
10665     {
10666       const GtkFileInfo *info;
10667
10668       info = get_list_file_info (impl, iter);
10669       if (!info)
10670         {
10671           g_object_set (cell,
10672                         "text", "",
10673                         "sensitive", TRUE,
10674                         NULL);
10675           return;
10676         }
10677
10678       time_mtime = gtk_file_info_get_modification_time (info);
10679
10680       if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
10681           impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
10682         sensitive = gtk_file_info_get_is_folder (info);
10683     }
10684
10685   if (time_mtime == 0)
10686     strcpy (buf, _("Unknown"));
10687   else
10688     {
10689       time_t time_now;
10690       g_date_set_time_t (&mtime, time_mtime);
10691       time_now = time (NULL);
10692       g_date_set_time_t (&now, time_now);
10693
10694       days_diff = g_date_get_julian (&now) - g_date_get_julian (&mtime);
10695
10696       if (days_diff == 0)
10697         strcpy (buf, _("Today"));
10698       else if (days_diff == 1)
10699         strcpy (buf, _("Yesterday"));
10700       else
10701         {
10702           char *format;
10703
10704           if (days_diff > 1 && days_diff < 7)
10705             format = "%A"; /* Days from last week */
10706           else
10707             format = "%x"; /* Any other date */
10708
10709           if (g_date_strftime (buf, sizeof (buf), format, &mtime) == 0)
10710             strcpy (buf, _("Unknown"));
10711         }
10712     }
10713
10714   g_object_set (cell,
10715                 "text", buf,
10716                 "sensitive", sensitive,
10717                 NULL);
10718 }
10719
10720 GtkWidget *
10721 _gtk_file_chooser_default_new (const char *file_system)
10722 {
10723   return  g_object_new (GTK_TYPE_FILE_CHOOSER_DEFAULT,
10724                         "file-system-backend", file_system,
10725                         NULL);
10726 }
10727
10728 static void
10729 location_set_user_text (GtkFileChooserDefault *impl,
10730                         const gchar           *path)
10731 {
10732   _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), path);
10733   gtk_editable_set_position (GTK_EDITABLE (impl->location_entry), -1);
10734 }
10735
10736 static void
10737 location_popup_handler (GtkFileChooserDefault *impl,
10738                         const gchar           *path)
10739
10740   if (impl->operation_mode != OPERATION_MODE_BROWSE)
10741     {
10742       GtkWidget *widget_to_focus;
10743       
10744       /* This will give us the location widgets back */
10745       switch (impl->operation_mode)
10746         {
10747         case OPERATION_MODE_SEARCH:
10748           search_switch_to_browse_mode (impl);
10749           break;
10750         case OPERATION_MODE_RECENT:
10751           recent_switch_to_browse_mode (impl);
10752           break;
10753         case OPERATION_MODE_BROWSE:
10754           g_assert_not_reached ();
10755           break;
10756         }
10757
10758       if (impl->current_folder)
10759         change_folder_and_display_error (impl, impl->current_folder, FALSE);
10760
10761       if (impl->location_mode == LOCATION_MODE_PATH_BAR)
10762         widget_to_focus = impl->browse_files_tree_view;
10763       else
10764         widget_to_focus = impl->location_entry;
10765
10766       gtk_widget_grab_focus (widget_to_focus);
10767       return; 
10768     }
10769   
10770   if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
10771       impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
10772     {
10773       LocationMode new_mode;
10774
10775       if (path != NULL)
10776         {
10777           /* since the user typed something, we unconditionally want to turn on the entry */
10778           new_mode = LOCATION_MODE_FILENAME_ENTRY;
10779         }
10780       else if (impl->location_mode == LOCATION_MODE_PATH_BAR)
10781         new_mode = LOCATION_MODE_FILENAME_ENTRY;
10782       else if (impl->location_mode == LOCATION_MODE_FILENAME_ENTRY)
10783         new_mode = LOCATION_MODE_PATH_BAR;
10784       else
10785         {
10786           g_assert_not_reached ();
10787           return;
10788         }
10789
10790       location_mode_set (impl, new_mode, TRUE);
10791       if (new_mode == LOCATION_MODE_FILENAME_ENTRY)
10792         {
10793           if (path != NULL)
10794             location_set_user_text (impl, path);
10795           else
10796             {
10797               location_entry_set_initial_text (impl);
10798               gtk_editable_select_region (GTK_EDITABLE (impl->location_entry), 0, -1);
10799             }
10800         }
10801     }
10802   else if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE ||
10803            impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
10804     {
10805       gtk_widget_grab_focus (impl->location_entry);
10806       if (path != NULL)
10807         location_set_user_text (impl, path);
10808     }
10809   else
10810     g_assert_not_reached ();
10811 }
10812
10813 /* Handler for the "up-folder" keybinding signal */
10814 static void
10815 up_folder_handler (GtkFileChooserDefault *impl)
10816 {
10817   _gtk_path_bar_up (GTK_PATH_BAR (impl->browse_path_bar));
10818 }
10819
10820 /* Handler for the "down-folder" keybinding signal */
10821 static void
10822 down_folder_handler (GtkFileChooserDefault *impl)
10823 {
10824   _gtk_path_bar_down (GTK_PATH_BAR (impl->browse_path_bar));
10825 }
10826
10827 /* Switches to the shortcut in the specified index */
10828 static void
10829 switch_to_shortcut (GtkFileChooserDefault *impl,
10830                     int pos)
10831 {
10832   GtkTreeIter iter;
10833
10834   if (!gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (impl->shortcuts_model), &iter, NULL, pos))
10835     g_assert_not_reached ();
10836
10837   shortcuts_activate_iter (impl, &iter);
10838   focus_browse_tree_view_if_possible (impl);
10839 }
10840
10841 /* Handler for the "home-folder" keybinding signal */
10842 static void
10843 home_folder_handler (GtkFileChooserDefault *impl)
10844 {
10845   if (impl->has_home)
10846     switch_to_shortcut (impl, shortcuts_get_index (impl, SHORTCUTS_HOME));
10847 }
10848
10849 /* Handler for the "desktop-folder" keybinding signal */
10850 static void
10851 desktop_folder_handler (GtkFileChooserDefault *impl)
10852 {
10853   if (impl->has_desktop)
10854     switch_to_shortcut (impl, shortcuts_get_index (impl, SHORTCUTS_DESKTOP));
10855 }
10856
10857 /* Handler for the "search-shortcut" keybinding signal */
10858 static void
10859 search_shortcut_handler (GtkFileChooserDefault *impl)
10860 {
10861   if (impl->has_search)
10862     {
10863       switch_to_shortcut (impl, shortcuts_get_index (impl, SHORTCUTS_SEARCH));
10864
10865       /* we want the entry widget to grab the focus the first
10866        * time, not the browse_files_tree_view widget.
10867        */
10868       if (impl->search_entry)
10869         gtk_widget_grab_focus (impl->search_entry);
10870     }
10871 }
10872
10873 /* Handler for the "recent-shortcut" keybinding signal */
10874 static void
10875 recent_shortcut_handler (GtkFileChooserDefault *impl)
10876 {
10877   if (impl->has_recent)
10878     switch_to_shortcut (impl, shortcuts_get_index (impl, SHORTCUTS_RECENT));
10879 }
10880
10881 static void
10882 quick_bookmark_handler (GtkFileChooserDefault *impl,
10883                         gint bookmark_index)
10884 {
10885   int bookmark_pos;
10886   GtkTreePath *path;
10887
10888   if (bookmark_index < 0 || bookmark_index >= impl->num_bookmarks)
10889     return;
10890
10891   bookmark_pos = shortcuts_get_index (impl, SHORTCUTS_BOOKMARKS) + bookmark_index;
10892
10893   path = gtk_tree_path_new_from_indices (bookmark_pos, -1);
10894   gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view),
10895                                 path, NULL,
10896                                 FALSE, 0.0, 0.0);
10897   gtk_tree_path_free (path);
10898
10899   switch_to_shortcut (impl, bookmark_pos);
10900 }
10901
10902 static void
10903 show_hidden_handler (GtkFileChooserDefault *impl)
10904 {
10905   g_object_set (impl,
10906                 "show-hidden", !impl->show_hidden,
10907                 NULL);
10908 }
10909
10910
10911 /* Drag and drop interfaces */
10912
10913 static void
10914 _shortcuts_pane_model_filter_class_init (ShortcutsPaneModelFilterClass *class)
10915 {
10916 }
10917
10918 static void
10919 _shortcuts_pane_model_filter_init (ShortcutsPaneModelFilter *model)
10920 {
10921   model->impl = NULL;
10922 }
10923
10924 /* GtkTreeDragSource::row_draggable implementation for the shortcuts filter model */
10925 static gboolean
10926 shortcuts_pane_model_filter_row_draggable (GtkTreeDragSource *drag_source,
10927                                            GtkTreePath       *path)
10928 {
10929   ShortcutsPaneModelFilter *model;
10930   int pos;
10931   int bookmarks_pos;
10932
10933   model = SHORTCUTS_PANE_MODEL_FILTER (drag_source);
10934
10935   pos = *gtk_tree_path_get_indices (path);
10936   bookmarks_pos = shortcuts_get_index (model->impl, SHORTCUTS_BOOKMARKS);
10937
10938   return (pos >= bookmarks_pos && pos < bookmarks_pos + model->impl->num_bookmarks);
10939 }
10940
10941 /* GtkTreeDragSource::drag_data_get implementation for the shortcuts filter model */
10942 static gboolean
10943 shortcuts_pane_model_filter_drag_data_get (GtkTreeDragSource *drag_source,
10944                                            GtkTreePath       *path,
10945                                            GtkSelectionData  *selection_data)
10946 {
10947   ShortcutsPaneModelFilter *model;
10948
10949   model = SHORTCUTS_PANE_MODEL_FILTER (drag_source);
10950
10951   /* FIXME */
10952
10953   return FALSE;
10954 }
10955
10956 /* Fill the GtkTreeDragSourceIface vtable */
10957 static void
10958 shortcuts_pane_model_filter_drag_source_iface_init (GtkTreeDragSourceIface *iface)
10959 {
10960   iface->row_draggable = shortcuts_pane_model_filter_row_draggable;
10961   iface->drag_data_get = shortcuts_pane_model_filter_drag_data_get;
10962 }
10963
10964 #if 0
10965 /* Fill the GtkTreeDragDestIface vtable */
10966 static void
10967 shortcuts_pane_model_filter_drag_dest_iface_init (GtkTreeDragDestIface *iface)
10968 {
10969   iface->drag_data_received = shortcuts_pane_model_filter_drag_data_received;
10970   iface->row_drop_possible = shortcuts_pane_model_filter_row_drop_possible;
10971 }
10972 #endif
10973
10974 static GtkTreeModel *
10975 shortcuts_pane_model_filter_new (GtkFileChooserDefault *impl,
10976                                  GtkTreeModel          *child_model,
10977                                  GtkTreePath           *root)
10978 {
10979   ShortcutsPaneModelFilter *model;
10980
10981   model = g_object_new (SHORTCUTS_PANE_MODEL_FILTER_TYPE,
10982                         "child-model", child_model,
10983                         "virtual-root", root,
10984                         NULL);
10985
10986   model->impl = impl;
10987
10988   return GTK_TREE_MODEL (model);
10989 }