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