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