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