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