summaryrefslogtreecommitdiffstats
path: root/meta/packages
diff options
context:
space:
mode:
authorTomas Frydrych <tf@openedhand.com>2008-01-04 15:51:51 +0000
committerTomas Frydrych <tf@openedhand.com>2008-01-04 15:51:51 +0000
commit9ea75153131c3bedd234ea6a7c1534093d2d9f2a (patch)
tree9ce1f2833b7a7784bcc9f9b3b2f4ec04a5290561 /meta/packages
parentfe7eb79225aa51bc919357f395564eb4f5e0e6a6 (diff)
downloadpoky-9ea75153131c3bedd234ea6a7c1534093d2d9f2a.tar.gz
ported filechooser patcheas to gtk 2.12.3
git-svn-id: https://svn.o-hand.com/repos/poky/trunk@3408 311d38ba-8fff-0310-9ca6-ca027cbcb966
Diffstat (limited to 'meta/packages')
-rw-r--r--meta/packages/gtk+/gtk+-2.12.3/filechooser-default.patch14188
-rw-r--r--meta/packages/gtk+/gtk+-2.12.3/filechooser-utils.patch32
-rw-r--r--meta/packages/gtk+/gtk+-2.12.3/filechooser.patch25
-rw-r--r--meta/packages/gtk+/gtk+-2.12.3/filesystem-volumes.patch198
-rw-r--r--meta/packages/gtk+/gtk+_2.12.3.bb19
5 files changed, 14455 insertions, 7 deletions
diff --git a/meta/packages/gtk+/gtk+-2.12.3/filechooser-default.patch b/meta/packages/gtk+/gtk+-2.12.3/filechooser-default.patch
new file mode 100644
index 0000000000..17671db0d1
--- /dev/null
+++ b/meta/packages/gtk+/gtk+-2.12.3/filechooser-default.patch
@@ -0,0 +1,14188 @@
1Index: gtk+-2.12.3/gtk/gtkfilechooserdefault.c
2===================================================================
3--- gtk+-2.12.3.orig/gtk/gtkfilechooserdefault.c 2007-12-04 16:52:08.000000000 +0000
4+++ gtk+-2.12.3/gtk/gtkfilechooserdefault.c 2008-01-04 10:11:11.000000000 +0000
5@@ -27,12 +27,12 @@
6 #include "gtkcelllayout.h"
7 #include "gtkcellrendererpixbuf.h"
8 #include "gtkcellrenderertext.h"
9+#include "gtkcellrenderertext.h"
10 #include "gtkcheckmenuitem.h"
11 #include "gtkclipboard.h"
12 #include "gtkcombobox.h"
13 #include "gtkentry.h"
14 #include "gtkeventbox.h"
15-#include "gtkexpander.h"
16 #include "gtkfilechooserprivate.h"
17 #include "gtkfilechooserdefault.h"
18 #include "gtkfilechooserembed.h"
19@@ -53,17 +53,13 @@
20 #include "gtkmarshalers.h"
21 #include "gtkmenuitem.h"
22 #include "gtkmessagedialog.h"
23-#include "gtkpathbar.h"
24 #include "gtkprivate.h"
25 #include "gtkradiobutton.h"
26-#include "gtkrecentfilter.h"
27-#include "gtkrecentmanager.h"
28 #include "gtkscrolledwindow.h"
29 #include "gtkseparatormenuitem.h"
30 #include "gtksizegroup.h"
31 #include "gtkstock.h"
32 #include "gtktable.h"
33-#include "gtktooltip.h"
34 #include "gtktreednd.h"
35 #include "gtktreeprivate.h"
36 #include "gtktreeselection.h"
37@@ -81,8 +77,6 @@
38 #include <errno.h>
39 #include <string.h>
40 #include <time.h>
41-#include <sys/stat.h>
42-#include <sys/types.h>
43
44
45 #ifdef HAVE_UNISTD_H
46@@ -92,6 +86,8 @@
47 #include <io.h>
48 #endif
49
50+#define DEFAULT_SPACING 5
51+
52 /* Profiling stuff */
53 #undef PROFILE_FILE_CHOOSER
54 #ifdef PROFILE_FILE_CHOOSER
55@@ -102,6 +98,7 @@
56 #endif
57
58 #define PROFILE_INDENT 4
59+
60 static int profile_indent;
61
62 static void
63@@ -141,8 +138,6 @@
64 #define profile_msg(x, y)
65 #endif
66
67-
68-
69 typedef struct _GtkFileChooserDefaultClass GtkFileChooserDefaultClass;
70
71 #define GTK_FILE_CHOOSER_DEFAULT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_FILE_CHOOSER_DEFAULT, GtkFileChooserDefaultClass))
72@@ -150,6 +145,7 @@
73 #define GTK_FILE_CHOOSER_DEFAULT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_FILE_CHOOSER_DEFAULT, GtkFileChooserDefaultClass))
74
75 #define MAX_LOADING_TIME 500
76+#define LONG_CLICK_LENGTH 500
77
78 struct _GtkFileChooserDefaultClass
79 {
80@@ -163,38 +159,12 @@
81 UP_FOLDER,
82 DOWN_FOLDER,
83 HOME_FOLDER,
84- DESKTOP_FOLDER,
85- QUICK_BOOKMARK,
86- LOCATION_TOGGLE_POPUP,
87 SHOW_HIDDEN,
88- SEARCH_SHORTCUT,
89- RECENT_SHORTCUT,
90-
91 LAST_SIGNAL
92 };
93
94 static guint signals[LAST_SIGNAL] = { 0 };
95
96-/* Column numbers for the shortcuts tree. Keep these in sync with shortcuts_model_create() */
97-enum {
98- SHORTCUTS_COL_PIXBUF,
99- SHORTCUTS_COL_NAME,
100- SHORTCUTS_COL_DATA,
101- SHORTCUTS_COL_TYPE,
102- SHORTCUTS_COL_REMOVABLE,
103- SHORTCUTS_COL_PIXBUF_VISIBLE,
104- SHORTCUTS_COL_HANDLE,
105- SHORTCUTS_COL_NUM_COLUMNS
106-};
107-
108-typedef enum {
109- SHORTCUT_TYPE_PATH,
110- SHORTCUT_TYPE_VOLUME,
111- SHORTCUT_TYPE_SEPARATOR,
112- SHORTCUT_TYPE_SEARCH,
113- SHORTCUT_TYPE_RECENT
114-} ShortcutType;
115-
116 /* Column numbers for the file list */
117 enum {
118 FILE_LIST_COL_NAME,
119@@ -203,100 +173,10 @@
120 FILE_LIST_COL_NUM_COLUMNS
121 };
122
123-/* Column numbers for the search model.
124- * Keep this in sync with search_setup_model()
125- */
126-enum {
127- SEARCH_MODEL_COL_PATH,
128- SEARCH_MODEL_COL_DISPLAY_NAME,
129- SEARCH_MODEL_COL_COLLATION_KEY,
130- SEARCH_MODEL_COL_STAT,
131- SEARCH_MODEL_COL_HANDLE,
132- SEARCH_MODEL_COL_PIXBUF,
133- SEARCH_MODEL_COL_MIME_TYPE,
134- SEARCH_MODEL_COL_IS_FOLDER,
135- SEARCH_MODEL_COL_NUM_COLUMNS
136-};
137-
138-enum {
139- RECENT_MODEL_COL_PATH,
140- RECENT_MODEL_COL_DISPLAY_NAME,
141- RECENT_MODEL_COL_INFO,
142- RECENT_MODEL_COL_IS_FOLDER,
143- RECENT_MODEL_COL_HANDLE,
144- RECENT_MODEL_COL_NUM_COLUMNS
145-};
146-
147-/* Identifiers for target types */
148-enum {
149- GTK_TREE_MODEL_ROW,
150- TEXT_URI_LIST
151-};
152-
153-/* Target types for dragging from the shortcuts list */
154-static const GtkTargetEntry shortcuts_source_targets[] = {
155- { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, GTK_TREE_MODEL_ROW }
156-};
157-
158-static const int num_shortcuts_source_targets = G_N_ELEMENTS (shortcuts_source_targets);
159-
160-/* Target types for dropping into the shortcuts list */
161-static const GtkTargetEntry shortcuts_dest_targets[] = {
162- { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, GTK_TREE_MODEL_ROW },
163- { "text/uri-list", 0, TEXT_URI_LIST }
164-};
165-
166-static const int num_shortcuts_dest_targets = G_N_ELEMENTS (shortcuts_dest_targets);
167-
168-/* Target types for DnD from the file list */
169-static const GtkTargetEntry file_list_source_targets[] = {
170- { "text/uri-list", 0, TEXT_URI_LIST }
171-};
172-
173-static const int num_file_list_source_targets = G_N_ELEMENTS (file_list_source_targets);
174-
175-/* Target types for dropping into the file list */
176-static const GtkTargetEntry file_list_dest_targets[] = {
177- { "text/uri-list", 0, TEXT_URI_LIST }
178-};
179-
180-static const int num_file_list_dest_targets = G_N_ELEMENTS (file_list_dest_targets);
181-
182-/* Target types for dragging from the recent files list */
183-static const GtkTargetEntry recent_list_source_targets[] = {
184- { "text/uri-list", 0, TEXT_URI_LIST }
185-};
186-
187-static const int num_recent_list_source_targets = G_N_ELEMENTS (recent_list_source_targets);
188-
189-static gboolean
190-search_is_possible (GtkFileChooserDefault *impl)
191-{
192- if (impl->search_engine == NULL)
193- impl->search_engine = _gtk_search_engine_new ();
194-
195- return impl->search_engine != NULL;
196-}
197-
198-/* Interesting places in the shortcuts bar */
199-typedef enum {
200- SHORTCUTS_SEARCH,
201- SHORTCUTS_RECENT,
202- SHORTCUTS_RECENT_SEPARATOR,
203- SHORTCUTS_HOME,
204- SHORTCUTS_DESKTOP,
205- SHORTCUTS_VOLUMES,
206- SHORTCUTS_SHORTCUTS,
207- SHORTCUTS_BOOKMARKS_SEPARATOR,
208- SHORTCUTS_BOOKMARKS,
209- SHORTCUTS_CURRENT_FOLDER_SEPARATOR,
210- SHORTCUTS_CURRENT_FOLDER
211-} ShortcutsIndex;
212-
213 /* Icon size for if we can't get it from the theme */
214-#define FALLBACK_ICON_SIZE 16
215+#define FALLBACK_ICON_SIZE 24
216
217-#define PREVIEW_HBOX_SPACING 12
218+#define LIST_HBOX_SPACING DEFAULT_SPACING
219 #define NUM_LINES 45
220 #define NUM_CHARS 60
221
222@@ -361,7 +241,6 @@
223 const GtkFilePath *path,
224 GError **error);
225 static GSList * gtk_file_chooser_default_list_shortcut_folders (GtkFileChooser *chooser);
226-
227 static void gtk_file_chooser_default_get_default_size (GtkFileChooserEmbed *chooser_embed,
228 gint *default_width,
229 gint *default_height);
230@@ -369,52 +248,17 @@
231 static gboolean gtk_file_chooser_default_should_respond (GtkFileChooserEmbed *chooser_embed);
232 static void gtk_file_chooser_default_initial_focus (GtkFileChooserEmbed *chooser_embed);
233
234-static void location_popup_handler (GtkFileChooserDefault *impl,
235- const gchar *path);
236-static void location_popup_on_paste_handler (GtkFileChooserDefault *impl);
237-static void location_toggle_popup_handler (GtkFileChooserDefault *impl);
238-static void up_folder_handler (GtkFileChooserDefault *impl);
239-static void down_folder_handler (GtkFileChooserDefault *impl);
240-static void home_folder_handler (GtkFileChooserDefault *impl);
241-static void desktop_folder_handler (GtkFileChooserDefault *impl);
242-static void quick_bookmark_handler (GtkFileChooserDefault *impl,
243- gint bookmark_index);
244-static void show_hidden_handler (GtkFileChooserDefault *impl);
245-static void search_shortcut_handler (GtkFileChooserDefault *impl);
246-static void recent_shortcut_handler (GtkFileChooserDefault *impl);
247-static void update_appearance (GtkFileChooserDefault *impl);
248-
249-static void set_current_filter (GtkFileChooserDefault *impl,
250- GtkFileFilter *filter);
251-static void check_preview_change (GtkFileChooserDefault *impl);
252+static void up_folder_handler (GtkFileChooserDefault *impl);
253+static void down_folder_handler (GtkFileChooserDefault *impl);
254+static void home_folder_handler (GtkFileChooserDefault *impl);
255+static void show_hidden_handler (GtkFileChooserDefault *impl);
256+static void update_appearance (GtkFileChooserDefault *impl);
257
258 static void filter_combo_changed (GtkComboBox *combo_box,
259 GtkFileChooserDefault *impl);
260-static void shortcuts_row_activated_cb (GtkTreeView *tree_view,
261- GtkTreePath *path,
262- GtkTreeViewColumn *column,
263- GtkFileChooserDefault *impl);
264-
265-static gboolean shortcuts_key_press_event_cb (GtkWidget *widget,
266- GdkEventKey *event,
267- GtkFileChooserDefault *impl);
268-
269-static gboolean shortcuts_select_func (GtkTreeSelection *selection,
270- GtkTreeModel *model,
271- GtkTreePath *path,
272- gboolean path_currently_selected,
273- gpointer data);
274-static gboolean shortcuts_get_selected (GtkFileChooserDefault *impl,
275- GtkTreeIter *iter);
276-static void shortcuts_activate_iter (GtkFileChooserDefault *impl,
277- GtkTreeIter *iter);
278-static int shortcuts_get_index (GtkFileChooserDefault *impl,
279- ShortcutsIndex where);
280-static int shortcut_find_position (GtkFileChooserDefault *impl,
281- const GtkFilePath *path);
282-
283-static void bookmarks_check_add_sensitivity (GtkFileChooserDefault *impl);
284
285+static void set_current_filter (GtkFileChooserDefault *impl,
286+ GtkFileFilter *filter);
287 static gboolean list_select_func (GtkTreeSelection *selection,
288 GtkTreeModel *model,
289 GtkTreePath *path,
290@@ -433,19 +277,6 @@
291 GtkTreeIter *iter,
292 gpointer user_data);
293
294-static void path_bar_clicked (GtkPathBar *path_bar,
295- GtkFilePath *file_path,
296- GtkFilePath *child_path,
297- gboolean child_is_hidden,
298- GtkFileChooserDefault *impl);
299-
300-static void add_bookmark_button_clicked_cb (GtkButton *button,
301- GtkFileChooserDefault *impl);
302-static void remove_bookmark_button_clicked_cb (GtkButton *button,
303- GtkFileChooserDefault *impl);
304-static void save_folder_combo_changed_cb (GtkComboBox *combo,
305- GtkFileChooserDefault *impl);
306-
307 static void list_icon_data_func (GtkTreeViewColumn *tree_column,
308 GtkCellRenderer *cell,
309 GtkTreeModel *tree_model,
310@@ -477,114 +308,7 @@
311
312 static void location_button_toggled_cb (GtkToggleButton *toggle,
313 GtkFileChooserDefault *impl);
314-static void location_switch_to_path_bar (GtkFileChooserDefault *impl);
315-
316-static void search_stop_searching (GtkFileChooserDefault *impl,
317- gboolean remove_query);
318-static void search_clear_model (GtkFileChooserDefault *impl,
319- gboolean remove_from_treeview);
320-static gboolean search_should_respond (GtkFileChooserDefault *impl);
321-static void search_switch_to_browse_mode (GtkFileChooserDefault *impl);
322-static GSList *search_get_selected_paths (GtkFileChooserDefault *impl);
323-static void search_entry_activate_cb (GtkEntry *entry,
324- gpointer data);
325-static void settings_load (GtkFileChooserDefault *impl);
326-static void search_get_valid_child_iter (GtkFileChooserDefault *impl,
327- GtkTreeIter *child_iter,
328- GtkTreeIter *iter);
329-
330-static void recent_manager_update (GtkFileChooserDefault *impl);
331-static void recent_stop_loading (GtkFileChooserDefault *impl);
332-static void recent_clear_model (GtkFileChooserDefault *impl,
333- gboolean remove_from_treeview);
334-static gboolean recent_should_respond (GtkFileChooserDefault *impl);
335-static void recent_switch_to_browse_mode (GtkFileChooserDefault *impl);
336-static GSList * recent_get_selected_paths (GtkFileChooserDefault *impl);
337-static void recent_get_valid_child_iter (GtkFileChooserDefault *impl,
338- GtkTreeIter *child_iter,
339- GtkTreeIter *iter);
340-
341-
342-
343-
344-/* Drag and drop interface declarations */
345-
346-typedef struct {
347- GtkTreeModelFilter parent;
348-
349- GtkFileChooserDefault *impl;
350-} ShortcutsPaneModelFilter;
351-
352-typedef struct {
353- GtkTreeModelFilterClass parent_class;
354-} ShortcutsPaneModelFilterClass;
355-
356-#define SHORTCUTS_PANE_MODEL_FILTER_TYPE (_shortcuts_pane_model_filter_get_type ())
357-#define SHORTCUTS_PANE_MODEL_FILTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SHORTCUTS_PANE_MODEL_FILTER_TYPE, ShortcutsPaneModelFilter))
358-
359-static void shortcuts_pane_model_filter_drag_source_iface_init (GtkTreeDragSourceIface *iface);
360-
361-G_DEFINE_TYPE_WITH_CODE (ShortcutsPaneModelFilter,
362- _shortcuts_pane_model_filter,
363- GTK_TYPE_TREE_MODEL_FILTER,
364- G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_SOURCE,
365- shortcuts_pane_model_filter_drag_source_iface_init))
366-
367-static GtkTreeModel *shortcuts_pane_model_filter_new (GtkFileChooserDefault *impl,
368- GtkTreeModel *child_model,
369- GtkTreePath *root);
370-
371-
372-typedef struct {
373- GtkTreeModelSort parent;
374-
375- GtkFileChooserDefault *impl;
376-} RecentModelSort;
377-
378-typedef struct {
379- GtkTreeModelSortClass parent_class;
380-} RecentModelSortClass;
381-
382-#define RECENT_MODEL_SORT_TYPE (_recent_model_sort_get_type ())
383-#define RECENT_MODEL_SORT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), RECENT_MODEL_SORT_TYPE, RecentModelSort))
384-
385-static void recent_model_sort_drag_source_iface_init (GtkTreeDragSourceIface *iface);
386-
387-G_DEFINE_TYPE_WITH_CODE (RecentModelSort,
388- _recent_model_sort,
389- GTK_TYPE_TREE_MODEL_SORT,
390- G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_SOURCE,
391- recent_model_sort_drag_source_iface_init));
392-
393-static GtkTreeModel *recent_model_sort_new (GtkFileChooserDefault *impl,
394- GtkTreeModel *child_model);
395-
396-
397-typedef struct {
398- GtkTreeModelSort parent;
399-
400- GtkFileChooserDefault *impl;
401-} SearchModelSort;
402-
403-typedef struct {
404- GtkTreeModelSortClass parent_class;
405-} SearchModelSortClass;
406-
407-#define SEARCH_MODEL_SORT_TYPE (_search_model_sort_get_type ())
408-#define SEARCH_MODEL_SORT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEARCH_MODEL_SORT_TYPE, SearchModelSort))
409-
410-static void search_model_sort_drag_source_iface_init (GtkTreeDragSourceIface *iface);
411-
412-G_DEFINE_TYPE_WITH_CODE (SearchModelSort,
413- _search_model_sort,
414- GTK_TYPE_TREE_MODEL_SORT,
415- G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_SOURCE,
416- search_model_sort_drag_source_iface_init));
417-
418-static GtkTreeModel *search_model_sort_new (GtkFileChooserDefault *impl,
419- GtkTreeModel *child_model);
420-
421-
422+static void settings_load (GtkFileChooserDefault *impl);
423
424 G_DEFINE_TYPE_WITH_CODE (GtkFileChooserDefault, _gtk_file_chooser_default, GTK_TYPE_VBOX,
425 G_IMPLEMENT_INTERFACE (GTK_TYPE_FILE_CHOOSER,
426@@ -595,13 +319,9 @@
427 static void
428 _gtk_file_chooser_default_class_init (GtkFileChooserDefaultClass *class)
429 {
430- static const guint quick_bookmark_keyvals[10] = {
431- GDK_1, GDK_2, GDK_3, GDK_4, GDK_5, GDK_6, GDK_7, GDK_8, GDK_9, GDK_0
432- };
433 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
434 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
435 GtkBindingSet *binding_set;
436- int i;
437
438 gobject_class->finalize = gtk_file_chooser_default_finalize;
439 gobject_class->constructor = gtk_file_chooser_default_constructor;
440@@ -621,7 +341,7 @@
441 _gtk_binding_signal_new (I_("location-popup"),
442 G_OBJECT_CLASS_TYPE (class),
443 G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
444- G_CALLBACK (location_popup_handler),
445+ NULL,
446 NULL, NULL,
447 _gtk_marshal_VOID__STRING,
448 G_TYPE_NONE, 1, G_TYPE_STRING);
449@@ -629,15 +349,7 @@
450 _gtk_binding_signal_new ("location-popup-on-paste",
451 G_OBJECT_CLASS_TYPE (class),
452 G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
453- G_CALLBACK (location_popup_on_paste_handler),
454- NULL, NULL,
455- _gtk_marshal_VOID__VOID,
456- G_TYPE_NONE, 0);
457- signals[LOCATION_TOGGLE_POPUP] =
458- _gtk_binding_signal_new (I_("location-toggle-popup"),
459- G_OBJECT_CLASS_TYPE (class),
460- G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
461- G_CALLBACK (location_toggle_popup_handler),
462+ NULL,
463 NULL, NULL,
464 _gtk_marshal_VOID__VOID,
465 G_TYPE_NONE, 0);
466@@ -665,22 +377,6 @@
467 NULL, NULL,
468 _gtk_marshal_VOID__VOID,
469 G_TYPE_NONE, 0);
470- signals[DESKTOP_FOLDER] =
471- _gtk_binding_signal_new (I_("desktop-folder"),
472- G_OBJECT_CLASS_TYPE (class),
473- G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
474- G_CALLBACK (desktop_folder_handler),
475- NULL, NULL,
476- _gtk_marshal_VOID__VOID,
477- G_TYPE_NONE, 0);
478- signals[QUICK_BOOKMARK] =
479- _gtk_binding_signal_new (I_("quick-bookmark"),
480- G_OBJECT_CLASS_TYPE (class),
481- G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
482- G_CALLBACK (quick_bookmark_handler),
483- NULL, NULL,
484- _gtk_marshal_VOID__INT,
485- G_TYPE_NONE, 1, G_TYPE_INT);
486 signals[SHOW_HIDDEN] =
487 _gtk_binding_signal_new ("show-hidden",
488 G_OBJECT_CLASS_TYPE (class),
489@@ -689,22 +385,6 @@
490 NULL, NULL,
491 _gtk_marshal_VOID__VOID,
492 G_TYPE_NONE, 0);
493- signals[SEARCH_SHORTCUT] =
494- _gtk_binding_signal_new ("search-shortcut",
495- G_OBJECT_CLASS_TYPE (class),
496- G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
497- G_CALLBACK (search_shortcut_handler),
498- NULL, NULL,
499- _gtk_marshal_VOID__VOID,
500- G_TYPE_NONE, 0);
501- signals[RECENT_SHORTCUT] =
502- _gtk_binding_signal_new ("recent-shortcut",
503- G_OBJECT_CLASS_TYPE (class),
504- G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
505- G_CALLBACK (recent_shortcut_handler),
506- NULL, NULL,
507- _gtk_marshal_VOID__VOID,
508- G_TYPE_NONE, 0);
509
510 binding_set = gtk_binding_set_by_class (class);
511
512@@ -764,29 +444,17 @@
513 "home-folder",
514 0);
515 gtk_binding_entry_add_signal (binding_set,
516- GDK_d, GDK_MOD1_MASK,
517- "desktop-folder",
518- 0);
519- gtk_binding_entry_add_signal (binding_set,
520 GDK_h, GDK_CONTROL_MASK,
521 "show-hidden",
522 0);
523- gtk_binding_entry_add_signal (binding_set,
524- GDK_s, GDK_MOD1_MASK,
525- "search-shortcut",
526- 0);
527- gtk_binding_entry_add_signal (binding_set,
528- GDK_r, GDK_MOD1_MASK,
529- "recent-shortcut",
530- 0);
531-
532- for (i = 0; i < 10; i++)
533- gtk_binding_entry_add_signal (binding_set,
534- quick_bookmark_keyvals[i], GDK_MOD1_MASK,
535- "quick-bookmark",
536- 1, G_TYPE_INT, i);
537
538 _gtk_file_chooser_install_properties (gobject_class);
539+
540+ gtk_settings_install_property (g_param_spec_string ("gtk-file-chooser-backend",
541+ P_("Default file chooser backend"),
542+ P_("Name of the GtkFileChooser backend to use by default"),
543+ NULL,
544+ GTK_PARAM_READWRITE));
545 }
546
547 static void
548@@ -797,7 +465,6 @@
549 iface->select_all = gtk_file_chooser_default_select_all;
550 iface->unselect_all = gtk_file_chooser_default_unselect_all;
551 iface->get_paths = gtk_file_chooser_default_get_paths;
552- iface->get_preview_path = gtk_file_chooser_default_get_preview_path;
553 iface->get_file_system = gtk_file_chooser_default_get_file_system;
554 iface->set_current_folder = gtk_file_chooser_default_set_current_folder;
555 iface->get_current_folder = gtk_file_chooser_default_get_current_folder;
556@@ -805,9 +472,12 @@
557 iface->add_filter = gtk_file_chooser_default_add_filter;
558 iface->remove_filter = gtk_file_chooser_default_remove_filter;
559 iface->list_filters = gtk_file_chooser_default_list_filters;
560+
561+ /* these are only stubs */
562+ iface->get_preview_path = gtk_file_chooser_default_get_preview_path;
563 iface->add_shortcut_folder = gtk_file_chooser_default_add_shortcut_folder;
564 iface->remove_shortcut_folder = gtk_file_chooser_default_remove_shortcut_folder;
565- iface->list_shortcut_folders = gtk_file_chooser_default_list_shortcut_folders;
566+
567 }
568
569 static void
570@@ -827,85 +497,27 @@
571 access ("MARK: *** CREATE FILE CHOOSER", F_OK);
572 #endif
573 impl->local_only = TRUE;
574- impl->preview_widget_active = TRUE;
575- impl->use_preview_label = TRUE;
576 impl->select_multiple = FALSE;
577 impl->show_hidden = FALSE;
578+ impl->show_create_folder = TRUE;
579 impl->icon_size = FALLBACK_ICON_SIZE;
580 impl->load_state = LOAD_EMPTY;
581 impl->reload_state = RELOAD_EMPTY;
582 impl->pending_select_paths = NULL;
583- impl->location_mode = LOCATION_MODE_PATH_BAR;
584- impl->operation_mode = OPERATION_MODE_BROWSE;
585+ impl->location_mode = LOCATION_MODE_FILENAME_ENTRY;
586+ impl->path_history = NULL;
587
588- gtk_box_set_spacing (GTK_BOX (impl), 12);
589+ gtk_box_set_spacing (GTK_BOX (impl), DEFAULT_SPACING);
590
591 impl->tooltips = gtk_tooltips_new ();
592 g_object_ref_sink (impl->tooltips);
593
594- profile_end ("end", NULL);
595-}
596-
597-/* Frees the data columns for the specified iter in the shortcuts model*/
598-static void
599-shortcuts_free_row_data (GtkFileChooserDefault *impl,
600- GtkTreeIter *iter)
601-{
602- gpointer col_data;
603- ShortcutType shortcut_type;
604- GtkFileSystemHandle *handle;
605-
606- gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), iter,
607- SHORTCUTS_COL_DATA, &col_data,
608- SHORTCUTS_COL_TYPE, &shortcut_type,
609- SHORTCUTS_COL_HANDLE, &handle,
610- -1);
611-
612- if (handle)
613- gtk_file_system_cancel_operation (handle);
614-
615- if (!(shortcut_type == SHORTCUT_TYPE_PATH ||
616- shortcut_type == SHORTCUT_TYPE_VOLUME) ||
617- !col_data)
618- return;
619-
620- if (shortcut_type == SHORTCUT_TYPE_VOLUME)
621- {
622- GtkFileSystemVolume *volume;
623-
624- volume = col_data;
625- gtk_file_system_volume_free (impl->file_system, volume);
626- }
627- else
628- {
629- GtkFilePath *path;
630-
631- g_assert (shortcut_type == SHORTCUT_TYPE_PATH);
632+ if (!impl->root_folder)
633+ impl->root_folder = g_strdup ("/");
634
635- path = col_data;
636- gtk_file_path_free (path);
637- }
638+ profile_end ("end", NULL);
639 }
640
641-/* Frees all the data columns in the shortcuts model */
642-static void
643-shortcuts_free (GtkFileChooserDefault *impl)
644-{
645- GtkTreeIter iter;
646-
647- if (!impl->shortcuts_model)
648- return;
649-
650- if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (impl->shortcuts_model), &iter))
651- do
652- {
653- shortcuts_free_row_data (impl, &iter);
654- }
655- while (gtk_tree_model_iter_next (GTK_TREE_MODEL (impl->shortcuts_model), &iter));
656-
657- g_object_unref (impl->shortcuts_model);
658- impl->shortcuts_model = NULL;
659-}
660
661 static void
662 pending_select_paths_free (GtkFileChooserDefault *impl)
663@@ -924,12 +536,12 @@
664 impl->pending_select_paths = NULL;
665 }
666
667+
668 static void
669 pending_select_paths_add (GtkFileChooserDefault *impl,
670 const GtkFilePath *path)
671 {
672- impl->pending_select_paths =
673- g_slist_prepend (impl->pending_select_paths, gtk_file_path_copy (path));
674+ impl->pending_select_paths = g_slist_prepend (impl->pending_select_paths, gtk_file_path_copy (path));
675 }
676
677 /* Used from gtk_tree_selection_selected_foreach() */
678@@ -964,18 +576,27 @@
679 }
680
681 static void
682-gtk_file_chooser_default_finalize (GObject *object)
683+path_history_free (GtkFileChooserDefault *impl)
684 {
685- GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (object);
686 GSList *l;
687
688- if (impl->shortcuts_pane_filter_model)
689- g_object_unref (impl->shortcuts_pane_filter_model);
690+ for (l = impl->path_history; l; l = l->next)
691+ {
692+ GtkFilePath *path;
693+
694+ path = l->data;
695+ gtk_file_path_free (path);
696+ }
697
698- if (impl->shortcuts_combo_filter_model)
699- g_object_unref (impl->shortcuts_combo_filter_model);
700+ g_slist_free (impl->path_history);
701+ impl->path_history = NULL;
702+}
703
704- shortcuts_free (impl);
705+static void
706+gtk_file_chooser_default_finalize (GObject *object)
707+{
708+ GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (object);
709+ GSList *l;
710
711 g_object_unref (impl->file_system);
712
713@@ -999,8 +620,7 @@
714 if (impl->current_folder)
715 gtk_file_path_free (impl->current_folder);
716
717- if (impl->preview_path)
718- gtk_file_path_free (impl->preview_path);
719+ path_history_free (impl);
720
721 load_remove_timer (impl);
722
723@@ -1011,15 +631,18 @@
724 if (impl->sort_model)
725 g_object_unref (impl->sort_model);
726
727- search_clear_model (impl, FALSE);
728- recent_clear_model (impl, FALSE);
729-
730- g_free (impl->preview_display_name);
731+ if (impl->list_press_path)
732+ {
733+ gtk_tree_path_free (impl->list_press_path);
734+ impl->list_press_path = NULL;
735+ }
736
737 g_free (impl->edited_new_text);
738
739 g_object_unref (impl->tooltips);
740
741+ g_free (impl->root_folder);
742+
743 G_OBJECT_CLASS (_gtk_file_chooser_default_parent_class)->finalize (object);
744 }
745
746@@ -1104,28 +727,6 @@
747 path, error);
748 }
749
750-/* Shows an error dialog about not being able to add a bookmark */
751-static void
752-error_adding_bookmark_dialog (GtkFileChooserDefault *impl,
753- const GtkFilePath *path,
754- GError *error)
755-{
756- error_dialog (impl,
757- _("Could not add a bookmark"),
758- path, error);
759-}
760-
761-/* Shows an error dialog about not being able to remove a bookmark */
762-static void
763-error_removing_bookmark_dialog (GtkFileChooserDefault *impl,
764- const GtkFilePath *path,
765- GError *error)
766-{
767- error_dialog (impl,
768- _("Could not remove bookmark"),
769- path, error);
770-}
771-
772 /* Shows an error dialog about not being able to create a folder */
773 static void
774 error_creating_folder_dialog (GtkFileChooserDefault *impl,
775@@ -1146,9 +747,9 @@
776 GError *error)
777 {
778 error_dialog (impl,
779- _("The folder could not be created, as a file with the same "
780- "name already exists. Try using a different name for the "
781- "folder, or rename the file first."),
782+ _("The folder could not be created, as a file with the same name "
783+ "already exists. Try using a different name for the folder, "
784+ "or rename the file first."),
785 path, error);
786 }
787
788@@ -1175,9378 +776,3705 @@
789
790 /* Changes folders, displaying an error dialog if this fails */
791 static gboolean
792-change_folder_and_display_error (GtkFileChooserDefault *impl,
793- const GtkFilePath *path,
794- gboolean clear_entry)
795+change_folder (GtkFileChooserDefault *impl, const GtkFilePath *path,
796+ gboolean errormsg)
797 {
798 GError *error;
799 gboolean result;
800 GtkFilePath *path_copy;
801+ gchar * file_name;
802
803 g_return_val_if_fail (path != NULL, FALSE);
804
805- profile_start ("start", (char *) path);
806+ path_copy = gtk_file_path_copy (path);
807+ file_name = gtk_file_system_path_to_filename (impl->file_system, path_copy);
808
809- /* We copy the path because of this case:
810- *
811- * list_row_activated()
812- * fetches path from model; path belongs to the model (*)
813- * calls change_folder_and_display_error()
814- * calls _gtk_file_chooser_set_current_folder_path()
815- * changing folders fails, sets model to NULL, thus freeing the path in (*)
816- */
817+ if (!file_name)
818+ {
819+ gtk_file_path_free (path_copy);
820+ return 0;
821+ }
822+
823+ if (impl->root_folder && file_name[0] == '/' && file_name[1] == 0)
824+ {
825+ /* If changing to / and we have root_folder, change into it instead */
826+ gtk_file_path_free (path_copy);
827+ path_copy = gtk_file_system_filename_to_path (impl->file_system,
828+ impl->root_folder);
829+
830+ gtk_widget_set_sensitive (impl->up_button, FALSE);
831+ }
832+ else if (impl->root_folder &&
833+ strcmp (file_name, impl->root_folder) &&
834+ !strncmp (file_name, impl->root_folder, strlen (file_name)))
835+ {
836+ /* refuse to change below the root */
837+ gtk_file_path_free (path_copy);
838+ g_free (file_name);
839+ return 0;
840+ }
841+ else if (!strcmp (file_name, impl->root_folder))
842+ {
843+ gtk_widget_set_sensitive (impl->up_button, FALSE);
844+ }
845+ else if (impl->current_folder && !strcmp (file_name, "/media"))
846+ {
847+ /* Asked to changed into /media -- if we are already in a media
848+ * child folder, we refuse, but if we are in the root, we permit this
849+ */
850+ gchar *name =
851+ gtk_file_system_path_to_filename (impl->file_system,
852+ impl->current_folder);
853+
854+ if (name && !strncmp (name, "/media", 6))
855+ {
856+ g_free (name);
857+ gtk_file_path_free (path_copy);
858+ g_free (file_name);
859+ return 0;
860+ }
861+
862+ gtk_widget_set_sensitive (impl->up_button, TRUE);
863+ }
864+ else if (!strncmp (file_name, "/media/", 7))
865+ {
866+ /* Changing into a media child -- if it is an immediate child, disable
867+ * the Up button
868+ */
869+ gchar * p = file_name + 7;
870+ gchar * q = strchr (p, '/');
871+ if (!q)
872+ gtk_widget_set_sensitive (impl->up_button, FALSE);
873+ else
874+ gtk_widget_set_sensitive (impl->up_button, TRUE);
875+ }
876+ else
877+ {
878+ gtk_widget_set_sensitive (impl->up_button, TRUE);
879+ }
880
881- path_copy = gtk_file_path_copy (path);
882
883 error = NULL;
884- result = gtk_file_chooser_default_update_current_folder (GTK_FILE_CHOOSER (impl), path_copy, TRUE, clear_entry, &error);
885+ result = _gtk_file_chooser_set_current_folder_path (GTK_FILE_CHOOSER (impl), path_copy, &error);
886
887- if (!result)
888+ if (errormsg && !result)
889 error_changing_folder_dialog (impl, path_copy, error);
890
891- gtk_file_path_free (path_copy);
892+ gtk_label_set_text (GTK_LABEL (impl->location_label), file_name);
893
894- profile_end ("end", (char *) path);
895+ gtk_file_path_free (path_copy);
896+ g_free (file_name);
897
898 return result;
899 }
900
901-static void
902-update_preview_widget_visibility (GtkFileChooserDefault *impl)
903+static gboolean
904+change_folder_and_display_error (GtkFileChooserDefault *impl,
905+ const GtkFilePath *path)
906 {
907- if (impl->use_preview_label)
908- {
909- if (!impl->preview_label)
910- {
911- impl->preview_label = gtk_label_new (impl->preview_display_name);
912- gtk_box_pack_start (GTK_BOX (impl->preview_box), impl->preview_label, FALSE, FALSE, 0);
913- gtk_box_reorder_child (GTK_BOX (impl->preview_box), impl->preview_label, 0);
914- gtk_label_set_ellipsize (GTK_LABEL (impl->preview_label), PANGO_ELLIPSIZE_MIDDLE);
915- gtk_widget_show (impl->preview_label);
916- }
917- }
918- else
919- {
920- if (impl->preview_label)
921- {
922- gtk_widget_destroy (impl->preview_label);
923- impl->preview_label = NULL;
924- }
925- }
926-
927- if (impl->preview_widget_active && impl->preview_widget)
928- gtk_widget_show (impl->preview_box);
929- else
930- gtk_widget_hide (impl->preview_box);
931-
932- g_signal_emit_by_name (impl, "default-size-changed");
933+ return change_folder (impl, path, TRUE);
934 }
935
936-static void
937-set_preview_widget (GtkFileChooserDefault *impl,
938- GtkWidget *preview_widget)
939+
940+/* FIXME: GtkFileSystem needs a function to split a remote path
941+ * into hostname and path components, or maybe just have a
942+ * gtk_file_system_path_get_display_name().
943+ *
944+ * This function is also used in gtkfilechooserbutton.c
945+ */
946+gchar *
947+_gtk_file_chooser_label_for_uri (const gchar *uri)
948 {
949- if (preview_widget == impl->preview_widget)
950- return;
951+ const gchar *path, *start, *end, *p;
952+ gchar *host, *label;
953
954- if (impl->preview_widget)
955- gtk_container_remove (GTK_CONTAINER (impl->preview_box),
956- impl->preview_widget);
957+ start = strstr (uri, "://");
958+ start += 3;
959+ path = strchr (start, '/');
960
961- impl->preview_widget = preview_widget;
962- if (impl->preview_widget)
963+ if (path)
964+ end = path;
965+ else
966 {
967- gtk_widget_show (impl->preview_widget);
968- gtk_box_pack_start (GTK_BOX (impl->preview_box), impl->preview_widget, TRUE, TRUE, 0);
969- gtk_box_reorder_child (GTK_BOX (impl->preview_box),
970- impl->preview_widget,
971- (impl->use_preview_label && impl->preview_label) ? 1 : 0);
972+ end = uri + strlen (uri);
973+ path = "/";
974 }
975
976- update_preview_widget_visibility (impl);
977-}
978+ /* strip username */
979+ p = strchr (start, '@');
980+ if (p && p < end)
981+ {
982+ start = p + 1;
983+ }
984
985-/* Renders a "Search" icon at an appropriate size for a tree view */
986-static GdkPixbuf *
987-render_search_icon (GtkFileChooserDefault *impl)
988-{
989- return gtk_widget_render_icon (GTK_WIDGET (impl), GTK_STOCK_FIND, GTK_ICON_SIZE_MENU, NULL);
990-}
991+ p = strchr (start, ':');
992+ if (p && p < end)
993+ end = p;
994
995-static GdkPixbuf *
996-render_recent_icon (GtkFileChooserDefault *impl)
997-{
998- GtkIconTheme *theme;
999- GdkPixbuf *retval;
1000+ host = g_strndup (start, end - start);
1001
1002- if (gtk_widget_has_screen (GTK_WIDGET (impl)))
1003- theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (impl)));
1004- else
1005- theme = gtk_icon_theme_get_default ();
1006+ /* Translators: the first string is a path and the second string
1007+ * is a hostname. Nautilus and the panel contain the same string
1008+ * to translate.
1009+ */
1010+ label = g_strdup_printf (_("%1$s on %2$s"), path, host);
1011
1012- retval = gtk_icon_theme_load_icon (theme, "document-open-recent",
1013- impl->icon_size, 0,
1014- NULL);
1015-
1016- /* fallback */
1017- if (!retval)
1018- retval = gtk_widget_render_icon (GTK_WIDGET (impl), GTK_STOCK_FILE, GTK_ICON_SIZE_MENU, NULL);
1019+ g_free (host);
1020
1021- return retval;
1022+ return label;
1023 }
1024
1025
1026-/* Re-reads all the icons for the shortcuts, used when the theme changes */
1027-struct ReloadIconsData
1028-{
1029- GtkFileChooserDefault *impl;
1030- GtkTreeRowReference *row_ref;
1031-};
1032-
1033+/* Callback used when the "New Folder" button is clicked */
1034 static void
1035-shortcuts_reload_icons_get_info_cb (GtkFileSystemHandle *handle,
1036- const GtkFileInfo *info,
1037- const GError *error,
1038- gpointer user_data)
1039+new_folder_button_clicked (GtkButton *button,
1040+ GtkFileChooserDefault *impl)
1041 {
1042- GdkPixbuf *pixbuf;
1043 GtkTreeIter iter;
1044 GtkTreePath *path;
1045- gboolean cancelled = handle->cancelled;
1046- struct ReloadIconsData *data = user_data;
1047
1048- if (!g_slist_find (data->impl->reload_icon_handles, handle))
1049- goto out;
1050+ if (!impl->browse_files_model)
1051+ return; /* FIXME: this sucks. Disable the New Folder button or something. */
1052
1053- data->impl->reload_icon_handles = g_slist_remove (data->impl->reload_icon_handles, handle);
1054+ /* Prevent button from being clicked twice */
1055+ gtk_widget_set_sensitive (impl->browse_new_folder_button, FALSE);
1056
1057- if (cancelled || error)
1058- goto out;
1059+ _gtk_file_system_model_add_editable (impl->browse_files_model, &iter);
1060
1061- pixbuf = gtk_file_info_render_icon (info, GTK_WIDGET (data->impl),
1062- data->impl->icon_size, NULL);
1063+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->browse_files_model), &iter);
1064+ gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (impl->browse_files_tree_view),
1065+ path, impl->list_name_column,
1066+ FALSE, 0.0, 0.0);
1067+
1068+ g_object_set (impl->list_name_renderer, "editable", TRUE, NULL);
1069+ gtk_tree_view_set_cursor (GTK_TREE_VIEW (impl->browse_files_tree_view),
1070+ path,
1071+ impl->list_name_column,
1072+ TRUE);
1073
1074- path = gtk_tree_row_reference_get_path (data->row_ref);
1075- gtk_tree_model_get_iter (GTK_TREE_MODEL (data->impl->shortcuts_model), &iter, path);
1076- gtk_list_store_set (data->impl->shortcuts_model, &iter,
1077- SHORTCUTS_COL_PIXBUF, pixbuf,
1078- -1);
1079 gtk_tree_path_free (path);
1080+}
1081
1082- if (pixbuf)
1083- g_object_unref (pixbuf);
1084+static void
1085+edited_idle_create_folder_cb (GtkFileSystemHandle *handle,
1086+ const GtkFilePath *path,
1087+ const GError *error,
1088+ gpointer data)
1089+{
1090+ gboolean cancelled = handle->cancelled;
1091+ GtkFileChooserDefault *impl = data;
1092
1093-out:
1094- gtk_tree_row_reference_free (data->row_ref);
1095- g_object_unref (data->impl);
1096- g_free (data);
1097+ if (!g_slist_find (impl->pending_handles, handle))
1098+ goto out;
1099+
1100+ impl->pending_handles = g_slist_remove (impl->pending_handles, handle);
1101+
1102+ if (cancelled)
1103+ goto out;
1104+
1105+ if (!error)
1106+ change_folder_and_display_error (impl, path);
1107+ else
1108+ error_creating_folder_dialog (impl, path, g_error_copy (error));
1109
1110+ out:
1111+ g_object_unref (impl);
1112 g_object_unref (handle);
1113 }
1114
1115-static void
1116-shortcuts_reload_icons (GtkFileChooserDefault *impl)
1117+/* Idle handler for creating a new folder after editing its name cell, or for
1118+ * canceling the editing.
1119+ */
1120+static gboolean
1121+edited_idle_cb (GtkFileChooserDefault *impl)
1122 {
1123- GSList *l;
1124- GtkTreeIter iter;
1125+ GDK_THREADS_ENTER ();
1126
1127- profile_start ("start", NULL);
1128+ g_source_destroy (impl->edited_idle);
1129+ impl->edited_idle = NULL;
1130
1131- if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (impl->shortcuts_model), &iter))
1132- goto out;
1133+ _gtk_file_system_model_remove_editable (impl->browse_files_model);
1134+ g_object_set (impl->list_name_renderer, "editable", FALSE, NULL);
1135
1136- for (l = impl->reload_icon_handles; l; l = l->next)
1137- {
1138- GtkFileSystemHandle *handle = GTK_FILE_SYSTEM_HANDLE (l->data);
1139- gtk_file_system_cancel_operation (handle);
1140- }
1141- g_slist_free (impl->reload_icon_handles);
1142- impl->reload_icon_handles = NULL;
1143+ gtk_widget_set_sensitive (impl->browse_new_folder_button, TRUE);
1144
1145- do
1146+ if (impl->edited_new_text) /* not cancelled? */
1147 {
1148- gpointer data;
1149- ShortcutType shortcut_type;
1150- gboolean pixbuf_visible;
1151- GdkPixbuf *pixbuf;
1152-
1153- gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter,
1154- SHORTCUTS_COL_DATA, &data,
1155- SHORTCUTS_COL_TYPE, &shortcut_type,
1156- SHORTCUTS_COL_PIXBUF_VISIBLE, &pixbuf_visible,
1157- -1);
1158+ GError *error;
1159+ GtkFilePath *file_path;
1160
1161- pixbuf = NULL;
1162- if (pixbuf_visible)
1163- {
1164- if (shortcut_type == SHORTCUT_TYPE_VOLUME)
1165- {
1166- GtkFileSystemVolume *volume;
1167+ error = NULL;
1168+ file_path = gtk_file_system_make_path (impl->file_system,
1169+ impl->current_folder,
1170+ impl->edited_new_text,
1171+ &error);
1172+ if (file_path)
1173+ {
1174+ GtkFileSystemHandle *handle;
1175
1176- volume = data;
1177- pixbuf = gtk_file_system_volume_render_icon (impl->file_system, volume, GTK_WIDGET (impl),
1178- impl->icon_size, NULL);
1179-
1180- gtk_list_store_set (impl->shortcuts_model, &iter,
1181- SHORTCUTS_COL_PIXBUF, pixbuf,
1182- -1);
1183+ handle = gtk_file_system_create_folder (impl->file_system, file_path,
1184+ edited_idle_create_folder_cb,
1185+ g_object_ref (impl));
1186+ impl->pending_handles = g_slist_append (impl->pending_handles, handle);
1187
1188- if (pixbuf)
1189- g_object_unref (pixbuf);
1190- }
1191- else if (shortcut_type == SHORTCUT_TYPE_PATH)
1192- {
1193- if (gtk_file_system_path_is_local (impl->file_system, (GtkFilePath *)data))
1194- {
1195- const GtkFilePath *path;
1196- struct ReloadIconsData *info;
1197- GtkTreePath *tree_path;
1198- GtkFileSystemHandle *handle;
1199-
1200- path = data;
1201-
1202- info = g_new0 (struct ReloadIconsData, 1);
1203- info->impl = g_object_ref (impl);
1204- tree_path = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->shortcuts_model), &iter);
1205- info->row_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (impl->shortcuts_model), tree_path);
1206- gtk_tree_path_free (tree_path);
1207-
1208- handle = gtk_file_system_get_info (impl->file_system, path,
1209- GTK_FILE_INFO_ICON,
1210- shortcuts_reload_icons_get_info_cb,
1211- info);
1212- impl->reload_icon_handles = g_slist_append (impl->reload_icon_handles, handle);
1213- }
1214- else
1215- {
1216- GtkIconTheme *icon_theme;
1217-
1218- /* Don't call get_info for remote paths to avoid latency and
1219- * auth dialogs.
1220- * If we switch to a better bookmarks file format (XBEL), we
1221- * should use mime info to get a better icon.
1222- */
1223- icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (impl)));
1224- pixbuf = gtk_icon_theme_load_icon (icon_theme, "gnome-fs-share",
1225- impl->icon_size, 0, NULL);
1226-
1227- gtk_list_store_set (impl->shortcuts_model, &iter,
1228- SHORTCUTS_COL_PIXBUF, pixbuf,
1229- -1);
1230-
1231- if (pixbuf)
1232- g_object_unref (pixbuf);
1233- }
1234- }
1235- else if (shortcut_type == SHORTCUT_TYPE_SEARCH)
1236- {
1237- pixbuf = render_search_icon (impl);
1238- }
1239- else if (shortcut_type == SHORTCUT_TYPE_RECENT)
1240- {
1241- pixbuf = render_recent_icon (impl);
1242- }
1243+ gtk_file_path_free (file_path);
1244 }
1245+ else
1246+ error_creating_folder_dialog (impl, file_path, error);
1247+
1248+ g_free (impl->edited_new_text);
1249+ impl->edited_new_text = NULL;
1250 }
1251- while (gtk_tree_model_iter_next (GTK_TREE_MODEL (impl->shortcuts_model),&iter));
1252
1253- out:
1254+ GDK_THREADS_LEAVE ();
1255
1256- profile_end ("end", NULL);
1257+ return FALSE;
1258 }
1259
1260-static void
1261-shortcuts_find_folder (GtkFileChooserDefault *impl,
1262- GtkFilePath *folder)
1263+static void
1264+queue_edited_idle (GtkFileChooserDefault *impl,
1265+ const gchar *new_text)
1266 {
1267- GtkTreeSelection *selection;
1268- int pos;
1269- GtkTreePath *path;
1270-
1271- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view));
1272+ /* We create the folder in an idle handler so that we don't modify the tree
1273+ * just now.
1274+ */
1275
1276- g_assert (folder != NULL);
1277- pos = shortcut_find_position (impl, folder);
1278- if (pos == -1)
1279+ if (!impl->edited_idle)
1280 {
1281- gtk_tree_selection_unselect_all (selection);
1282- return;
1283+ impl->edited_idle = g_idle_source_new ();
1284+ g_source_set_closure (impl->edited_idle,
1285+ g_cclosure_new_object (G_CALLBACK (edited_idle_cb),
1286+ G_OBJECT (impl)));
1287+ g_source_attach (impl->edited_idle, NULL);
1288 }
1289
1290- path = gtk_tree_path_new_from_indices (pos, -1);
1291- gtk_tree_selection_select_path (selection, path);
1292- gtk_tree_path_free (path);
1293+ g_free (impl->edited_new_text);
1294+ impl->edited_new_text = g_strdup (new_text);
1295 }
1296
1297-/* If a shortcut corresponds to the current folder, selects it */
1298+/* Callback used from the text cell renderer when the new folder is named */
1299 static void
1300-shortcuts_find_current_folder (GtkFileChooserDefault *impl)
1301+renderer_edited_cb (GtkCellRendererText *cell_renderer_text,
1302+ const gchar *path,
1303+ const gchar *new_text,
1304+ GtkFileChooserDefault *impl)
1305 {
1306- shortcuts_find_folder (impl, impl->current_folder);
1307+ /* work around bug #154921 */
1308+ g_object_set (cell_renderer_text,
1309+ "mode", GTK_CELL_RENDERER_MODE_INERT, NULL);
1310+ queue_edited_idle (impl, new_text);
1311 }
1312
1313-/* Removes the specified number of rows from the shortcuts list */
1314+/* Callback used from the text cell renderer when the new folder edition gets
1315+ * canceled.
1316+ */
1317 static void
1318-shortcuts_remove_rows (GtkFileChooserDefault *impl,
1319- int start_row,
1320- int n_rows)
1321+renderer_editing_canceled_cb (GtkCellRendererText *cell_renderer_text,
1322+ GtkFileChooserDefault *impl)
1323 {
1324- GtkTreePath *path;
1325-
1326- path = gtk_tree_path_new_from_indices (start_row, -1);
1327-
1328- for (; n_rows; n_rows--)
1329- {
1330- GtkTreeIter iter;
1331-
1332- if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->shortcuts_model), &iter, path))
1333- g_assert_not_reached ();
1334+ /* work around bug #154921 */
1335+ g_object_set (cell_renderer_text,
1336+ "mode", GTK_CELL_RENDERER_MODE_INERT, NULL);
1337+ queue_edited_idle (impl, NULL);
1338+}
1339
1340- shortcuts_free_row_data (impl, &iter);
1341- gtk_list_store_remove (impl->shortcuts_model, &iter);
1342- }
1343+/* Creates the widgets for the filter combo box */
1344+static GtkWidget *
1345+filter_create (GtkFileChooserDefault *impl)
1346+{
1347+ impl->filter_combo = gtk_combo_box_new_text ();
1348+ gtk_combo_box_set_focus_on_click (GTK_COMBO_BOX (impl->filter_combo), FALSE);
1349
1350- gtk_tree_path_free (path);
1351-}
1352+ g_signal_connect (impl->filter_combo, "changed",
1353+ G_CALLBACK (filter_combo_changed), impl);
1354
1355-static void
1356-shortcuts_update_count (GtkFileChooserDefault *impl,
1357- ShortcutsIndex type,
1358- gint value)
1359-{
1360- switch (type)
1361- {
1362- case SHORTCUTS_HOME:
1363- if (value < 0)
1364- impl->has_home = FALSE;
1365- else
1366- impl->has_home = TRUE;
1367- break;
1368-
1369- case SHORTCUTS_DESKTOP:
1370- if (value < 0)
1371- impl->has_desktop = FALSE;
1372- else
1373- impl->has_desktop = TRUE;
1374- break;
1375-
1376- case SHORTCUTS_VOLUMES:
1377- impl->num_volumes += value;
1378- break;
1379-
1380- case SHORTCUTS_SHORTCUTS:
1381- impl->num_shortcuts += value;
1382- break;
1383-
1384- case SHORTCUTS_BOOKMARKS:
1385- impl->num_bookmarks += value;
1386- break;
1387-
1388- case SHORTCUTS_CURRENT_FOLDER:
1389- if (value < 0)
1390- impl->shortcuts_current_folder_active = FALSE;
1391- else
1392- impl->shortcuts_current_folder_active = TRUE;
1393- break;
1394-
1395- default:
1396- /* nothing */
1397- break;
1398- }
1399+ return impl->filter_combo;
1400 }
1401
1402-struct ShortcutsInsertRequest
1403-{
1404+struct selection_check_closure {
1405 GtkFileChooserDefault *impl;
1406- GtkFilePath *parent_path;
1407- GtkFilePath *path;
1408- int pos;
1409- char *label_copy;
1410- GtkTreeRowReference *row_ref;
1411- ShortcutsIndex type;
1412- gboolean name_only;
1413- gboolean removable;
1414+ int num_selected;
1415+ gboolean all_files;
1416+ gboolean all_folders;
1417 };
1418
1419+/* Used from gtk_tree_selection_selected_foreach() */
1420 static void
1421-get_file_info_finished (GtkFileSystemHandle *handle,
1422- const GtkFileInfo *info,
1423- const GError *error,
1424- gpointer data)
1425+selection_check_foreach_cb (GtkTreeModel *model,
1426+ GtkTreePath *path,
1427+ GtkTreeIter *iter,
1428+ gpointer data)
1429 {
1430- gint pos = -1;
1431- gboolean cancelled = handle->cancelled;
1432- GdkPixbuf *pixbuf;
1433- GtkTreePath *path;
1434- GtkTreeIter iter;
1435- GtkFileSystemHandle *model_handle;
1436- struct ShortcutsInsertRequest *request = data;
1437-
1438- path = gtk_tree_row_reference_get_path (request->row_ref);
1439- if (!path)
1440- /* Handle doesn't exist anymore in the model */
1441- goto out;
1442-
1443- pos = gtk_tree_path_get_indices (path)[0];
1444- gtk_tree_model_get_iter (GTK_TREE_MODEL (request->impl->shortcuts_model),
1445- &iter, path);
1446- gtk_tree_path_free (path);
1447-
1448- /* validate handle, else goto out */
1449- gtk_tree_model_get (GTK_TREE_MODEL (request->impl->shortcuts_model), &iter,
1450- SHORTCUTS_COL_HANDLE, &model_handle,
1451- -1);
1452- if (handle != model_handle)
1453- goto out;
1454+ struct selection_check_closure *closure;
1455+ GtkTreeIter child_iter;
1456+ const GtkFileInfo *info;
1457+ gboolean is_folder;
1458
1459- /* set the handle to NULL in the model (we unref later on) */
1460- gtk_list_store_set (request->impl->shortcuts_model, &iter,
1461- SHORTCUTS_COL_HANDLE, NULL,
1462- -1);
1463+ closure = data;
1464+ closure->num_selected++;
1465
1466- if (cancelled)
1467- goto out;
1468+ gtk_tree_model_sort_convert_iter_to_child_iter (closure->impl->sort_model, &child_iter, iter);
1469
1470- if (!info)
1471- {
1472- gtk_list_store_remove (request->impl->shortcuts_model, &iter);
1473- shortcuts_update_count (request->impl, request->type, -1);
1474+ info = _gtk_file_system_model_get_info (closure->impl->browse_files_model, &child_iter);
1475+ is_folder = info ? gtk_file_info_get_is_folder (info) : FALSE;
1476
1477- if (request->type == SHORTCUTS_HOME)
1478- {
1479- const char *home = g_get_home_dir ();
1480- GtkFilePath *home_path;
1481+ closure->all_folders = closure->all_folders && is_folder;
1482+ closure->all_files = closure->all_files && !is_folder;
1483+}
1484
1485- home_path = gtk_file_system_filename_to_path (request->impl->file_system, home);
1486- error_getting_info_dialog (request->impl, home_path, g_error_copy (error));
1487- gtk_file_path_free (home_path);
1488- }
1489- else if (request->type == SHORTCUTS_CURRENT_FOLDER)
1490- {
1491- /* Remove the current folder separator */
1492- gint separator_pos = shortcuts_get_index (request->impl, SHORTCUTS_CURRENT_FOLDER_SEPARATOR);
1493- shortcuts_remove_rows (request->impl, separator_pos, 1);
1494- }
1495+/* Checks whether the selected items in the file list are all files or all folders */
1496+static void
1497+selection_check (GtkFileChooserDefault *impl,
1498+ gint *num_selected,
1499+ gboolean *all_files,
1500+ gboolean *all_folders)
1501+{
1502+ struct selection_check_closure closure;
1503+ GtkTreeSelection *selection;
1504
1505- goto out;
1506- }
1507-
1508- if (!request->label_copy)
1509- request->label_copy = g_strdup (gtk_file_info_get_display_name (info));
1510- pixbuf = gtk_file_info_render_icon (info, GTK_WIDGET (request->impl),
1511- request->impl->icon_size, NULL);
1512-
1513- gtk_list_store_set (request->impl->shortcuts_model, &iter,
1514- SHORTCUTS_COL_PIXBUF, pixbuf,
1515- SHORTCUTS_COL_PIXBUF_VISIBLE, TRUE,
1516- SHORTCUTS_COL_NAME, request->label_copy,
1517- SHORTCUTS_COL_TYPE, SHORTCUT_TYPE_PATH,
1518- SHORTCUTS_COL_REMOVABLE, request->removable,
1519- -1);
1520-
1521- if (request->impl->shortcuts_pane_filter_model)
1522- gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (request->impl->shortcuts_pane_filter_model));
1523-
1524- if (request->impl->shortcuts_combo_filter_model)
1525- gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (request->impl->shortcuts_combo_filter_model));
1526-
1527- if (request->type == SHORTCUTS_CURRENT_FOLDER &&
1528- request->impl->save_folder_combo != NULL)
1529- {
1530- /* The current folder is updated via _activate_iter(), don't
1531- * have save_folder_combo_changed_cb() call _activate_iter()
1532- * again.
1533- */
1534- g_signal_handlers_block_by_func (request->impl->save_folder_combo,
1535- G_CALLBACK (save_folder_combo_changed_cb),
1536- request->impl);
1537-
1538- if (request->impl->has_search)
1539- pos -= 1;
1540+ closure.impl = impl;
1541+ closure.num_selected = 0;
1542+ closure.all_files = TRUE;
1543+ closure.all_folders = TRUE;
1544
1545- if (request->impl->has_recent)
1546- pos -= 2;
1547+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
1548+ gtk_tree_selection_selected_foreach (selection,
1549+ selection_check_foreach_cb,
1550+ &closure);
1551
1552- gtk_combo_box_set_active (GTK_COMBO_BOX (request->impl->save_folder_combo), pos);
1553- g_signal_handlers_unblock_by_func (request->impl->save_folder_combo,
1554- G_CALLBACK (save_folder_combo_changed_cb),
1555- request->impl);
1556- }
1557+ g_assert (closure.num_selected == 0 || !(closure.all_files && closure.all_folders));
1558
1559- if (pixbuf)
1560- g_object_unref (pixbuf);
1561+ if (num_selected)
1562+ *num_selected = closure.num_selected;
1563
1564-out:
1565- g_object_unref (request->impl);
1566- gtk_file_path_free (request->parent_path);
1567- gtk_file_path_free (request->path);
1568- gtk_tree_row_reference_free (request->row_ref);
1569- g_free (request->label_copy);
1570- g_free (request);
1571+ if (all_files)
1572+ *all_files = closure.all_files;
1573
1574- g_object_unref (handle);
1575+ if (all_folders)
1576+ *all_folders = closure.all_folders;
1577 }
1578
1579-/* FIXME: GtkFileSystem needs a function to split a remote path
1580- * into hostname and path components, or maybe just have a
1581- * gtk_file_system_path_get_display_name().
1582- *
1583- * This function is also used in gtkfilechooserbutton.c
1584+struct get_selected_path_closure {
1585+ GtkFileChooserDefault *impl;
1586+ const GtkFilePath *path;
1587+};
1588+
1589+/* Handles key press events on the file list, so that we can trap Enter to
1590+ * activate the default button on our own. Also, checks to see if '/' has been
1591+ * pressed. See comment by tree_view_keybinding_cb() for more details.
1592 */
1593-gchar *
1594-_gtk_file_chooser_label_for_uri (const gchar *uri)
1595+static gboolean
1596+trap_activate_cb (GtkWidget *widget,
1597+ GdkEventKey *event,
1598+ gpointer data)
1599 {
1600- const gchar *path, *start, *end, *p;
1601- gchar *host, *label;
1602-
1603- start = strstr (uri, "://");
1604- start += 3;
1605- path = strchr (start, '/');
1606-
1607- if (path)
1608- end = path;
1609- else
1610- {
1611- end = uri + strlen (uri);
1612- path = "/";
1613- }
1614+ GtkFileChooserDefault *impl;
1615+ int modifiers;
1616
1617- /* strip username */
1618- p = strchr (start, '@');
1619- if (p && p < end)
1620- {
1621- start = p + 1;
1622- }
1623-
1624- p = strchr (start, ':');
1625- if (p && p < end)
1626- end = p;
1627-
1628- host = g_strndup (start, end - start);
1629+ impl = (GtkFileChooserDefault *) data;
1630
1631- /* Translators: the first string is a path and the second string
1632- * is a hostname. Nautilus and the panel contain the same string
1633- * to translate.
1634- */
1635- label = g_strdup_printf (_("%1$s on %2$s"), path, host);
1636-
1637- g_free (host);
1638+ modifiers = gtk_accelerator_get_default_mod_mask ();
1639
1640- return label;
1641-}
1642+ if ((event->keyval == GDK_Return
1643+ || event->keyval == GDK_ISO_Enter
1644+ || event->keyval == GDK_KP_Enter
1645+ || event->keyval == GDK_space)
1646+ && ((event->state & modifiers) == 0)
1647+ && !(impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
1648+ impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER))
1649+ {
1650+ GtkWindow *window;
1651
1652-/* Inserts a path in the shortcuts tree, making a copy of it; alternatively,
1653- * inserts a volume. A position of -1 indicates the end of the tree.
1654- */
1655-static void
1656-shortcuts_insert_path (GtkFileChooserDefault *impl,
1657- int pos,
1658- ShortcutType shortcut_type,
1659- GtkFileSystemVolume *volume,
1660- const GtkFilePath *path,
1661- const char *label,
1662- gboolean removable,
1663- ShortcutsIndex type)
1664-{
1665- char *label_copy;
1666- GdkPixbuf *pixbuf = NULL;
1667- gpointer data = NULL;
1668- GtkTreeIter iter;
1669- GtkIconTheme *icon_theme;
1670+ window = get_toplevel (widget);
1671+ if (window
1672+ && widget != window->default_widget
1673+ && !(widget == window->focus_widget &&
1674+ (!window->default_widget || !GTK_WIDGET_SENSITIVE (window->default_widget))))
1675+ {
1676+ gtk_window_activate_default (window);
1677+ return TRUE;
1678+ }
1679+ }
1680+
1681+ return FALSE;
1682+}
1683
1684- profile_start ("start", (shortcut_type == SHORTCUT_TYPE_VOLUME) ? "volume"
1685- : ((shortcut_type == SHORTCUT_TYPE_PATH) ? (char *) path : NULL));
1686+static gboolean
1687+list_button_press (GtkWidget *widget, GdkEventButton *event, gpointer data)
1688+{
1689+ GtkTreeView * tree = GTK_TREE_VIEW (widget);
1690+ GtkFileChooserDefault *impl = data;
1691+ GtkTreePath *path;
1692
1693- if (shortcut_type == SHORTCUT_TYPE_VOLUME)
1694+ if (event->type != GDK_BUTTON_PRESS ||
1695+ !gtk_tree_view_get_path_at_pos (tree, (gint)event->x, (gint)event->y,
1696+ &path, NULL, NULL, NULL))
1697 {
1698- data = volume;
1699- label_copy = gtk_file_system_volume_get_display_name (impl->file_system, volume);
1700- pixbuf = gtk_file_system_volume_render_icon (impl->file_system, volume, GTK_WIDGET (impl),
1701- impl->icon_size, NULL);
1702+ return FALSE;
1703 }
1704- else if (shortcut_type == SHORTCUT_TYPE_PATH)
1705- {
1706- if (gtk_file_system_path_is_local (impl->file_system, path))
1707- {
1708- struct ShortcutsInsertRequest *request;
1709- GtkFileSystemHandle *handle;
1710- GtkTreePath *p;
1711-
1712- request = g_new0 (struct ShortcutsInsertRequest, 1);
1713- request->impl = g_object_ref (impl);
1714- request->path = gtk_file_path_copy (path);
1715- request->name_only = TRUE;
1716- request->removable = removable;
1717- request->pos = pos;
1718- request->type = type;
1719- if (label)
1720- request->label_copy = g_strdup (label);
1721-
1722- if (pos == -1)
1723- gtk_list_store_append (impl->shortcuts_model, &iter);
1724- else
1725- gtk_list_store_insert (impl->shortcuts_model, &iter, pos);
1726-
1727- p = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->shortcuts_model), &iter);
1728- request->row_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (impl->shortcuts_model), p);
1729- gtk_tree_path_free (p);
1730-
1731- handle = gtk_file_system_get_info (request->impl->file_system, request->path,
1732- GTK_FILE_INFO_DISPLAY_NAME | GTK_FILE_INFO_IS_HIDDEN | GTK_FILE_INFO_ICON,
1733- get_file_info_finished, request);
1734-
1735- gtk_list_store_set (impl->shortcuts_model, &iter,
1736- SHORTCUTS_COL_DATA, gtk_file_path_copy (path),
1737- SHORTCUTS_COL_TYPE, SHORTCUT_TYPE_PATH,
1738- SHORTCUTS_COL_HANDLE, handle,
1739- -1);
1740
1741- shortcuts_update_count (impl, type, 1);
1742-
1743- return;
1744- }
1745- else
1746- {
1747- /* Don't call get_info for remote paths to avoid latency and
1748- * auth dialogs.
1749- */
1750- data = gtk_file_path_copy (path);
1751- if (label)
1752- label_copy = g_strdup (label);
1753- else
1754- {
1755- gchar *uri;
1756+ impl->list_press_time = event->time;
1757+ impl->list_press_path = path;
1758
1759- uri = gtk_file_system_path_to_uri (impl->file_system, path);
1760+ return FALSE;
1761+}
1762
1763- label_copy = _gtk_file_chooser_label_for_uri (uri);
1764+static gboolean
1765+list_button_release (GtkWidget *widget, GdkEventButton *event, gpointer data)
1766+{
1767+ GtkTreeView * tree = GTK_TREE_VIEW (widget);
1768+ GtkFileChooserDefault *impl = data;
1769+ GtkTreePath *path = NULL;
1770+ gboolean retval = FALSE;
1771
1772- g_free (uri);
1773- }
1774-
1775- /* If we switch to a better bookmarks file format (XBEL), we
1776- * should use mime info to get a better icon.
1777- */
1778- icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (impl)));
1779- pixbuf = gtk_icon_theme_load_icon (icon_theme, "gnome-fs-share",
1780- impl->icon_size, 0, NULL);
1781- }
1782- }
1783- else
1784+ if (!impl->list_press_time ||
1785+ !impl->list_press_path ||
1786+ event->type != GDK_BUTTON_RELEASE ||
1787+ !gtk_tree_view_get_path_at_pos (tree, (gint)event->x, (gint)event->y,
1788+ &path, NULL, NULL, NULL))
1789 {
1790- g_assert_not_reached ();
1791+ goto done;
1792+ }
1793
1794- return;
1795+ if (event->time - impl->list_press_time > LONG_CLICK_LENGTH &&
1796+ !gtk_tree_path_compare (impl->list_press_path, path))
1797+ {
1798+ retval = TRUE;
1799+ list_row_activated (tree, path, NULL, impl);
1800 }
1801
1802- if (pos == -1)
1803- gtk_list_store_append (impl->shortcuts_model, &iter);
1804- else
1805- gtk_list_store_insert (impl->shortcuts_model, &iter, pos);
1806+ done:
1807+ if (path)
1808+ gtk_tree_path_free (path);
1809
1810- shortcuts_update_count (impl, type, 1);
1811+ impl->list_press_time = 0;
1812
1813- gtk_list_store_set (impl->shortcuts_model, &iter,
1814- SHORTCUTS_COL_PIXBUF, pixbuf,
1815- SHORTCUTS_COL_PIXBUF_VISIBLE, TRUE,
1816- SHORTCUTS_COL_NAME, label_copy,
1817- SHORTCUTS_COL_DATA, data,
1818- SHORTCUTS_COL_TYPE, shortcut_type,
1819- SHORTCUTS_COL_REMOVABLE, removable,
1820- SHORTCUTS_COL_HANDLE, NULL,
1821- -1);
1822-
1823- if (impl->shortcuts_pane_filter_model)
1824- gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_pane_filter_model));
1825-
1826- if (impl->shortcuts_combo_filter_model)
1827- gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_combo_filter_model));
1828-
1829- if (type == SHORTCUTS_CURRENT_FOLDER && impl->save_folder_combo != NULL)
1830- {
1831- /* The current folder is updated via _activate_iter(), don't
1832- * have save_folder_combo_changed_cb() call _activate_iter()
1833- * again.
1834- */
1835- gint combo_pos = shortcuts_get_index (impl, SHORTCUTS_CURRENT_FOLDER);
1836+ if (impl->list_press_path)
1837+ {
1838+ gtk_tree_path_free (impl->list_press_path);
1839+ impl->list_press_path = NULL;
1840+ }
1841
1842- if (impl->has_search)
1843- combo_pos -= 1;
1844+ return FALSE;
1845+}
1846
1847- if (impl->has_recent)
1848- combo_pos -= 2;
1849-
1850- g_signal_handlers_block_by_func (impl->save_folder_combo,
1851- G_CALLBACK (save_folder_combo_changed_cb),
1852- impl);
1853-
1854- gtk_combo_box_set_active (GTK_COMBO_BOX (impl->save_folder_combo), combo_pos);
1855- g_signal_handlers_unblock_by_func (impl->save_folder_combo,
1856- G_CALLBACK (save_folder_combo_changed_cb),
1857- impl);
1858- }
1859
1860- g_free (label_copy);
1861+/* Creates the widgets for the file list */
1862+static GtkWidget *
1863+create_file_list (GtkFileChooserDefault *impl)
1864+{
1865+ GtkWidget *swin;
1866+ GtkTreeSelection *selection;
1867+ GtkTreeViewColumn *column;
1868+ GtkCellRenderer *renderer;
1869
1870- if (pixbuf)
1871- g_object_unref (pixbuf);
1872+ /* Scrolled window */
1873
1874- profile_end ("end", NULL);
1875-}
1876+ swin = gtk_scrolled_window_new (NULL, NULL);
1877+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swin),
1878+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1879+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (swin),
1880+ GTK_SHADOW_IN);
1881
1882-static void
1883-shortcuts_append_search (GtkFileChooserDefault *impl)
1884-{
1885- GdkPixbuf *pixbuf;
1886- GtkTreeIter iter;
1887+ /* Tree/list view */
1888
1889- pixbuf = render_search_icon (impl);
1890+ impl->browse_files_tree_view = gtk_tree_view_new ();
1891+#ifdef PROFILE_FILE_CHOOSER
1892+ g_object_set_data (G_OBJECT (impl->browse_files_tree_view), "fmq-name", "file_list");
1893+#endif
1894+ g_object_set_data (G_OBJECT (impl->browse_files_tree_view), I_("GtkFileChooserDefault"), impl);
1895+ atk_object_set_name (gtk_widget_get_accessible (impl->browse_files_tree_view), _("Files"));
1896
1897- gtk_list_store_append (impl->shortcuts_model, &iter);
1898- gtk_list_store_set (impl->shortcuts_model, &iter,
1899- SHORTCUTS_COL_PIXBUF, pixbuf,
1900- SHORTCUTS_COL_PIXBUF_VISIBLE, TRUE,
1901- SHORTCUTS_COL_NAME, _("Search"),
1902- SHORTCUTS_COL_DATA, NULL,
1903- SHORTCUTS_COL_TYPE, SHORTCUT_TYPE_SEARCH,
1904- SHORTCUTS_COL_REMOVABLE, FALSE,
1905- -1);
1906+ gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (impl->browse_files_tree_view), TRUE);
1907+ gtk_container_add (GTK_CONTAINER (swin), impl->browse_files_tree_view);
1908
1909- if (pixbuf)
1910- g_object_unref (pixbuf);
1911+ g_signal_connect (impl->browse_files_tree_view, "row_activated",
1912+ G_CALLBACK (list_row_activated), impl);
1913+ g_signal_connect (impl->browse_files_tree_view, "key_press_event",
1914+ G_CALLBACK (trap_activate_cb), impl);
1915+ g_signal_connect (impl->browse_files_tree_view, "button_press_event",
1916+ G_CALLBACK (list_button_press), impl);
1917+ g_signal_connect (impl->browse_files_tree_view, "button_release_event",
1918+ G_CALLBACK (list_button_release), impl);
1919
1920- impl->has_search = TRUE;
1921-}
1922+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
1923+ gtk_tree_selection_set_select_function (selection,
1924+ list_select_func,
1925+ impl, NULL);
1926
1927-static void
1928-shortcuts_append_recent (GtkFileChooserDefault *impl)
1929-{
1930- GdkPixbuf *pixbuf;
1931- GtkTreeIter iter;
1932+ g_signal_connect (selection, "changed",
1933+ G_CALLBACK (list_selection_changed), impl);
1934
1935- pixbuf = render_recent_icon (impl);
1936+ /* Filename column */
1937
1938- gtk_list_store_append (impl->shortcuts_model, &iter);
1939- gtk_list_store_set (impl->shortcuts_model, &iter,
1940- SHORTCUTS_COL_PIXBUF, pixbuf,
1941- SHORTCUTS_COL_PIXBUF_VISIBLE, TRUE,
1942- SHORTCUTS_COL_NAME, _("Recently Used"),
1943- SHORTCUTS_COL_DATA, NULL,
1944- SHORTCUTS_COL_TYPE, SHORTCUT_TYPE_RECENT,
1945- SHORTCUTS_COL_REMOVABLE, FALSE,
1946- -1);
1947-
1948- if (pixbuf)
1949- g_object_unref (pixbuf);
1950+ impl->list_name_column = gtk_tree_view_column_new ();
1951+ gtk_tree_view_column_set_expand (impl->list_name_column, TRUE);
1952+ gtk_tree_view_column_set_resizable (impl->list_name_column, TRUE);
1953+ gtk_tree_view_column_set_title (impl->list_name_column, _("Name"));
1954+ gtk_tree_view_column_set_sort_column_id (impl->list_name_column, FILE_LIST_COL_NAME);
1955
1956- impl->has_recent = TRUE;
1957-}
1958+ renderer = gtk_cell_renderer_pixbuf_new ();
1959+ gtk_tree_view_column_pack_start (impl->list_name_column, renderer, FALSE);
1960+ gtk_tree_view_column_set_cell_data_func (impl->list_name_column, renderer,
1961+ list_icon_data_func, impl, NULL);
1962
1963-/* Appends an item for the user's home directory to the shortcuts model */
1964-static void
1965-shortcuts_append_home (GtkFileChooserDefault *impl)
1966-{
1967- const char *home;
1968- GtkFilePath *home_path;
1969+ impl->list_name_renderer = gtk_cell_renderer_text_new ();
1970+ g_object_set (impl->list_name_renderer,
1971+ "ellipsize", PANGO_ELLIPSIZE_END,
1972+ NULL);
1973+ g_signal_connect (impl->list_name_renderer, "edited",
1974+ G_CALLBACK (renderer_edited_cb), impl);
1975+ g_signal_connect (impl->list_name_renderer, "editing_canceled",
1976+ G_CALLBACK (renderer_editing_canceled_cb), impl);
1977+ gtk_tree_view_column_pack_start (impl->list_name_column, impl->list_name_renderer, TRUE);
1978+ gtk_tree_view_column_set_cell_data_func (impl->list_name_column, impl->list_name_renderer,
1979+ list_name_data_func, impl, NULL);
1980
1981- profile_start ("start", NULL);
1982+ gtk_tree_view_append_column (GTK_TREE_VIEW (impl->browse_files_tree_view), impl->list_name_column);
1983+#if 0
1984+ /* Size column */
1985
1986- home = g_get_home_dir ();
1987- if (home == NULL)
1988- {
1989- profile_end ("end - no home directory!?", NULL);
1990- return;
1991- }
1992+ column = gtk_tree_view_column_new ();
1993+ gtk_tree_view_column_set_title (column, _("Size"));
1994
1995- home_path = gtk_file_system_filename_to_path (impl->file_system, home);
1996+ renderer = gtk_cell_renderer_text_new ();
1997+ gtk_tree_view_column_pack_start (column, renderer, TRUE); /* bug: it doesn't expand */
1998+ gtk_tree_view_column_set_cell_data_func (column, renderer,
1999+ list_size_data_func, impl, NULL);
2000+ gtk_tree_view_column_set_sort_column_id (column, FILE_LIST_COL_SIZE);
2001+ gtk_tree_view_append_column (GTK_TREE_VIEW (impl->browse_files_tree_view), column);
2002+#endif
2003+ /* Modification time column */
2004
2005- shortcuts_insert_path (impl, -1, SHORTCUT_TYPE_PATH, NULL, home_path, NULL, FALSE, SHORTCUTS_HOME);
2006- impl->has_home = TRUE;
2007+ column = gtk_tree_view_column_new ();
2008+ gtk_tree_view_column_set_resizable (column, TRUE);
2009+ gtk_tree_view_column_set_title (column, _("Modified"));
2010
2011- gtk_file_path_free (home_path);
2012+ renderer = gtk_cell_renderer_text_new ();
2013+ gtk_tree_view_column_pack_start (column, renderer, TRUE);
2014+ gtk_tree_view_column_set_cell_data_func (column, renderer,
2015+ list_mtime_data_func, impl, NULL);
2016+ gtk_tree_view_column_set_sort_column_id (column, FILE_LIST_COL_MTIME);
2017+ gtk_tree_view_append_column (GTK_TREE_VIEW (impl->browse_files_tree_view), column);
2018+ gtk_widget_show_all (swin);
2019
2020- profile_end ("end", NULL);
2021+ return swin;
2022 }
2023
2024-/* Appends the ~/Desktop directory to the shortcuts model */
2025 static void
2026-shortcuts_append_desktop (GtkFileChooserDefault *impl)
2027+up_button_clicked_cb (GtkButton *button, gpointer data)
2028 {
2029- const char *name;
2030- GtkFilePath *path;
2031-
2032- profile_start ("start", NULL);
2033-
2034- name = g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP);
2035- path = gtk_file_system_filename_to_path (impl->file_system, name);
2036- shortcuts_insert_path (impl, -1, SHORTCUT_TYPE_PATH, NULL, path, _("Desktop"), FALSE, SHORTCUTS_DESKTOP);
2037- impl->has_desktop = TRUE;
2038-
2039- /* We do not actually pop up an error dialog if there is no desktop directory
2040- * because some people may really not want to have one.
2041- */
2042+ GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (data);
2043+ up_folder_handler (impl);
2044+}
2045
2046- gtk_file_path_free (path);
2047+static void
2048+volume_button_clicked_cb (GtkButton *button, gpointer data)
2049+{
2050+ GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (data);
2051+ GtkFilePath * path = g_object_get_data (G_OBJECT (button), "file-path");
2052
2053- profile_end ("end", NULL);
2054+ change_folder_and_display_error (impl, path);
2055 }
2056
2057-/* Appends a list of GtkFilePath to the shortcuts model; returns how many were inserted */
2058-static int
2059-shortcuts_append_paths (GtkFileChooserDefault *impl,
2060- GSList *paths)
2061-{
2062- int start_row;
2063- int num_inserted;
2064- gchar *label;
2065+static GtkWidget *
2066+create_bar (GtkFileChooserDefault *impl)
2067+{
2068+ GSList *list, *l;
2069+ int n;
2070+ GtkWidget *bar = gtk_hbox_new (FALSE, DEFAULT_SPACING);
2071+ GtkWidget *img;
2072+ GtkWidget *label;
2073+
2074+ /* first the Up button */
2075+ img = gtk_image_new_from_stock (GTK_STOCK_GO_UP, GTK_ICON_SIZE_BUTTON);
2076+ gtk_widget_show (img);
2077+
2078+ impl->up_button = gtk_button_new ();
2079+ gtk_container_add (GTK_CONTAINER (impl->up_button), img);
2080+ gtk_widget_show (impl->up_button);
2081+ gtk_widget_set_sensitive (impl->up_button, FALSE);
2082+ gtk_button_set_focus_on_click (GTK_BUTTON (impl->up_button), FALSE);
2083+
2084+ g_signal_connect (impl->up_button, "clicked",
2085+ G_CALLBACK (up_button_clicked_cb), impl);
2086+ gtk_box_pack_start (GTK_BOX(bar), impl->up_button, FALSE, FALSE, 0);
2087
2088- profile_start ("start", NULL);
2089+ impl->num_volumes = 0;
2090+ list = gtk_file_system_list_volumes (impl->file_system);
2091
2092- /* As there is no separator now, we want to start there.
2093- */
2094- start_row = shortcuts_get_index (impl, SHORTCUTS_BOOKMARKS_SEPARATOR);
2095- num_inserted = 0;
2096+ n = 0;
2097
2098- for (; paths; paths = paths->next)
2099+ for (l = list; l; l = l->next, n++)
2100 {
2101- GtkFilePath *path;
2102-
2103- path = paths->data;
2104+ GtkFileSystemVolume *volume;
2105+ GdkPixbuf *pixbuf;
2106+ GtkWidget *button;
2107+ GtkWidget *image;
2108+ GtkFilePath *base_path;
2109+ gchar * file_name = NULL;
2110
2111- if (impl->local_only &&
2112- !gtk_file_system_path_is_local (impl->file_system, path))
2113- continue;
2114+ volume = l->data;
2115+ base_path =
2116+ gtk_file_system_volume_get_base_path (impl->file_system, volume);
2117
2118- label = gtk_file_system_get_bookmark_label (impl->file_system, path);
2119+ if (impl->local_only)
2120+ {
2121+ gboolean is_local =
2122+ gtk_file_system_path_is_local (impl->file_system, base_path);
2123
2124- /* NULL GError, but we don't really want to show error boxes here */
2125- shortcuts_insert_path (impl, start_row + num_inserted, SHORTCUT_TYPE_PATH, NULL, path, label, TRUE, SHORTCUTS_BOOKMARKS);
2126- num_inserted++;
2127+ if (!is_local)
2128+ {
2129+ gtk_file_path_free (base_path);
2130+ gtk_file_system_volume_free (impl->file_system, volume);
2131+ continue;
2132+ }
2133+ }
2134
2135- g_free (label);
2136- }
2137+#if 0
2138+ label_copy =
2139+ gtk_file_system_volume_get_display_name (impl->file_system, volume);
2140+#endif
2141+ pixbuf =
2142+ gtk_file_system_volume_render_icon (impl->file_system, volume,
2143+ GTK_WIDGET (impl),
2144+ impl->icon_size, NULL);
2145+
2146+ button = gtk_button_new ();
2147+ image = gtk_image_new_from_pixbuf (pixbuf);
2148+ g_object_unref (G_OBJECT (pixbuf));
2149+ gtk_container_add (GTK_CONTAINER (button), image);
2150+ gtk_button_set_focus_on_click (GTK_BUTTON (button), FALSE);
2151+
2152+ file_name =
2153+ gtk_file_system_path_to_filename (impl->file_system, base_path);
2154+
2155+ if (file_name && impl->root_folder &&
2156+ strcmp (file_name, impl->root_folder) &&
2157+ !strncmp (file_name, impl->root_folder, strlen (file_name)))
2158+ {
2159+ /* The base path is below the root folder; we replace it with
2160+ * the root folder
2161+ */
2162+ gtk_file_path_free (base_path);
2163+ base_path = gtk_file_system_filename_to_path (impl->file_system,
2164+ impl->root_folder);
2165+ }
2166
2167- profile_end ("end", NULL);
2168+ g_free (file_name);
2169+ gtk_widget_show_all (button);
2170
2171- return num_inserted;
2172-}
2173+ g_object_set_data (G_OBJECT (button), "file-path", base_path);
2174
2175-/* Returns the index for the corresponding item in the shortcuts bar */
2176-static int
2177-shortcuts_get_index (GtkFileChooserDefault *impl,
2178- ShortcutsIndex where)
2179-{
2180- int n;
2181+ g_signal_connect (button, "clicked",
2182+ G_CALLBACK (volume_button_clicked_cb), impl);
2183
2184- n = 0;
2185-
2186- if (where == SHORTCUTS_SEARCH)
2187- goto out;
2188+ gtk_box_pack_start (GTK_BOX(bar), button, FALSE, FALSE, 0);
2189+ }
2190
2191- n += impl->has_search ? 1 : 0;
2192+ impl->num_volumes = n;
2193+ g_slist_free (list);
2194
2195- if (where == SHORTCUTS_RECENT)
2196- goto out;
2197+ label = impl->location_label = gtk_label_new (NULL);
2198+ gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_START);
2199+ gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
2200+ gtk_label_set_text (GTK_LABEL (label), impl->root_folder);
2201+ gtk_widget_show (label);
2202+ gtk_box_pack_start (GTK_BOX(bar), label, TRUE, TRUE, 0);
2203
2204- n += impl->has_recent ? 1 : 0;
2205+ gtk_widget_show (bar);
2206
2207- if (where == SHORTCUTS_RECENT_SEPARATOR)
2208- goto out;
2209+ return bar;
2210+}
2211
2212- n += impl->has_recent ? 1 : 0;
2213+/* Creates the widgets for the files/folders pane */
2214+static GtkWidget *
2215+file_pane_create (GtkFileChooserDefault *impl)
2216+{
2217+ GtkWidget *vbox;
2218+ GtkWidget *hbox;
2219+ GtkWidget *widget;
2220+ vbox = gtk_vbox_new (FALSE, DEFAULT_SPACING);
2221+ gtk_widget_show (vbox);
2222
2223- if (where == SHORTCUTS_HOME)
2224- goto out;
2225+ /* The volume bar and 'Create Folder' button */
2226+ hbox = gtk_hbox_new (FALSE, DEFAULT_SPACING);
2227+ gtk_widget_show (hbox);
2228+ impl->bar = create_bar (impl);
2229+ gtk_widget_show_all (impl->bar);
2230+ gtk_box_pack_start (GTK_BOX (hbox), impl->bar, TRUE, TRUE, 0);
2231
2232- n += impl->has_home ? 1 : 0;
2233+ /* Create Folder */
2234+ widget = gtk_image_new_from_icon_name ("folder-new", GTK_ICON_SIZE_BUTTON);
2235+ gtk_widget_show (widget);
2236+ impl->browse_new_folder_button = gtk_button_new ();
2237+ gtk_container_add (GTK_CONTAINER (impl->browse_new_folder_button), widget);
2238+ gtk_button_set_focus_on_click (GTK_BUTTON (impl->browse_new_folder_button),
2239+ FALSE);
2240
2241- if (where == SHORTCUTS_DESKTOP)
2242- goto out;
2243+ g_signal_connect (impl->browse_new_folder_button, "clicked",
2244+ G_CALLBACK (new_folder_button_clicked), impl);
2245+ gtk_box_pack_end (GTK_BOX (hbox), impl->browse_new_folder_button, FALSE, FALSE, 0);
2246
2247- n += impl->has_desktop ? 1 : 0;
2248+ widget = filter_create (impl);
2249+ gtk_widget_hide (widget);
2250+ gtk_box_pack_end (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
2251
2252- if (where == SHORTCUTS_VOLUMES)
2253- goto out;
2254+ gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
2255
2256- n += impl->num_volumes;
2257+ /* Box for lists */
2258+ hbox = gtk_hbox_new (FALSE, LIST_HBOX_SPACING);
2259+ gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
2260+ gtk_widget_show (hbox);
2261
2262- if (where == SHORTCUTS_SHORTCUTS)
2263- goto out;
2264+ /* File list */
2265
2266- n += impl->num_shortcuts;
2267+ widget = create_file_list (impl);
2268+ gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 0);
2269
2270- if (where == SHORTCUTS_BOOKMARKS_SEPARATOR)
2271- goto out;
2272+ return vbox;
2273+}
2274
2275- /* If there are no bookmarks there won't be a separator */
2276- n += (impl->num_bookmarks > 0) ? 1 : 0;
2277-
2278- if (where == SHORTCUTS_BOOKMARKS)
2279- goto out;
2280-
2281- n += impl->num_bookmarks;
2282+/* Creates the widgets specific to Save mode */
2283+static GtkWidget *
2284+save_widgets_create (GtkFileChooserDefault *impl)
2285+{
2286+ GtkWidget *vbox;
2287+ GtkWidget *hbox;
2288+ GtkWidget *widget;
2289
2290- if (where == SHORTCUTS_CURRENT_FOLDER_SEPARATOR)
2291- goto out;
2292+ vbox = gtk_vbox_new (FALSE, 0);
2293+ hbox = gtk_hbox_new (FALSE, DEFAULT_SPACING);
2294
2295- n += 1;
2296+ widget = gtk_label_new (_("Name:"));
2297+ gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
2298+ gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
2299+ gtk_widget_show (widget);
2300
2301- if (where == SHORTCUTS_CURRENT_FOLDER)
2302- goto out;
2303+ impl->location_entry = _gtk_file_chooser_entry_new (TRUE);
2304+ _gtk_file_chooser_entry_set_file_system (GTK_FILE_CHOOSER_ENTRY (impl->location_entry),
2305+ impl->file_system);
2306+/* gtk_entry_set_width_chars (GTK_ENTRY (impl->location_entry), 45); */
2307+ gtk_entry_set_activates_default (GTK_ENTRY (impl->location_entry), TRUE);
2308+ gtk_box_pack_start (GTK_BOX (hbox), impl->location_entry,
2309+ TRUE, TRUE, 0);
2310
2311- g_assert_not_reached ();
2312+ gtk_widget_show (impl->location_entry);
2313
2314- out:
2315+ gtk_widget_show (hbox);
2316+ gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
2317
2318- return n;
2319+ return vbox;
2320 }
2321
2322-/* Adds all the file system volumes to the shortcuts model */
2323+/* Destroys the widgets specific to Save mode */
2324+/* ??? */
2325 static void
2326-shortcuts_add_volumes (GtkFileChooserDefault *impl)
2327+save_widgets_destroy (GtkFileChooserDefault *impl)
2328 {
2329- int start_row;
2330- GSList *list, *l;
2331- int n;
2332- gboolean old_changing_folders;
2333-
2334- profile_start ("start", NULL);
2335-
2336-
2337- old_changing_folders = impl->changing_folder;
2338- impl->changing_folder = TRUE;
2339+ if (impl->save_widgets == NULL)
2340+ return;
2341
2342- start_row = shortcuts_get_index (impl, SHORTCUTS_VOLUMES);
2343- shortcuts_remove_rows (impl, start_row, impl->num_volumes);
2344- impl->num_volumes = 0;
2345+ gtk_widget_destroy (impl->save_widgets);
2346+ impl->save_widgets = NULL;
2347+ impl->location_entry = NULL;
2348+}
2349
2350- list = gtk_file_system_list_volumes (impl->file_system);
2351+/* Creates the main hpaned with the widgets shared by Open and Save mode */
2352+static GtkWidget *
2353+browse_widgets_create (GtkFileChooserDefault *impl)
2354+{
2355+ GtkWidget *widget;
2356
2357- n = 0;
2358+ widget = file_pane_create (impl);
2359
2360- for (l = list; l; l = l->next)
2361- {
2362- GtkFileSystemVolume *volume;
2363+ return widget;
2364+}
2365
2366- volume = l->data;
2367+static GObject*
2368+gtk_file_chooser_default_constructor (GType type,
2369+ guint n_construct_properties,
2370+ GObjectConstructParam *construct_params)
2371+{
2372+ GtkFileChooserDefault *impl;
2373+ GObject *object;
2374
2375- if (impl->local_only)
2376- {
2377- if (gtk_file_system_volume_get_is_mounted (impl->file_system, volume))
2378- {
2379- GtkFilePath *base_path;
2380+ profile_start ("start", NULL);
2381
2382- base_path = gtk_file_system_volume_get_base_path (impl->file_system, volume);
2383- if (base_path != NULL)
2384- {
2385- gboolean is_local = gtk_file_system_path_is_local (impl->file_system, base_path);
2386- gtk_file_path_free (base_path);
2387-
2388- if (!is_local)
2389- {
2390- gtk_file_system_volume_free (impl->file_system, volume);
2391- continue;
2392- }
2393- }
2394- }
2395- }
2396+ object = G_OBJECT_CLASS (_gtk_file_chooser_default_parent_class)->constructor (type,
2397+ n_construct_properties,
2398+ construct_params);
2399+ impl = GTK_FILE_CHOOSER_DEFAULT (object);
2400
2401- shortcuts_insert_path (impl, start_row + n, SHORTCUT_TYPE_VOLUME, volume, NULL, NULL, FALSE, SHORTCUTS_VOLUMES);
2402- n++;
2403- }
2404+ g_assert (impl->file_system);
2405
2406- impl->num_volumes = n;
2407- g_slist_free (list);
2408+ gtk_widget_push_composite_child ();
2409
2410- if (impl->shortcuts_pane_filter_model)
2411- gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_pane_filter_model));
2412+ /* Widgets for Save mode */
2413+ impl->save_widgets = save_widgets_create (impl);
2414+ gtk_box_pack_start (GTK_BOX (impl), impl->save_widgets, FALSE, FALSE, 0);
2415
2416- if (impl->shortcuts_combo_filter_model)
2417- gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_combo_filter_model));
2418+ /* The browse widgets */
2419+ impl->browse_widgets = browse_widgets_create (impl);
2420+ gtk_box_pack_start (GTK_BOX (impl), impl->browse_widgets, TRUE, TRUE, 0);
2421
2422- impl->changing_folder = old_changing_folders;
2423+ gtk_widget_pop_composite_child ();
2424+ update_appearance (impl);
2425
2426 profile_end ("end", NULL);
2427-}
2428-
2429-/* Inserts a separator node in the shortcuts list */
2430-static void
2431-shortcuts_insert_separator (GtkFileChooserDefault *impl,
2432- ShortcutsIndex where)
2433-{
2434- GtkTreeIter iter;
2435
2436- g_assert (where == SHORTCUTS_RECENT_SEPARATOR ||
2437- where == SHORTCUTS_BOOKMARKS_SEPARATOR ||
2438- where == SHORTCUTS_CURRENT_FOLDER_SEPARATOR);
2439-
2440- gtk_list_store_insert (impl->shortcuts_model, &iter,
2441- shortcuts_get_index (impl, where));
2442- gtk_list_store_set (impl->shortcuts_model, &iter,
2443- SHORTCUTS_COL_PIXBUF, NULL,
2444- SHORTCUTS_COL_PIXBUF_VISIBLE, FALSE,
2445- SHORTCUTS_COL_NAME, NULL,
2446- SHORTCUTS_COL_DATA, NULL,
2447- SHORTCUTS_COL_TYPE, SHORTCUT_TYPE_SEPARATOR,
2448- -1);
2449+ return object;
2450 }
2451
2452-/* Updates the list of bookmarks */
2453 static void
2454-shortcuts_add_bookmarks (GtkFileChooserDefault *impl)
2455+set_local_only (GtkFileChooserDefault *impl,
2456+ gboolean local_only)
2457 {
2458- GSList *bookmarks;
2459- gboolean old_changing_folders;
2460- GtkTreeIter iter;
2461- GtkFilePath *list_selected = NULL;
2462- GtkFilePath *combo_selected = NULL;
2463- ShortcutType shortcut_type;
2464- gpointer col_data;
2465+ if (local_only != impl->local_only)
2466+ {
2467+ impl->local_only = local_only;
2468
2469- profile_start ("start", NULL);
2470-
2471- old_changing_folders = impl->changing_folder;
2472- impl->changing_folder = TRUE;
2473+ if (local_only &&
2474+ !gtk_file_system_path_is_local (impl->file_system, impl->current_folder))
2475+ {
2476+ /* If we are pointing to a non-local folder, make an effort to change
2477+ * back to a local folder, but it's really up to the app to not cause
2478+ * such a situation, so we ignore errors.
2479+ */
2480+ const gchar *home = g_get_home_dir ();
2481+ GtkFilePath *home_path;
2482
2483- if (shortcuts_get_selected (impl, &iter))
2484- {
2485- gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model),
2486- &iter,
2487- SHORTCUTS_COL_DATA, &col_data,
2488- SHORTCUTS_COL_TYPE, &shortcut_type,
2489- -1);
2490+ if (home == NULL)
2491+ return;
2492
2493- if (col_data && shortcut_type == SHORTCUT_TYPE_PATH)
2494- list_selected = gtk_file_path_copy (col_data);
2495- }
2496+ home_path = gtk_file_system_filename_to_path (impl->file_system, home);
2497
2498- if (impl->save_folder_combo &&
2499- gtk_combo_box_get_active_iter (GTK_COMBO_BOX (impl->save_folder_combo),
2500- &iter))
2501- {
2502- GtkTreeIter child_iter;
2503+ _gtk_file_chooser_set_current_folder_path (GTK_FILE_CHOOSER (impl), home_path, NULL);
2504
2505- gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (impl->shortcuts_combo_filter_model),
2506- &child_iter,
2507- &iter);
2508- gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model),
2509- &child_iter,
2510- SHORTCUTS_COL_DATA, &col_data,
2511- SHORTCUTS_COL_TYPE, &shortcut_type,
2512- -1);
2513-
2514- if (col_data && shortcut_type == SHORTCUT_TYPE_PATH)
2515- combo_selected = gtk_file_path_copy (col_data);
2516+ gtk_file_path_free (home_path);
2517+ }
2518 }
2519+}
2520
2521- if (impl->num_bookmarks > 0)
2522- shortcuts_remove_rows (impl,
2523- shortcuts_get_index (impl, SHORTCUTS_BOOKMARKS_SEPARATOR),
2524- impl->num_bookmarks + 1);
2525+static void
2526+volumes_changed_cb (GtkFileSystem *file_system,
2527+ GtkFileChooserDefault *impl)
2528+{
2529+ /* FIXME -- update the bar */
2530+}
2531+
2532+/* Sets the file chooser to multiple selection mode */
2533+static void
2534+set_select_multiple (GtkFileChooserDefault *impl,
2535+ gboolean select_multiple,
2536+ gboolean property_notify)
2537+{
2538+ GtkTreeSelection *selection;
2539+ GtkSelectionMode mode;
2540
2541- impl->num_bookmarks = 0;
2542+ if (select_multiple == impl->select_multiple)
2543+ return;
2544
2545- bookmarks = gtk_file_system_list_bookmarks (impl->file_system);
2546- shortcuts_append_paths (impl, bookmarks);
2547- gtk_file_paths_free (bookmarks);
2548+ mode = select_multiple ? GTK_SELECTION_MULTIPLE : GTK_SELECTION_BROWSE;
2549
2550- if (impl->num_bookmarks > 0)
2551- shortcuts_insert_separator (impl, SHORTCUTS_BOOKMARKS_SEPARATOR);
2552+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
2553+ gtk_tree_selection_set_mode (selection, mode);
2554
2555- if (impl->shortcuts_pane_filter_model)
2556- gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_pane_filter_model));
2557+ impl->select_multiple = select_multiple;
2558+ g_object_notify (G_OBJECT (impl), "select-multiple");
2559+}
2560
2561- if (impl->shortcuts_combo_filter_model)
2562- gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_combo_filter_model));
2563+static void
2564+set_file_system_backend (GtkFileChooserDefault *impl,
2565+ const char *backend)
2566+{
2567+ profile_start ("start for backend", backend ? backend : "default");
2568
2569- if (list_selected)
2570+ if (impl->file_system)
2571 {
2572- shortcuts_find_folder (impl, list_selected);
2573- gtk_file_path_free (list_selected);
2574+ g_signal_handler_disconnect (impl->file_system, impl->volumes_changed_id);
2575+ impl->volumes_changed_id = 0;
2576+ g_object_unref (impl->file_system);
2577 }
2578
2579- if (combo_selected)
2580+ impl->file_system = NULL;
2581+ if (backend)
2582+ impl->file_system = gtk_file_system_create (backend);
2583+ else
2584 {
2585- gint pos;
2586-
2587- pos = shortcut_find_position (impl, combo_selected);
2588- if (pos != -1)
2589- {
2590- if (impl->has_search)
2591- pos -= 1;
2592+ GtkSettings *settings = gtk_settings_get_default ();
2593+ gchar *default_backend = NULL;
2594
2595- if (impl->has_recent)
2596- pos -= 2;
2597+ g_object_get (settings, "gtk-file-chooser-backend", &default_backend, NULL);
2598+ if (default_backend)
2599+ {
2600+ impl->file_system = gtk_file_system_create (default_backend);
2601+ g_free (default_backend);
2602+ }
2603+ }
2604
2605- gtk_combo_box_set_active (GTK_COMBO_BOX (impl->save_folder_combo), pos);
2606- }
2607+ if (!impl->file_system)
2608+ {
2609+#if defined (G_OS_UNIX)
2610+ impl->file_system = gtk_file_system_unix_new ();
2611+#elif defined (G_OS_WIN32)
2612+ impl->file_system = gtk_file_system_win32_new ();
2613+#else
2614+#error "No default filesystem implementation on the platform"
2615+#endif
2616+ }
2617
2618- gtk_file_path_free (combo_selected);
2619+ if (impl->file_system)
2620+ {
2621+ impl->volumes_changed_id = g_signal_connect (impl->file_system, "volumes-changed",
2622+ G_CALLBACK (volumes_changed_cb),
2623+ impl);
2624 }
2625-
2626- impl->changing_folder = old_changing_folders;
2627
2628 profile_end ("end", NULL);
2629 }
2630
2631-/* Appends a separator and a row to the shortcuts list for the current folder */
2632 static void
2633-shortcuts_add_current_folder (GtkFileChooserDefault *impl)
2634+show_new_folder_button (GtkFileChooserDefault *impl)
2635 {
2636- int pos;
2637- gboolean success;
2638-
2639- g_assert (!impl->shortcuts_current_folder_active);
2640-
2641- success = TRUE;
2642-
2643- g_assert (impl->current_folder != NULL);
2644-
2645- pos = shortcut_find_position (impl, impl->current_folder);
2646- if (pos == -1)
2647+ if ((impl->action == GTK_FILE_CHOOSER_ACTION_SAVE ||
2648+ impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER) &&
2649+ impl->show_create_folder)
2650 {
2651- GtkFileSystemVolume *volume;
2652- GtkFilePath *base_path;
2653-
2654- /* Separator */
2655-
2656- shortcuts_insert_separator (impl, SHORTCUTS_CURRENT_FOLDER_SEPARATOR);
2657-
2658- /* Item */
2659-
2660- pos = shortcuts_get_index (impl, SHORTCUTS_CURRENT_FOLDER);
2661-
2662- volume = gtk_file_system_get_volume_for_path (impl->file_system, impl->current_folder);
2663- if (volume)
2664- base_path = gtk_file_system_volume_get_base_path (impl->file_system, volume);
2665- else
2666- base_path = NULL;
2667-
2668- if (base_path &&
2669- strcmp (gtk_file_path_get_string (base_path), gtk_file_path_get_string (impl->current_folder)) == 0)
2670- {
2671- shortcuts_insert_path (impl, pos, SHORTCUT_TYPE_VOLUME, volume, NULL, NULL, FALSE, SHORTCUTS_CURRENT_FOLDER);
2672- }
2673- else
2674- {
2675- shortcuts_insert_path (impl, pos, SHORTCUT_TYPE_PATH, NULL, impl->current_folder, NULL, FALSE, SHORTCUTS_CURRENT_FOLDER);
2676- if (volume)
2677- gtk_file_system_volume_free (impl->file_system, volume);
2678- }
2679-
2680- if (base_path)
2681- gtk_file_path_free (base_path);
2682+ gtk_widget_show (impl->browse_new_folder_button);
2683+ gtk_misc_set_alignment (GTK_MISC (impl->location_label), 0.5, 0.5);
2684 }
2685- else if (impl->save_folder_combo != NULL)
2686+ else
2687 {
2688- if (impl->has_search)
2689- pos -= 1;
2690-
2691- if (impl->has_recent)
2692- pos -= 2; /* + separator */
2693-
2694- gtk_combo_box_set_active (GTK_COMBO_BOX (impl->save_folder_combo), pos);
2695+ gtk_widget_hide (impl->browse_new_folder_button);
2696+ gtk_misc_set_alignment (GTK_MISC (impl->location_label), 1.0, 0.5);
2697 }
2698 }
2699
2700-/* Updates the current folder row in the shortcuts model */
2701+/* This function is basically a do_all function.
2702+ *
2703+ * It sets the visibility on all the widgets based on the current state, and
2704+ * moves the custom_widget if needed.
2705+ */
2706 static void
2707-shortcuts_update_current_folder (GtkFileChooserDefault *impl)
2708+update_appearance (GtkFileChooserDefault *impl)
2709 {
2710- int pos;
2711-
2712- pos = shortcuts_get_index (impl, SHORTCUTS_CURRENT_FOLDER_SEPARATOR);
2713+ if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE ||
2714+ impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
2715+ {
2716+ gtk_widget_show (impl->save_widgets);
2717+ gtk_widget_show (impl->browse_widgets);
2718
2719- if (impl->shortcuts_current_folder_active)
2720+ if (impl->select_multiple)
2721+ {
2722+ g_warning ("Save mode cannot be set in conjunction with multiple selection mode. "
2723+ "Re-setting to single selection mode.");
2724+ set_select_multiple (impl, FALSE, TRUE);
2725+ }
2726+ }
2727+ else if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
2728+ impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
2729 {
2730- shortcuts_remove_rows (impl, pos, 2);
2731- impl->shortcuts_current_folder_active = FALSE;
2732+ gtk_widget_hide (impl->save_widgets);
2733+ gtk_widget_show (impl->browse_widgets);
2734 }
2735
2736- shortcuts_add_current_folder (impl);
2737-}
2738-
2739-/* Filter function used for the shortcuts filter model */
2740-static gboolean
2741-shortcuts_pane_filter_cb (GtkTreeModel *model,
2742- GtkTreeIter *iter,
2743- gpointer data)
2744-{
2745- GtkFileChooserDefault *impl;
2746- GtkTreePath *path;
2747- int pos;
2748-
2749- impl = GTK_FILE_CHOOSER_DEFAULT (data);
2750-
2751- path = gtk_tree_model_get_path (model, iter);
2752- if (!path)
2753- return FALSE;
2754+ show_new_folder_button (impl);
2755
2756- pos = *gtk_tree_path_get_indices (path);
2757- gtk_tree_path_free (path);
2758+ gtk_widget_queue_draw (impl->browse_files_tree_view);
2759
2760- return (pos < shortcuts_get_index (impl, SHORTCUTS_CURRENT_FOLDER_SEPARATOR));
2761+ g_signal_emit_by_name (impl, "default-size-changed");
2762 }
2763
2764-/* Creates the list model for shortcuts */
2765 static void
2766-shortcuts_model_create (GtkFileChooserDefault *impl)
2767-{
2768- /* Keep this order in sync with the SHORCUTS_COL_* enum values */
2769- impl->shortcuts_model = gtk_list_store_new (SHORTCUTS_COL_NUM_COLUMNS,
2770- GDK_TYPE_PIXBUF, /* pixbuf */
2771- G_TYPE_STRING, /* name */
2772- G_TYPE_POINTER, /* path or volume */
2773- G_TYPE_INT, /* ShortcutType */
2774- G_TYPE_BOOLEAN, /* removable */
2775- G_TYPE_BOOLEAN, /* pixbuf cell visibility */
2776- G_TYPE_POINTER); /* GtkFileSystemHandle */
2777+gtk_file_chooser_default_set_property (GObject *object,
2778+ guint prop_id,
2779+ const GValue *value,
2780+ GParamSpec *pspec)
2781
2782- if (search_is_possible (impl))
2783- {
2784- shortcuts_append_search (impl);
2785- }
2786+{
2787+ GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (object);
2788
2789- if (impl->recent_manager)
2790- {
2791- shortcuts_append_recent (impl);
2792- shortcuts_insert_separator (impl, SHORTCUTS_RECENT_SEPARATOR);
2793- }
2794-
2795- if (impl->file_system)
2796+ switch (prop_id)
2797 {
2798- shortcuts_append_home (impl);
2799- shortcuts_append_desktop (impl);
2800- shortcuts_add_volumes (impl);
2801- }
2802-
2803- impl->shortcuts_pane_filter_model = shortcuts_pane_model_filter_new (impl,
2804- GTK_TREE_MODEL (impl->shortcuts_model),
2805- NULL);
2806-
2807- gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (impl->shortcuts_pane_filter_model),
2808- shortcuts_pane_filter_cb,
2809- impl,
2810- NULL);
2811-}
2812+ case GTK_FILE_CHOOSER_PROP_ACTION:
2813+ {
2814+ GtkFileChooserAction action = g_value_get_enum (value);
2815
2816-/* Callback used when the "New Folder" button is clicked */
2817-static void
2818-new_folder_button_clicked (GtkButton *button,
2819- GtkFileChooserDefault *impl)
2820-{
2821- GtkTreeIter iter;
2822- GtkTreePath *path;
2823-
2824- if (!impl->browse_files_model)
2825- return; /* FIXME: this sucks. Disable the New Folder button or something. */
2826-
2827- /* Prevent button from being clicked twice */
2828- gtk_widget_set_sensitive (impl->browse_new_folder_button, FALSE);
2829-
2830- _gtk_file_system_model_add_editable (impl->browse_files_model, &iter);
2831-
2832- path = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->browse_files_model), &iter);
2833- gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (impl->browse_files_tree_view),
2834- path, impl->list_name_column,
2835- FALSE, 0.0, 0.0);
2836-
2837- g_object_set (impl->list_name_renderer, "editable", TRUE, NULL);
2838- gtk_tree_view_set_cursor (GTK_TREE_VIEW (impl->browse_files_tree_view),
2839- path,
2840- impl->list_name_column,
2841- TRUE);
2842-
2843- gtk_tree_path_free (path);
2844-}
2845-
2846-static void
2847-edited_idle_create_folder_cb (GtkFileSystemHandle *handle,
2848- const GtkFilePath *path,
2849- const GError *error,
2850- gpointer data)
2851-{
2852- gboolean cancelled = handle->cancelled;
2853- GtkFileChooserDefault *impl = data;
2854-
2855- if (!g_slist_find (impl->pending_handles, handle))
2856- goto out;
2857-
2858- impl->pending_handles = g_slist_remove (impl->pending_handles, handle);
2859+ if (action != impl->action)
2860+ {
2861+ gtk_file_chooser_default_unselect_all (GTK_FILE_CHOOSER (impl));
2862+
2863+ if ((action == GTK_FILE_CHOOSER_ACTION_SAVE || action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
2864+ && impl->select_multiple)
2865+ {
2866+ g_warning ("Tried to change the file chooser action to SAVE or CREATE_FOLDER, but "
2867+ "this is not allowed in multiple selection mode. Resetting the file chooser "
2868+ "to single selection mode.");
2869+ set_select_multiple (impl, FALSE, TRUE);
2870+ }
2871+ impl->action = action;
2872+ update_appearance (impl);
2873+ settings_load (impl);
2874+ }
2875+ }
2876+ break;
2877
2878- if (cancelled)
2879- goto out;
2880+ case GTK_FILE_CHOOSER_PROP_FILE_SYSTEM_BACKEND:
2881+ set_file_system_backend (impl, g_value_get_string (value));
2882+ break;
2883
2884- if (!error)
2885- change_folder_and_display_error (impl, path, FALSE);
2886- else
2887- error_creating_folder_dialog (impl, path, g_error_copy (error));
2888+ case GTK_FILE_CHOOSER_PROP_FILTER:
2889+ set_current_filter (impl, g_value_get_object (value));
2890+ break;
2891
2892- out:
2893- g_object_unref (impl);
2894- g_object_unref (handle);
2895-}
2896+ case GTK_FILE_CHOOSER_PROP_LOCAL_ONLY:
2897+ set_local_only (impl, g_value_get_boolean (value));
2898+ break;
2899
2900-/* Idle handler for creating a new folder after editing its name cell, or for
2901- * canceling the editing.
2902- */
2903-static gboolean
2904-edited_idle_cb (GtkFileChooserDefault *impl)
2905-{
2906- GDK_THREADS_ENTER ();
2907-
2908- g_source_destroy (impl->edited_idle);
2909- impl->edited_idle = NULL;
2910+ case GTK_FILE_CHOOSER_PROP_SELECT_MULTIPLE:
2911+ {
2912+ gboolean select_multiple = g_value_get_boolean (value);
2913+ if ((impl->action == GTK_FILE_CHOOSER_ACTION_SAVE || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
2914+ && select_multiple)
2915+ {
2916+ g_warning ("Tried to set the file chooser to multiple selection mode, but this is "
2917+ "not allowed in SAVE or CREATE_FOLDER modes. Ignoring the change and "
2918+ "leaving the file chooser in single selection mode.");
2919+ return;
2920+ }
2921
2922- _gtk_file_system_model_remove_editable (impl->browse_files_model);
2923- g_object_set (impl->list_name_renderer, "editable", FALSE, NULL);
2924+ set_select_multiple (impl, select_multiple, FALSE);
2925+ }
2926+ break;
2927
2928- gtk_widget_set_sensitive (impl->browse_new_folder_button, TRUE);
2929+ case GTK_FILE_CHOOSER_PROP_SHOW_HIDDEN:
2930+ {
2931+ gboolean show_hidden = g_value_get_boolean (value);
2932+ if (show_hidden != impl->show_hidden)
2933+ {
2934+ impl->show_hidden = show_hidden;
2935
2936- if (impl->edited_new_text) /* not cancelled? */
2937- {
2938- GError *error;
2939- GtkFilePath *file_path;
2940+ if (impl->browse_files_model)
2941+ _gtk_file_system_model_set_show_hidden (impl->browse_files_model, show_hidden);
2942+ }
2943+ }
2944+ break;
2945
2946- error = NULL;
2947- file_path = gtk_file_system_make_path (impl->file_system,
2948- impl->current_folder,
2949- impl->edited_new_text,
2950- &error);
2951- if (file_path)
2952- {
2953- GtkFileSystemHandle *handle;
2954+ case GTK_FILE_CHOOSER_PROP_DO_OVERWRITE_CONFIRMATION:
2955+ {
2956+ gboolean do_overwrite_confirmation = g_value_get_boolean (value);
2957+ impl->do_overwrite_confirmation = do_overwrite_confirmation;
2958+ }
2959+ break;
2960
2961- handle = gtk_file_system_create_folder (impl->file_system, file_path,
2962- edited_idle_create_folder_cb,
2963- g_object_ref (impl));
2964- impl->pending_handles = g_slist_append (impl->pending_handles, handle);
2965+ case GTK_FILE_CHOOSER_PROP_ROOT_FOLDER:
2966+ {
2967+ GtkFilePath * path;
2968+ gchar * new_root = g_strdup (g_value_get_string (value));
2969
2970- gtk_file_path_free (file_path);
2971- }
2972- else
2973- error_creating_folder_dialog (impl, file_path, error);
2974+ if (!new_root)
2975+ {
2976+ new_root = g_strdup ("/");
2977+ }
2978
2979- g_free (impl->edited_new_text);
2980- impl->edited_new_text = NULL;
2981- }
2982+ path = gtk_file_system_filename_to_path (impl->file_system,
2983+ new_root);
2984+ if (change_folder (impl, path, FALSE))
2985+ {
2986+ g_free (impl->root_folder);
2987+ impl->root_folder = new_root;
2988+ }
2989+ else
2990+ {
2991+ g_warning ("Unable to set [%s] as root folder", new_root);
2992+ g_free (new_root);
2993+ }
2994
2995- GDK_THREADS_LEAVE ();
2996+ gtk_file_path_free (path);
2997+ }
2998+ break;
2999
3000- return FALSE;
3001-}
3002+ case GTK_FILE_CHOOSER_PROP_SHOW_CREATE_FOLDER:
3003+ {
3004+ gboolean show = g_value_get_boolean (value);
3005+ if (show != impl->show_create_folder)
3006+ {
3007+ impl->show_create_folder = show;
3008+ show_new_folder_button (impl);
3009+ }
3010+ }
3011+ break;
3012
3013-static void
3014-queue_edited_idle (GtkFileChooserDefault *impl,
3015- const gchar *new_text)
3016-{
3017- /* We create the folder in an idle handler so that we don't modify the tree
3018- * just now.
3019- */
3020+ /* These are not supported */
3021+ case GTK_FILE_CHOOSER_PROP_PREVIEW_WIDGET:
3022+ case GTK_FILE_CHOOSER_PROP_PREVIEW_WIDGET_ACTIVE:
3023+ case GTK_FILE_CHOOSER_PROP_USE_PREVIEW_LABEL:
3024+ case GTK_FILE_CHOOSER_PROP_EXTRA_WIDGET:
3025+ break;
3026
3027- if (!impl->edited_idle)
3028- {
3029- impl->edited_idle = g_idle_source_new ();
3030- g_source_set_closure (impl->edited_idle,
3031- g_cclosure_new_object (G_CALLBACK (edited_idle_cb),
3032- G_OBJECT (impl)));
3033- g_source_attach (impl->edited_idle, NULL);
3034+ default:
3035+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
3036+ break;
3037 }
3038-
3039- g_free (impl->edited_new_text);
3040- impl->edited_new_text = g_strdup (new_text);
3041-}
3042-
3043-/* Callback used from the text cell renderer when the new folder is named */
3044-static void
3045-renderer_edited_cb (GtkCellRendererText *cell_renderer_text,
3046- const gchar *path,
3047- const gchar *new_text,
3048- GtkFileChooserDefault *impl)
3049-{
3050- /* work around bug #154921 */
3051- g_object_set (cell_renderer_text,
3052- "mode", GTK_CELL_RENDERER_MODE_INERT, NULL);
3053- queue_edited_idle (impl, new_text);
3054 }
3055
3056-/* Callback used from the text cell renderer when the new folder edition gets
3057- * canceled.
3058- */
3059 static void
3060-renderer_editing_canceled_cb (GtkCellRendererText *cell_renderer_text,
3061- GtkFileChooserDefault *impl)
3062-{
3063- /* work around bug #154921 */
3064- g_object_set (cell_renderer_text,
3065- "mode", GTK_CELL_RENDERER_MODE_INERT, NULL);
3066- queue_edited_idle (impl, NULL);
3067-}
3068-
3069-/* Creates the widgets for the filter combo box */
3070-static GtkWidget *
3071-filter_create (GtkFileChooserDefault *impl)
3072-{
3073- impl->filter_combo = gtk_combo_box_new_text ();
3074- gtk_combo_box_set_focus_on_click (GTK_COMBO_BOX (impl->filter_combo), FALSE);
3075-
3076- g_signal_connect (impl->filter_combo, "changed",
3077- G_CALLBACK (filter_combo_changed), impl);
3078-
3079- gtk_widget_set_tooltip_text (impl->filter_combo,
3080- _("Select which types of files are shown"));
3081-
3082- return impl->filter_combo;
3083-}
3084-
3085-static GtkWidget *
3086-button_new (GtkFileChooserDefault *impl,
3087- const char *text,
3088- const char *stock_id,
3089- gboolean sensitive,
3090- gboolean show,
3091- GCallback callback)
3092-{
3093- GtkWidget *button;
3094- GtkWidget *image;
3095-
3096- button = gtk_button_new_with_mnemonic (text);
3097- image = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_BUTTON);
3098- gtk_button_set_image (GTK_BUTTON (button), image);
3099-
3100- gtk_widget_set_sensitive (button, sensitive);
3101- g_signal_connect (button, "clicked", callback, impl);
3102-
3103- if (show)
3104- gtk_widget_show (button);
3105-
3106- return button;
3107-}
3108-
3109-/* Looks for a path among the shortcuts; returns its index or -1 if it doesn't exist */
3110-static int
3111-shortcut_find_position (GtkFileChooserDefault *impl,
3112- const GtkFilePath *path)
3113+gtk_file_chooser_default_get_property (GObject *object,
3114+ guint prop_id,
3115+ GValue *value,
3116+ GParamSpec *pspec)
3117 {
3118- GtkTreeIter iter;
3119- int i;
3120- int current_folder_separator_idx;
3121-
3122- if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (impl->shortcuts_model), &iter))
3123- return -1;
3124-
3125- current_folder_separator_idx = shortcuts_get_index (impl, SHORTCUTS_CURRENT_FOLDER_SEPARATOR);
3126-
3127-#if 0
3128- /* FIXME: is this still needed? */
3129- if (current_folder_separator_idx >= impl->shortcuts_model->length)
3130- return -1;
3131-#endif
3132+ GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (object);
3133
3134- for (i = 0; i < current_folder_separator_idx; i++)
3135+ switch (prop_id)
3136 {
3137- gpointer col_data;
3138- ShortcutType shortcut_type;
3139-
3140- gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter,
3141- SHORTCUTS_COL_DATA, &col_data,
3142- SHORTCUTS_COL_TYPE, &shortcut_type,
3143- -1);
3144-
3145- if (col_data)
3146- {
3147- if (shortcut_type == SHORTCUT_TYPE_VOLUME)
3148- {
3149- GtkFileSystemVolume *volume;
3150- GtkFilePath *base_path;
3151- gboolean exists;
3152-
3153- volume = col_data;
3154- base_path = gtk_file_system_volume_get_base_path (impl->file_system, volume);
3155-
3156- exists = base_path && strcmp (gtk_file_path_get_string (path),
3157- gtk_file_path_get_string (base_path)) == 0;
3158- g_free (base_path);
3159-
3160- if (exists)
3161- return i;
3162- }
3163- else if (shortcut_type == SHORTCUT_TYPE_PATH)
3164- {
3165- GtkFilePath *model_path;
3166-
3167- model_path = col_data;
3168-
3169- if (model_path && gtk_file_path_compare (model_path, path) == 0)
3170- return i;
3171- }
3172- }
3173+ case GTK_FILE_CHOOSER_PROP_ACTION:
3174+ g_value_set_enum (value, impl->action);
3175+ break;
3176
3177- if (i < current_folder_separator_idx - 1)
3178- {
3179- if (!gtk_tree_model_iter_next (GTK_TREE_MODEL (impl->shortcuts_model), &iter))
3180- g_assert_not_reached ();
3181- }
3182- }
3183-
3184- return -1;
3185-}
3186-
3187-/* Tries to add a bookmark from a path name */
3188-static gboolean
3189-shortcuts_add_bookmark_from_path (GtkFileChooserDefault *impl,
3190- const GtkFilePath *path,
3191- int pos)
3192-{
3193- GError *error;
3194-
3195- g_return_val_if_fail (path != NULL, FALSE);
3196-
3197- if (shortcut_find_position (impl, path) != -1)
3198- return FALSE;
3199-
3200- error = NULL;
3201- if (!gtk_file_system_insert_bookmark (impl->file_system, path, pos, &error))
3202- {
3203- error_adding_bookmark_dialog (impl, path, error);
3204- return FALSE;
3205- }
3206-
3207- return TRUE;
3208-}
3209-
3210-static void
3211-add_bookmark_foreach_cb (GtkTreeModel *model,
3212- GtkTreePath *path,
3213- GtkTreeIter *iter,
3214- gpointer data)
3215-{
3216- GtkFileChooserDefault *impl;
3217- GtkFileSystemModel *fs_model;
3218- GtkTreeIter child_iter;
3219- const GtkFilePath *file_path;
3220-
3221- impl = (GtkFileChooserDefault *) data;
3222-
3223- switch (impl->operation_mode)
3224- {
3225- case OPERATION_MODE_BROWSE:
3226- fs_model = impl->browse_files_model;
3227- gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model, &child_iter, iter);
3228- file_path = _gtk_file_system_model_get_path (fs_model, &child_iter);
3229- break;
3230-
3231- case OPERATION_MODE_SEARCH:
3232- search_get_valid_child_iter (impl, &child_iter, iter);
3233- gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &child_iter,
3234- SEARCH_MODEL_COL_PATH, &file_path,
3235- -1);
3236- break;
3237-
3238- case OPERATION_MODE_RECENT:
3239- recent_get_valid_child_iter (impl, &child_iter, iter);
3240- gtk_tree_model_get (GTK_TREE_MODEL (impl->recent_model), &child_iter,
3241- RECENT_MODEL_COL_PATH, &file_path,
3242- -1);
3243- break;
3244- }
3245-
3246- shortcuts_add_bookmark_from_path (impl, file_path, -1);
3247-}
3248-
3249-/* Adds a bookmark from the currently selected item in the file list */
3250-static void
3251-bookmarks_add_selected_folder (GtkFileChooserDefault *impl)
3252-{
3253- GtkTreeSelection *selection;
3254-
3255- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
3256-
3257- if (gtk_tree_selection_count_selected_rows (selection) == 0)
3258- shortcuts_add_bookmark_from_path (impl, impl->current_folder, -1);
3259- else
3260- gtk_tree_selection_selected_foreach (selection,
3261- add_bookmark_foreach_cb,
3262- impl);
3263-}
3264-
3265-/* Callback used when the "Add bookmark" button is clicked */
3266-static void
3267-add_bookmark_button_clicked_cb (GtkButton *button,
3268- GtkFileChooserDefault *impl)
3269-{
3270- bookmarks_add_selected_folder (impl);
3271-}
3272-
3273-/* Returns TRUE plus an iter in the shortcuts_model if a row is selected;
3274- * returns FALSE if no shortcut is selected.
3275- */
3276-static gboolean
3277-shortcuts_get_selected (GtkFileChooserDefault *impl,
3278- GtkTreeIter *iter)
3279-{
3280- GtkTreeSelection *selection;
3281- GtkTreeIter parent_iter;
3282-
3283- if (!impl->browse_shortcuts_tree_view)
3284- return FALSE;
3285-
3286- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view));
3287-
3288- if (!gtk_tree_selection_get_selected (selection, NULL, &parent_iter))
3289- return FALSE;
3290-
3291- gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (impl->shortcuts_pane_filter_model),
3292- iter,
3293- &parent_iter);
3294- return TRUE;
3295-}
3296-
3297-/* Removes the selected bookmarks */
3298-static void
3299-remove_selected_bookmarks (GtkFileChooserDefault *impl)
3300-{
3301- GtkTreeIter iter;
3302- gpointer col_data;
3303- GtkFilePath *path;
3304- gboolean removable;
3305- GError *error;
3306-
3307- if (!shortcuts_get_selected (impl, &iter))
3308- return;
3309-
3310- gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter,
3311- SHORTCUTS_COL_DATA, &col_data,
3312- SHORTCUTS_COL_REMOVABLE, &removable,
3313- -1);
3314-
3315- if (!removable)
3316- return;
3317-
3318- g_assert (col_data != NULL);
3319-
3320- path = col_data;
3321-
3322- error = NULL;
3323- if (!gtk_file_system_remove_bookmark (impl->file_system, path, &error))
3324- error_removing_bookmark_dialog (impl, path, error);
3325-}
3326-
3327-/* Callback used when the "Remove bookmark" button is clicked */
3328-static void
3329-remove_bookmark_button_clicked_cb (GtkButton *button,
3330- GtkFileChooserDefault *impl)
3331-{
3332- remove_selected_bookmarks (impl);
3333-}
3334-
3335-struct selection_check_closure {
3336- GtkFileChooserDefault *impl;
3337- int num_selected;
3338- gboolean all_files;
3339- gboolean all_folders;
3340-};
3341-
3342-/* Used from gtk_tree_selection_selected_foreach() */
3343-static void
3344-selection_check_foreach_cb (GtkTreeModel *model,
3345- GtkTreePath *path,
3346- GtkTreeIter *iter,
3347- gpointer data)
3348-{
3349- struct selection_check_closure *closure;
3350- GtkTreeIter child_iter;
3351- const GtkFileInfo *info;
3352- gboolean is_folder;
3353-
3354- closure = data;
3355- closure->num_selected++;
3356-
3357- switch (closure->impl->operation_mode)
3358- {
3359- case OPERATION_MODE_BROWSE:
3360- gtk_tree_model_sort_convert_iter_to_child_iter (closure->impl->sort_model, &child_iter, iter);
3361- info = _gtk_file_system_model_get_info (closure->impl->browse_files_model, &child_iter);
3362- is_folder = info ? gtk_file_info_get_is_folder (info) : FALSE;
3363- break;
3364-
3365- case OPERATION_MODE_SEARCH:
3366- search_get_valid_child_iter (closure->impl, &child_iter, iter);
3367- gtk_tree_model_get (GTK_TREE_MODEL (closure->impl->search_model), &child_iter,
3368- SEARCH_MODEL_COL_IS_FOLDER, &is_folder,
3369- -1);
3370- break;
3371-
3372- case OPERATION_MODE_RECENT:
3373- recent_get_valid_child_iter (closure->impl, &child_iter, iter);
3374- gtk_tree_model_get (GTK_TREE_MODEL (closure->impl->recent_model), &child_iter,
3375- RECENT_MODEL_COL_IS_FOLDER, &is_folder,
3376- -1);
3377- break;
3378- }
3379-
3380- closure->all_folders = closure->all_folders && is_folder;
3381- closure->all_files = closure->all_files && !is_folder;
3382-}
3383-
3384-/* Checks whether the selected items in the file list are all files or all folders */
3385-static void
3386-selection_check (GtkFileChooserDefault *impl,
3387- gint *num_selected,
3388- gboolean *all_files,
3389- gboolean *all_folders)
3390-{
3391- struct selection_check_closure closure;
3392- GtkTreeSelection *selection;
3393-
3394- closure.impl = impl;
3395- closure.num_selected = 0;
3396- closure.all_files = TRUE;
3397- closure.all_folders = TRUE;
3398-
3399- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
3400- gtk_tree_selection_selected_foreach (selection,
3401- selection_check_foreach_cb,
3402- &closure);
3403-
3404- g_assert (closure.num_selected == 0 || !(closure.all_files && closure.all_folders));
3405-
3406- if (num_selected)
3407- *num_selected = closure.num_selected;
3408-
3409- if (all_files)
3410- *all_files = closure.all_files;
3411-
3412- if (all_folders)
3413- *all_folders = closure.all_folders;
3414-}
3415-
3416-struct get_selected_path_closure {
3417- GtkFileChooserDefault *impl;
3418- const GtkFilePath *path;
3419-};
3420-
3421-static void
3422-get_selected_path_foreach_cb (GtkTreeModel *model,
3423- GtkTreePath *path,
3424- GtkTreeIter *iter,
3425- gpointer data)
3426-{
3427- struct get_selected_path_closure *closure;
3428- GtkTreeIter child_iter;
3429-
3430- closure = data;
3431-
3432- switch (closure->impl->operation_mode)
3433- {
3434- case OPERATION_MODE_BROWSE:
3435- gtk_tree_model_sort_convert_iter_to_child_iter (closure->impl->sort_model, &child_iter, iter);
3436- closure->path = _gtk_file_system_model_get_path (closure->impl->browse_files_model, &child_iter);
3437- break;
3438-
3439- case OPERATION_MODE_SEARCH:
3440- search_get_valid_child_iter (closure->impl, &child_iter, iter);
3441- gtk_tree_model_get (GTK_TREE_MODEL (closure->impl->search_model), &child_iter,
3442- SEARCH_MODEL_COL_PATH, &closure->path,
3443- -1);
3444- break;
3445-
3446- case OPERATION_MODE_RECENT:
3447- recent_get_valid_child_iter (closure->impl, &child_iter, iter);
3448- gtk_tree_model_get (GTK_TREE_MODEL (closure->impl->recent_model), &child_iter,
3449- RECENT_MODEL_COL_PATH, &closure->path,
3450- -1);
3451- break;
3452- }
3453-}
3454-
3455-/* Returns a selected path from the file list */
3456-static const GtkFilePath *
3457-get_selected_path (GtkFileChooserDefault *impl)
3458-{
3459- struct get_selected_path_closure closure;
3460- GtkTreeSelection *selection;
3461-
3462- closure.impl = impl;
3463- closure.path = NULL;
3464-
3465- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
3466- gtk_tree_selection_selected_foreach (selection,
3467- get_selected_path_foreach_cb,
3468- &closure);
3469-
3470- return closure.path;
3471-}
3472-
3473-typedef struct {
3474- GtkFileChooserDefault *impl;
3475- gchar *tip;
3476-} UpdateTooltipData;
3477-
3478-static void
3479-update_tooltip (GtkTreeModel *model,
3480- GtkTreePath *path,
3481- GtkTreeIter *iter,
3482- gpointer data)
3483-{
3484- UpdateTooltipData *udata = data;
3485- GtkTreeIter child_iter;
3486- const GtkFileInfo *info;
3487-
3488- if (udata->tip == NULL)
3489- {
3490- const gchar *display_name;
3491-
3492- switch (udata->impl->operation_mode)
3493- {
3494- case OPERATION_MODE_BROWSE:
3495- gtk_tree_model_sort_convert_iter_to_child_iter (udata->impl->sort_model,
3496- &child_iter,
3497- iter);
3498- info = _gtk_file_system_model_get_info (udata->impl->browse_files_model, &child_iter);
3499- display_name = gtk_file_info_get_display_name (info);
3500- break;
3501-
3502- case OPERATION_MODE_SEARCH:
3503- search_get_valid_child_iter (udata->impl, &child_iter, iter);
3504- gtk_tree_model_get (GTK_TREE_MODEL (udata->impl->search_model), &child_iter,
3505- SEARCH_MODEL_COL_DISPLAY_NAME, &display_name,
3506- -1);
3507- break;
3508-
3509- case OPERATION_MODE_RECENT:
3510- recent_get_valid_child_iter (udata->impl, &child_iter, iter);
3511- gtk_tree_model_get (GTK_TREE_MODEL (udata->impl->recent_model), &child_iter,
3512- RECENT_MODEL_COL_DISPLAY_NAME, &display_name,
3513- -1);
3514- break;
3515- }
3516-
3517- udata->tip = g_strdup_printf (_("Add the folder '%s' to the bookmarks"),
3518- display_name);
3519- }
3520-}
3521-
3522-
3523-/* Sensitize the "add bookmark" button if all the selected items are folders, or
3524- * if there are no selected items *and* the current folder is not in the
3525- * bookmarks list. De-sensitize the button otherwise.
3526- */
3527-static void
3528-bookmarks_check_add_sensitivity (GtkFileChooserDefault *impl)
3529-{
3530- gint num_selected;
3531- gboolean all_folders;
3532- gboolean active;
3533- gchar *tip;
3534-
3535- selection_check (impl, &num_selected, NULL, &all_folders);
3536-
3537- if (num_selected == 0)
3538- active = (impl->current_folder != NULL) && (shortcut_find_position (impl, impl->current_folder) == -1);
3539- else if (num_selected == 1)
3540- {
3541- const GtkFilePath *path;
3542-
3543- path = get_selected_path (impl);
3544- active = all_folders && (shortcut_find_position (impl, path) == -1);
3545- }
3546- else
3547- active = all_folders;
3548-
3549- gtk_widget_set_sensitive (impl->browse_shortcuts_add_button, active);
3550-
3551- if (impl->browse_files_popup_menu_add_shortcut_item)
3552- gtk_widget_set_sensitive (impl->browse_files_popup_menu_add_shortcut_item,
3553- (num_selected == 0) ? FALSE : active);
3554-
3555- if (active)
3556- {
3557- if (num_selected == 0)
3558- tip = g_strdup_printf (_("Add the current folder to the bookmarks"));
3559- else if (num_selected > 1)
3560- tip = g_strdup_printf (_("Add the selected folders to the bookmarks"));
3561- else
3562- {
3563- GtkTreeSelection *selection;
3564- UpdateTooltipData data;
3565-
3566- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
3567- data.impl = impl;
3568- data.tip = NULL;
3569- gtk_tree_selection_selected_foreach (selection, update_tooltip, &data);
3570- tip = data.tip;
3571- }
3572-
3573- gtk_widget_set_tooltip_text (impl->browse_shortcuts_add_button, tip);
3574- g_free (tip);
3575- }
3576-}
3577-
3578-/* Sets the sensitivity of the "remove bookmark" button depending on whether a
3579- * bookmark row is selected in the shortcuts tree.
3580- */
3581-static void
3582-bookmarks_check_remove_sensitivity (GtkFileChooserDefault *impl)
3583-{
3584- GtkTreeIter iter;
3585- gboolean removable = FALSE;
3586- gchar *name = NULL;
3587-
3588- if (shortcuts_get_selected (impl, &iter))
3589- gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter,
3590- SHORTCUTS_COL_REMOVABLE, &removable,
3591- SHORTCUTS_COL_NAME, &name,
3592- -1);
3593-
3594- gtk_widget_set_sensitive (impl->browse_shortcuts_remove_button, removable);
3595-
3596- if (removable)
3597- {
3598- gchar *tip;
3599-
3600- tip = g_strdup_printf (_("Remove the bookmark '%s'"), name);
3601- gtk_widget_set_tooltip_text (impl->browse_shortcuts_remove_button, tip);
3602- g_free (tip);
3603- }
3604-
3605- g_free (name);
3606-}
3607-
3608-static void
3609-shortcuts_check_popup_sensitivity (GtkFileChooserDefault *impl)
3610-{
3611- GtkTreeIter iter;
3612- gboolean removable = FALSE;
3613-
3614- if (impl->browse_shortcuts_popup_menu == NULL)
3615- return;
3616-
3617- if (shortcuts_get_selected (impl, &iter))
3618- gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter,
3619- SHORTCUTS_COL_REMOVABLE, &removable,
3620- -1);
3621-
3622- gtk_widget_set_sensitive (impl->browse_shortcuts_popup_menu_remove_item, removable);
3623- gtk_widget_set_sensitive (impl->browse_shortcuts_popup_menu_rename_item, removable);
3624-}
3625-
3626-/* GtkWidget::drag-begin handler for the shortcuts list. */
3627-static void
3628-shortcuts_drag_begin_cb (GtkWidget *widget,
3629- GdkDragContext *context,
3630- GtkFileChooserDefault *impl)
3631-{
3632-#if 0
3633- impl->shortcuts_drag_context = g_object_ref (context);
3634-#endif
3635-}
3636-
3637-#if 0
3638-/* Removes the idle handler for outside drags */
3639-static void
3640-shortcuts_cancel_drag_outside_idle (GtkFileChooserDefault *impl)
3641-{
3642- if (!impl->shortcuts_drag_outside_idle)
3643- return;
3644-
3645- g_source_destroy (impl->shortcuts_drag_outside_idle);
3646- impl->shortcuts_drag_outside_idle = NULL;
3647-}
3648-#endif
3649-
3650-/* GtkWidget::drag-end handler for the shortcuts list. */
3651-static void
3652-shortcuts_drag_end_cb (GtkWidget *widget,
3653- GdkDragContext *context,
3654- GtkFileChooserDefault *impl)
3655-{
3656-#if 0
3657- g_object_unref (impl->shortcuts_drag_context);
3658-
3659- shortcuts_cancel_drag_outside_idle (impl);
3660-
3661- if (!impl->shortcuts_drag_outside)
3662- return;
3663-
3664- gtk_button_clicked (GTK_BUTTON (impl->browse_shortcuts_remove_button));
3665-
3666- impl->shortcuts_drag_outside = FALSE;
3667-#endif
3668-}
3669-
3670-/* GtkWidget::drag-data-delete handler for the shortcuts list. */
3671-static void
3672-shortcuts_drag_data_delete_cb (GtkWidget *widget,
3673- GdkDragContext *context,
3674- GtkFileChooserDefault *impl)
3675-{
3676- g_signal_stop_emission_by_name (widget, "drag_data_delete");
3677-}
3678-
3679-#if 0
3680-/* Creates a suitable drag cursor to indicate that the selected bookmark will be
3681- * deleted or not.
3682- */
3683-static void
3684-shortcuts_drag_set_delete_cursor (GtkFileChooserDefault *impl,
3685- gboolean delete)
3686-{
3687- GtkTreeView *tree_view;
3688- GtkTreeIter iter;
3689- GtkTreePath *path;
3690- GdkPixmap *row_pixmap;
3691- GdkBitmap *mask;
3692- int row_pixmap_y;
3693- int cell_y;
3694-
3695- tree_view = GTK_TREE_VIEW (impl->browse_shortcuts_tree_view);
3696-
3697- /* Find the selected path and get its drag pixmap */
3698-
3699- if (!shortcuts_get_selected (impl, &iter))
3700- g_assert_not_reached ();
3701-
3702- path = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->shortcuts_model), &iter);
3703-
3704- row_pixmap = gtk_tree_view_create_row_drag_icon (tree_view, path);
3705- gtk_tree_path_free (path);
3706-
3707- mask = NULL;
3708- row_pixmap_y = 0;
3709-
3710- if (delete)
3711- {
3712- GdkPixbuf *pixbuf;
3713-
3714- pixbuf = gtk_widget_render_icon (impl->browse_shortcuts_tree_view,
3715- GTK_STOCK_DELETE,
3716- GTK_ICON_SIZE_DND,
3717- NULL);
3718- if (pixbuf)
3719- {
3720- GdkPixmap *composite;
3721- int row_pixmap_width, row_pixmap_height;
3722- int pixbuf_width, pixbuf_height;
3723- int composite_width, composite_height;
3724- int pixbuf_x, pixbuf_y;
3725- GdkGC *gc, *mask_gc;
3726- GdkColor color;
3727- GdkBitmap *pixbuf_mask;
3728-
3729- /* Create pixmap and mask for composite image */
3730-
3731- gdk_drawable_get_size (row_pixmap, &row_pixmap_width, &row_pixmap_height);
3732- pixbuf_width = gdk_pixbuf_get_width (pixbuf);
3733- pixbuf_height = gdk_pixbuf_get_height (pixbuf);
3734-
3735- composite_width = MAX (row_pixmap_width, pixbuf_width);
3736- composite_height = MAX (row_pixmap_height, pixbuf_height);
3737-
3738- row_pixmap_y = (composite_height - row_pixmap_height) / 2;
3739-
3740- if (gtk_widget_get_direction (impl->browse_shortcuts_tree_view) == GTK_TEXT_DIR_RTL)
3741- pixbuf_x = 0;
3742- else
3743- pixbuf_x = composite_width - pixbuf_width;
3744-
3745- pixbuf_y = (composite_height - pixbuf_height) / 2;
3746-
3747- composite = gdk_pixmap_new (row_pixmap, composite_width, composite_height, -1);
3748- gc = gdk_gc_new (composite);
3749-
3750- mask = gdk_pixmap_new (row_pixmap, composite_width, composite_height, 1);
3751- mask_gc = gdk_gc_new (mask);
3752- color.pixel = 0;
3753- gdk_gc_set_foreground (mask_gc, &color);
3754- gdk_draw_rectangle (mask, mask_gc, TRUE, 0, 0, composite_width, composite_height);
3755-
3756- color.red = 0xffff;
3757- color.green = 0xffff;
3758- color.blue = 0xffff;
3759- gdk_gc_set_rgb_fg_color (gc, &color);
3760- gdk_draw_rectangle (composite, gc, TRUE, 0, 0, composite_width, composite_height);
3761-
3762- /* Composite the row pixmap and the pixbuf */
3763-
3764- gdk_pixbuf_render_pixmap_and_mask_for_colormap
3765- (pixbuf,
3766- gtk_widget_get_colormap (impl->browse_shortcuts_tree_view),
3767- NULL, &pixbuf_mask, 128);
3768- gdk_draw_drawable (mask, mask_gc, pixbuf_mask,
3769- 0, 0,
3770- pixbuf_x, pixbuf_y,
3771- pixbuf_width, pixbuf_height);
3772- g_object_unref (pixbuf_mask);
3773-
3774- gdk_draw_drawable (composite, gc, row_pixmap,
3775- 0, 0,
3776- 0, row_pixmap_y,
3777- row_pixmap_width, row_pixmap_height);
3778- color.pixel = 1;
3779- gdk_gc_set_foreground (mask_gc, &color);
3780- gdk_draw_rectangle (mask, mask_gc, TRUE, 0, row_pixmap_y, row_pixmap_width, row_pixmap_height);
3781-
3782- gdk_draw_pixbuf (composite, gc, pixbuf,
3783- 0, 0,
3784- pixbuf_x, pixbuf_y,
3785- pixbuf_width, pixbuf_height,
3786- GDK_RGB_DITHER_MAX,
3787- 0, 0);
3788-
3789- g_object_unref (pixbuf);
3790- g_object_unref (row_pixmap);
3791-
3792- row_pixmap = composite;
3793- }
3794- }
3795-
3796- /* The hotspot offsets here are copied from gtk_tree_view_drag_begin(), ugh */
3797-
3798- gtk_tree_view_get_path_at_pos (tree_view,
3799- tree_view->priv->press_start_x,
3800- tree_view->priv->press_start_y,
3801- NULL,
3802- NULL,
3803- NULL,
3804- &cell_y);
3805-
3806- gtk_drag_set_icon_pixmap (impl->shortcuts_drag_context,
3807- gdk_drawable_get_colormap (row_pixmap),
3808- row_pixmap,
3809- mask,
3810- tree_view->priv->press_start_x + 1,
3811- row_pixmap_y + cell_y + 1);
3812-
3813- g_object_unref (row_pixmap);
3814- if (mask)
3815- g_object_unref (mask);
3816-}
3817-
3818-/* We set the delete cursor and the shortcuts_drag_outside flag in an idle
3819- * handler so that we can tell apart the drag_leave event that comes right
3820- * before a drag_drop, from a normal drag_leave. We don't want to set the
3821- * cursor nor the flag in the latter case.
3822- */
3823-static gboolean
3824-shortcuts_drag_outside_idle_cb (GtkFileChooserDefault *impl)
3825-{
3826- GDK_THREADS_ENTER ();
3827-
3828- shortcuts_drag_set_delete_cursor (impl, TRUE);
3829- impl->shortcuts_drag_outside = TRUE;
3830-
3831- shortcuts_cancel_drag_outside_idle (impl);
3832-
3833- GDK_THREADS_LEAVE ();
3834-
3835- return FALSE;
3836-}
3837-#endif
3838-
3839-/* GtkWidget::drag-leave handler for the shortcuts list. We unhighlight the
3840- * drop position.
3841- */
3842-static void
3843-shortcuts_drag_leave_cb (GtkWidget *widget,
3844- GdkDragContext *context,
3845- guint time_,
3846- GtkFileChooserDefault *impl)
3847-{
3848-#if 0
3849- if (gtk_drag_get_source_widget (context) == widget && !impl->shortcuts_drag_outside_idle)
3850- {
3851- impl->shortcuts_drag_outside_idle = g_idle_source_new ();
3852- g_source_set_closure (impl->shortcuts_drag_outside_idle,
3853- g_cclosure_new_object (G_CALLBACK (shortcuts_drag_outside_idle_cb),
3854- G_OBJECT (impl)));
3855- g_source_attach (impl->shortcuts_drag_outside_idle, NULL);
3856- }
3857-#endif
3858-
3859- gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view),
3860- NULL,
3861- GTK_TREE_VIEW_DROP_BEFORE);
3862-
3863- g_signal_stop_emission_by_name (widget, "drag_leave");
3864-}
3865-
3866-/* Computes the appropriate row and position for dropping */
3867-static void
3868-shortcuts_compute_drop_position (GtkFileChooserDefault *impl,
3869- int x,
3870- int y,
3871- GtkTreePath **path,
3872- GtkTreeViewDropPosition *pos)
3873-{
3874- GtkTreeView *tree_view;
3875- GtkTreeViewColumn *column;
3876- int cell_y;
3877- GdkRectangle cell;
3878- int row;
3879- int bookmarks_index;
3880-
3881- tree_view = GTK_TREE_VIEW (impl->browse_shortcuts_tree_view);
3882-
3883- bookmarks_index = shortcuts_get_index (impl, SHORTCUTS_BOOKMARKS);
3884-
3885- if (!gtk_tree_view_get_path_at_pos (tree_view,
3886- x,
3887- y - TREE_VIEW_HEADER_HEIGHT (tree_view),
3888- path,
3889- &column,
3890- NULL,
3891- &cell_y))
3892- {
3893- row = bookmarks_index + impl->num_bookmarks - 1;
3894- *path = gtk_tree_path_new_from_indices (row, -1);
3895- *pos = GTK_TREE_VIEW_DROP_AFTER;
3896- return;
3897- }
3898-
3899- row = *gtk_tree_path_get_indices (*path);
3900- gtk_tree_view_get_background_area (tree_view, *path, column, &cell);
3901- gtk_tree_path_free (*path);
3902-
3903- if (row < bookmarks_index)
3904- {
3905- row = bookmarks_index;
3906- *pos = GTK_TREE_VIEW_DROP_BEFORE;
3907- }
3908- else if (row > bookmarks_index + impl->num_bookmarks - 1)
3909- {
3910- row = bookmarks_index + impl->num_bookmarks - 1;
3911- *pos = GTK_TREE_VIEW_DROP_AFTER;
3912- }
3913- else
3914- {
3915- if (cell_y < cell.height / 2)
3916- *pos = GTK_TREE_VIEW_DROP_BEFORE;
3917- else
3918- *pos = GTK_TREE_VIEW_DROP_AFTER;
3919- }
3920-
3921- *path = gtk_tree_path_new_from_indices (row, -1);
3922-}
3923-
3924-/* GtkWidget::drag-motion handler for the shortcuts list. We basically
3925- * implement the destination side of DnD by hand, due to limitations in
3926- * GtkTreeView's DnD API.
3927- */
3928-static gboolean
3929-shortcuts_drag_motion_cb (GtkWidget *widget,
3930- GdkDragContext *context,
3931- gint x,
3932- gint y,
3933- guint time_,
3934- GtkFileChooserDefault *impl)
3935-{
3936- GtkTreePath *path;
3937- GtkTreeViewDropPosition pos;
3938- GdkDragAction action;
3939-
3940-#if 0
3941- if (gtk_drag_get_source_widget (context) == widget)
3942- {
3943- shortcuts_cancel_drag_outside_idle (impl);
3944-
3945- if (impl->shortcuts_drag_outside)
3946- {
3947- shortcuts_drag_set_delete_cursor (impl, FALSE);
3948- impl->shortcuts_drag_outside = FALSE;
3949- }
3950- }
3951-#endif
3952-
3953- if (context->suggested_action == GDK_ACTION_COPY ||
3954- (context->actions & GDK_ACTION_COPY) != 0)
3955- action = GDK_ACTION_COPY;
3956- else if (context->suggested_action == GDK_ACTION_MOVE ||
3957- (context->actions & GDK_ACTION_MOVE) != 0)
3958- action = GDK_ACTION_MOVE;
3959- else
3960- {
3961- action = 0;
3962- goto out;
3963- }
3964-
3965- shortcuts_compute_drop_position (impl, x, y, &path, &pos);
3966- gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view), path, pos);
3967- gtk_tree_path_free (path);
3968-
3969- out:
3970-
3971- g_signal_stop_emission_by_name (widget, "drag_motion");
3972-
3973- if (action != 0)
3974- {
3975- gdk_drag_status (context, action, time_);
3976- return TRUE;
3977- }
3978- else
3979- return FALSE;
3980-}
3981-
3982-/* GtkWidget::drag-drop handler for the shortcuts list. */
3983-static gboolean
3984-shortcuts_drag_drop_cb (GtkWidget *widget,
3985- GdkDragContext *context,
3986- gint x,
3987- gint y,
3988- guint time_,
3989- GtkFileChooserDefault *impl)
3990-{
3991-#if 0
3992- shortcuts_cancel_drag_outside_idle (impl);
3993-#endif
3994-
3995- g_signal_stop_emission_by_name (widget, "drag_drop");
3996- return TRUE;
3997-}
3998-
3999-/* Parses a "text/uri-list" string and inserts its URIs as bookmarks */
4000-static void
4001-shortcuts_drop_uris (GtkFileChooserDefault *impl,
4002- const char *data,
4003- int position)
4004-{
4005- gchar **uris;
4006- gint i;
4007-
4008- uris = g_uri_list_extract_uris (data);
4009-
4010- for (i = 0; uris[i]; i++)
4011- {
4012- char *uri;
4013- GtkFilePath *path;
4014-
4015- uri = uris[i];
4016- path = gtk_file_system_uri_to_path (impl->file_system, uri);
4017-
4018- if (path)
4019- {
4020- if (shortcuts_add_bookmark_from_path (impl, path, position))
4021- position++;
4022-
4023- gtk_file_path_free (path);
4024- }
4025- else
4026- {
4027- GError *error = NULL;
4028-
4029- g_set_error (&error,
4030- GTK_FILE_CHOOSER_ERROR,
4031- GTK_FILE_CHOOSER_ERROR_BAD_FILENAME,
4032- _("Could not add a bookmark for '%s' "
4033- "because it is an invalid path name."),
4034- uri);
4035- error_adding_bookmark_dialog (impl, path, error);
4036- }
4037- }
4038-
4039- g_strfreev (uris);
4040-}
4041-
4042-/* Reorders the selected bookmark to the specified position */
4043-static void
4044-shortcuts_reorder (GtkFileChooserDefault *impl,
4045- int new_position)
4046-{
4047- GtkTreeIter iter;
4048- gpointer col_data;
4049- ShortcutType shortcut_type;
4050- GtkTreePath *path;
4051- int old_position;
4052- int bookmarks_index;
4053- const GtkFilePath *file_path;
4054- GtkFilePath *file_path_copy;
4055- GError *error;
4056- gchar *name;
4057-
4058- /* Get the selected path */
4059-
4060- if (!shortcuts_get_selected (impl, &iter))
4061- g_assert_not_reached ();
4062-
4063- path = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->shortcuts_model), &iter);
4064- old_position = *gtk_tree_path_get_indices (path);
4065- gtk_tree_path_free (path);
4066-
4067- bookmarks_index = shortcuts_get_index (impl, SHORTCUTS_BOOKMARKS);
4068- old_position -= bookmarks_index;
4069- g_assert (old_position >= 0 && old_position < impl->num_bookmarks);
4070-
4071- gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter,
4072- SHORTCUTS_COL_NAME, &name,
4073- SHORTCUTS_COL_DATA, &col_data,
4074- SHORTCUTS_COL_TYPE, &shortcut_type,
4075- -1);
4076- g_assert (col_data != NULL);
4077- g_assert (shortcut_type == SHORTCUT_TYPE_PATH);
4078-
4079- file_path = col_data;
4080- file_path_copy = gtk_file_path_copy (file_path); /* removal below will free file_path, so we need a copy */
4081-
4082- /* Remove the path from the old position and insert it in the new one */
4083-
4084- if (new_position > old_position)
4085- new_position--;
4086-
4087- if (old_position == new_position)
4088- goto out;
4089-
4090- error = NULL;
4091- if (gtk_file_system_remove_bookmark (impl->file_system, file_path_copy, &error))
4092- {
4093- shortcuts_add_bookmark_from_path (impl, file_path_copy, new_position);
4094- gtk_file_system_set_bookmark_label (impl->file_system, file_path_copy, name);
4095- }
4096- else
4097- error_adding_bookmark_dialog (impl, file_path_copy, error);
4098-
4099- out:
4100-
4101- gtk_file_path_free (file_path_copy);
4102-}
4103-
4104-/* Callback used when we get the drag data for the bookmarks list. We add the
4105- * received URIs as bookmarks if they are folders.
4106- */
4107-static void
4108-shortcuts_drag_data_received_cb (GtkWidget *widget,
4109- GdkDragContext *context,
4110- gint x,
4111- gint y,
4112- GtkSelectionData *selection_data,
4113- guint info,
4114- guint time_,
4115- gpointer data)
4116-{
4117- GtkFileChooserDefault *impl;
4118- GtkTreePath *tree_path;
4119- GtkTreeViewDropPosition tree_pos;
4120- int position;
4121- int bookmarks_index;
4122-
4123- impl = GTK_FILE_CHOOSER_DEFAULT (data);
4124-
4125- /* Compute position */
4126-
4127- bookmarks_index = shortcuts_get_index (impl, SHORTCUTS_BOOKMARKS);
4128-
4129- shortcuts_compute_drop_position (impl, x, y, &tree_path, &tree_pos);
4130- position = *gtk_tree_path_get_indices (tree_path);
4131- gtk_tree_path_free (tree_path);
4132-
4133- if (tree_pos == GTK_TREE_VIEW_DROP_AFTER)
4134- position++;
4135-
4136- g_assert (position >= bookmarks_index);
4137- position -= bookmarks_index;
4138-
4139- if (selection_data->target == gdk_atom_intern_static_string ("text/uri-list"))
4140- shortcuts_drop_uris (impl, (const char *) selection_data->data, position);
4141- else if (selection_data->target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
4142- shortcuts_reorder (impl, position);
4143-
4144- g_signal_stop_emission_by_name (widget, "drag_data_received");
4145-}
4146-
4147-/* Callback used when the selection in the shortcuts tree changes */
4148-static void
4149-shortcuts_selection_changed_cb (GtkTreeSelection *selection,
4150- GtkFileChooserDefault *impl)
4151-{
4152- bookmarks_check_remove_sensitivity (impl);
4153- shortcuts_check_popup_sensitivity (impl);
4154-}
4155-
4156-static gboolean
4157-shortcuts_row_separator_func (GtkTreeModel *model,
4158- GtkTreeIter *iter,
4159- gpointer data)
4160-{
4161- ShortcutType shortcut_type;
4162-
4163- gtk_tree_model_get (model, iter, SHORTCUTS_COL_TYPE, &shortcut_type, -1);
4164-
4165- return shortcut_type == SHORTCUT_TYPE_SEPARATOR;
4166-}
4167-
4168-/* Since GtkTreeView has a keybinding attached to '/', we need to catch
4169- * keypresses before the TreeView gets them.
4170- */
4171-static gboolean
4172-tree_view_keybinding_cb (GtkWidget *tree_view,
4173- GdkEventKey *event,
4174- GtkFileChooserDefault *impl)
4175-{
4176- if ((event->keyval == GDK_slash
4177- || event->keyval == GDK_KP_Divide
4178-#ifdef G_OS_UNIX
4179- || event->keyval == GDK_asciitilde
4180-#endif
4181- ) && ! (event->state & (~GDK_SHIFT_MASK & gtk_accelerator_get_default_mod_mask ())))
4182- {
4183- location_popup_handler (impl, event->string);
4184- return TRUE;
4185- }
4186-
4187- return FALSE;
4188-}
4189-
4190-/* Callback used when the file list's popup menu is detached */
4191-static void
4192-shortcuts_popup_menu_detach_cb (GtkWidget *attach_widget,
4193- GtkMenu *menu)
4194-{
4195- GtkFileChooserDefault *impl;
4196-
4197- impl = g_object_get_data (G_OBJECT (attach_widget), "GtkFileChooserDefault");
4198- g_assert (GTK_IS_FILE_CHOOSER_DEFAULT (impl));
4199-
4200- impl->browse_shortcuts_popup_menu = NULL;
4201- impl->browse_shortcuts_popup_menu_remove_item = NULL;
4202- impl->browse_shortcuts_popup_menu_rename_item = NULL;
4203-}
4204-
4205-static void
4206-remove_shortcut_cb (GtkMenuItem *item,
4207- GtkFileChooserDefault *impl)
4208-{
4209- remove_selected_bookmarks (impl);
4210-}
4211-
4212-/* Rename the selected bookmark */
4213-static void
4214-rename_selected_bookmark (GtkFileChooserDefault *impl)
4215-{
4216- GtkTreeIter iter;
4217- GtkTreePath *path;
4218- GtkTreeViewColumn *column;
4219- GtkCellRenderer *cell;
4220- GList *renderers;
4221-
4222- if (shortcuts_get_selected (impl, &iter))
4223- {
4224- path = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->shortcuts_model), &iter);
4225- column = gtk_tree_view_get_column (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view), 0);
4226- renderers = gtk_tree_view_column_get_cell_renderers (column);
4227- cell = g_list_nth_data (renderers, 1);
4228- g_list_free (renderers);
4229- g_object_set (cell, "editable", TRUE, NULL);
4230- gtk_tree_view_set_cursor_on_cell (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view),
4231- path, column, cell, TRUE);
4232- gtk_tree_path_free (path);
4233- }
4234-}
4235-
4236-static void
4237-rename_shortcut_cb (GtkMenuItem *item,
4238- GtkFileChooserDefault *impl)
4239-{
4240- rename_selected_bookmark (impl);
4241-}
4242-
4243-/* Constructs the popup menu for the file list if needed */
4244-static void
4245-shortcuts_build_popup_menu (GtkFileChooserDefault *impl)
4246-{
4247- GtkWidget *item;
4248-
4249- if (impl->browse_shortcuts_popup_menu)
4250- return;
4251-
4252- impl->browse_shortcuts_popup_menu = gtk_menu_new ();
4253- gtk_menu_attach_to_widget (GTK_MENU (impl->browse_shortcuts_popup_menu),
4254- impl->browse_shortcuts_tree_view,
4255- shortcuts_popup_menu_detach_cb);
4256-
4257- item = gtk_image_menu_item_new_with_label (_("Remove"));
4258- impl->browse_shortcuts_popup_menu_remove_item = item;
4259- gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item),
4260- gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU));
4261- g_signal_connect (item, "activate",
4262- G_CALLBACK (remove_shortcut_cb), impl);
4263- gtk_widget_show (item);
4264- gtk_menu_shell_append (GTK_MENU_SHELL (impl->browse_shortcuts_popup_menu), item);
4265-
4266- item = gtk_menu_item_new_with_label (_("Rename..."));
4267- impl->browse_shortcuts_popup_menu_rename_item = item;
4268- g_signal_connect (item, "activate",
4269- G_CALLBACK (rename_shortcut_cb), impl);
4270- gtk_widget_show (item);
4271- gtk_menu_shell_append (GTK_MENU_SHELL (impl->browse_shortcuts_popup_menu), item);
4272-
4273- shortcuts_check_popup_sensitivity (impl);
4274-}
4275-
4276-static void
4277-shortcuts_update_popup_menu (GtkFileChooserDefault *impl)
4278-{
4279- shortcuts_build_popup_menu (impl);
4280-}
4281-
4282-static void
4283-popup_position_func (GtkMenu *menu,
4284- gint *x,
4285- gint *y,
4286- gboolean *push_in,
4287- gpointer user_data);
4288-
4289-static void
4290-shortcuts_popup_menu (GtkFileChooserDefault *impl,
4291- GdkEventButton *event)
4292-{
4293- shortcuts_update_popup_menu (impl);
4294- if (event)
4295- gtk_menu_popup (GTK_MENU (impl->browse_shortcuts_popup_menu),
4296- NULL, NULL, NULL, NULL,
4297- event->button, event->time);
4298- else
4299- {
4300- gtk_menu_popup (GTK_MENU (impl->browse_shortcuts_popup_menu),
4301- NULL, NULL,
4302- popup_position_func, impl->browse_shortcuts_tree_view,
4303- 0, GDK_CURRENT_TIME);
4304- gtk_menu_shell_select_first (GTK_MENU_SHELL (impl->browse_shortcuts_popup_menu),
4305- FALSE);
4306- }
4307-}
4308-
4309-/* Callback used for the GtkWidget::popup-menu signal of the shortcuts list */
4310-static gboolean
4311-shortcuts_popup_menu_cb (GtkWidget *widget,
4312- GtkFileChooserDefault *impl)
4313-{
4314- shortcuts_popup_menu (impl, NULL);
4315- return TRUE;
4316-}
4317-
4318-/* Callback used when a button is pressed on the shortcuts list.
4319- * We trap button 3 to bring up a popup menu.
4320- */
4321-static gboolean
4322-shortcuts_button_press_event_cb (GtkWidget *widget,
4323- GdkEventButton *event,
4324- GtkFileChooserDefault *impl)
4325-{
4326- static gboolean in_press = FALSE;
4327- gboolean handled;
4328-
4329- if (in_press)
4330- return FALSE;
4331-
4332- if (event->button != 3)
4333- return FALSE;
4334-
4335- in_press = TRUE;
4336- handled = gtk_widget_event (impl->browse_shortcuts_tree_view, (GdkEvent *) event);
4337- in_press = FALSE;
4338-
4339- if (!handled)
4340- return FALSE;
4341-
4342- shortcuts_popup_menu (impl, event);
4343- return TRUE;
4344-}
4345-
4346-static void
4347-shortcuts_edited (GtkCellRenderer *cell,
4348- gchar *path_string,
4349- gchar *new_text,
4350- GtkFileChooserDefault *impl)
4351-{
4352- GtkTreePath *path;
4353- GtkTreeIter iter;
4354- GtkFilePath *shortcut;
4355-
4356- g_object_set (cell, "editable", FALSE, NULL);
4357-
4358- path = gtk_tree_path_new_from_string (path_string);
4359- if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->shortcuts_model), &iter, path))
4360- g_assert_not_reached ();
4361-
4362- gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter,
4363- SHORTCUTS_COL_DATA, &shortcut,
4364- -1);
4365- gtk_tree_path_free (path);
4366-
4367- gtk_file_system_set_bookmark_label (impl->file_system, shortcut, new_text);
4368-}
4369-
4370-static void
4371-shortcuts_editing_canceled (GtkCellRenderer *cell,
4372- GtkFileChooserDefault *impl)
4373-{
4374- g_object_set (cell, "editable", FALSE, NULL);
4375-}
4376-
4377-/* Creates the widgets for the shortcuts and bookmarks tree */
4378-static GtkWidget *
4379-shortcuts_list_create (GtkFileChooserDefault *impl)
4380-{
4381- GtkWidget *swin;
4382- GtkTreeSelection *selection;
4383- GtkTreeViewColumn *column;
4384- GtkCellRenderer *renderer;
4385-
4386- /* Scrolled window */
4387-
4388- swin = gtk_scrolled_window_new (NULL, NULL);
4389- gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swin),
4390- GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
4391- gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (swin),
4392- GTK_SHADOW_IN);
4393- gtk_widget_show (swin);
4394-
4395- /* Tree */
4396-
4397- impl->browse_shortcuts_tree_view = gtk_tree_view_new ();
4398-#ifdef PROFILE_FILE_CHOOSER
4399- g_object_set_data (G_OBJECT (impl->browse_shortcuts_tree_view), "fmq-name", "shortcuts");
4400-#endif
4401- g_signal_connect (impl->browse_shortcuts_tree_view, "key_press_event",
4402- G_CALLBACK (tree_view_keybinding_cb), impl);
4403- g_signal_connect (impl->browse_shortcuts_tree_view, "popup_menu",
4404- G_CALLBACK (shortcuts_popup_menu_cb), impl);
4405- g_signal_connect (impl->browse_shortcuts_tree_view, "button_press_event",
4406- G_CALLBACK (shortcuts_button_press_event_cb), impl);
4407- /* Accessible object name for the file chooser's shortcuts pane */
4408- atk_object_set_name (gtk_widget_get_accessible (impl->browse_shortcuts_tree_view), _("Places"));
4409-
4410- gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view), impl->shortcuts_pane_filter_model);
4411-
4412- gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view),
4413- GDK_BUTTON1_MASK,
4414- shortcuts_source_targets,
4415- num_shortcuts_source_targets,
4416- GDK_ACTION_MOVE);
4417-
4418- gtk_drag_dest_set (impl->browse_shortcuts_tree_view,
4419- GTK_DEST_DEFAULT_ALL,
4420- shortcuts_dest_targets,
4421- num_shortcuts_dest_targets,
4422- GDK_ACTION_COPY | GDK_ACTION_MOVE);
4423-
4424- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view));
4425- gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
4426- gtk_tree_selection_set_select_function (selection,
4427- shortcuts_select_func,
4428- impl, NULL);
4429-
4430- g_signal_connect (selection, "changed",
4431- G_CALLBACK (shortcuts_selection_changed_cb), impl);
4432-
4433- g_signal_connect (impl->browse_shortcuts_tree_view, "row_activated",
4434- G_CALLBACK (shortcuts_row_activated_cb), impl);
4435-
4436- g_signal_connect (impl->browse_shortcuts_tree_view, "key_press_event",
4437- G_CALLBACK (shortcuts_key_press_event_cb), impl);
4438-
4439- g_signal_connect (impl->browse_shortcuts_tree_view, "drag_begin",
4440- G_CALLBACK (shortcuts_drag_begin_cb), impl);
4441- g_signal_connect (impl->browse_shortcuts_tree_view, "drag_end",
4442- G_CALLBACK (shortcuts_drag_end_cb), impl);
4443- g_signal_connect (impl->browse_shortcuts_tree_view, "drag_data_delete",
4444- G_CALLBACK (shortcuts_drag_data_delete_cb), impl);
4445-
4446- g_signal_connect (impl->browse_shortcuts_tree_view, "drag_leave",
4447- G_CALLBACK (shortcuts_drag_leave_cb), impl);
4448- g_signal_connect (impl->browse_shortcuts_tree_view, "drag_motion",
4449- G_CALLBACK (shortcuts_drag_motion_cb), impl);
4450- g_signal_connect (impl->browse_shortcuts_tree_view, "drag_drop",
4451- G_CALLBACK (shortcuts_drag_drop_cb), impl);
4452- g_signal_connect (impl->browse_shortcuts_tree_view, "drag_data_received",
4453- G_CALLBACK (shortcuts_drag_data_received_cb), impl);
4454-
4455- gtk_container_add (GTK_CONTAINER (swin), impl->browse_shortcuts_tree_view);
4456- gtk_widget_show (impl->browse_shortcuts_tree_view);
4457-
4458- /* Column */
4459-
4460- column = gtk_tree_view_column_new ();
4461- /* Column header for the file chooser's shortcuts pane */
4462- gtk_tree_view_column_set_title (column, _("_Places"));
4463-
4464- renderer = gtk_cell_renderer_pixbuf_new ();
4465- gtk_tree_view_column_pack_start (column, renderer, FALSE);
4466- gtk_tree_view_column_set_attributes (column, renderer,
4467- "pixbuf", SHORTCUTS_COL_PIXBUF,
4468- "visible", SHORTCUTS_COL_PIXBUF_VISIBLE,
4469- NULL);
4470-
4471- renderer = gtk_cell_renderer_text_new ();
4472- g_signal_connect (renderer, "edited",
4473- G_CALLBACK (shortcuts_edited), impl);
4474- g_signal_connect (renderer, "editing-canceled",
4475- G_CALLBACK (shortcuts_editing_canceled), impl);
4476- gtk_tree_view_column_pack_start (column, renderer, TRUE);
4477- gtk_tree_view_column_set_attributes (column, renderer,
4478- "text", SHORTCUTS_COL_NAME,
4479- NULL);
4480-
4481- gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view),
4482- shortcuts_row_separator_func,
4483- NULL, NULL);
4484-
4485- gtk_tree_view_append_column (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view), column);
4486-
4487- return swin;
4488-}
4489-
4490-/* Creates the widgets for the shortcuts/bookmarks pane */
4491-static GtkWidget *
4492-shortcuts_pane_create (GtkFileChooserDefault *impl,
4493- GtkSizeGroup *size_group)
4494-{
4495- GtkWidget *vbox;
4496- GtkWidget *hbox;
4497- GtkWidget *widget;
4498-
4499- vbox = gtk_vbox_new (FALSE, 6);
4500- gtk_widget_show (vbox);
4501-
4502- /* Shortcuts tree */
4503-
4504- widget = shortcuts_list_create (impl);
4505- gtk_box_pack_start (GTK_BOX (vbox), widget, TRUE, TRUE, 0);
4506-
4507- /* Box for buttons */
4508-
4509- hbox = gtk_hbox_new (TRUE, 6);
4510- gtk_size_group_add_widget (size_group, hbox);
4511- gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
4512- gtk_widget_show (hbox);
4513-
4514- /* Add bookmark button */
4515-
4516- impl->browse_shortcuts_add_button = button_new (impl,
4517- _("_Add"),
4518- GTK_STOCK_ADD,
4519- FALSE,
4520- TRUE,
4521- G_CALLBACK (add_bookmark_button_clicked_cb));
4522- gtk_box_pack_start (GTK_BOX (hbox), impl->browse_shortcuts_add_button, TRUE, TRUE, 0);
4523- gtk_widget_set_tooltip_text (impl->browse_shortcuts_add_button,
4524- _("Add the selected folder to the Bookmarks"));
4525-
4526- /* Remove bookmark button */
4527-
4528- impl->browse_shortcuts_remove_button = button_new (impl,
4529- _("_Remove"),
4530- GTK_STOCK_REMOVE,
4531- FALSE,
4532- TRUE,
4533- G_CALLBACK (remove_bookmark_button_clicked_cb));
4534- gtk_box_pack_start (GTK_BOX (hbox), impl->browse_shortcuts_remove_button, TRUE, TRUE, 0);
4535- gtk_widget_set_tooltip_text (impl->browse_shortcuts_remove_button,
4536- _("Remove the selected bookmark"));
4537-
4538- return vbox;
4539-}
4540-
4541-/* Handles key press events on the file list, so that we can trap Enter to
4542- * activate the default button on our own. Also, checks to see if '/' has been
4543- * pressed. See comment by tree_view_keybinding_cb() for more details.
4544- */
4545-static gboolean
4546-trap_activate_cb (GtkWidget *widget,
4547- GdkEventKey *event,
4548- gpointer data)
4549-{
4550- GtkFileChooserDefault *impl;
4551- int modifiers;
4552-
4553- impl = (GtkFileChooserDefault *) data;
4554-
4555- modifiers = gtk_accelerator_get_default_mod_mask ();
4556-
4557- if ((event->keyval == GDK_slash
4558- || event->keyval == GDK_KP_Divide
4559-#ifdef G_OS_UNIX
4560- || event->keyval == GDK_asciitilde
4561-#endif
4562- ) && ! (event->state & (~GDK_SHIFT_MASK & modifiers)))
4563- {
4564- location_popup_handler (impl, event->string);
4565- return TRUE;
4566- }
4567-
4568- if ((event->keyval == GDK_Return
4569- || event->keyval == GDK_ISO_Enter
4570- || event->keyval == GDK_KP_Enter
4571- || event->keyval == GDK_space)
4572- && ((event->state & modifiers) == 0)
4573- && !(impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
4574- impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER))
4575- {
4576- GtkWindow *window;
4577-
4578- window = get_toplevel (widget);
4579- if (window
4580- && widget != window->default_widget
4581- && !(widget == window->focus_widget &&
4582- (!window->default_widget || !GTK_WIDGET_SENSITIVE (window->default_widget))))
4583- {
4584- gtk_window_activate_default (window);
4585- return TRUE;
4586- }
4587- }
4588-
4589- return FALSE;
4590-}
4591-
4592-/* Callback used when the file list's popup menu is detached */
4593-static void
4594-popup_menu_detach_cb (GtkWidget *attach_widget,
4595- GtkMenu *menu)
4596-{
4597- GtkFileChooserDefault *impl;
4598-
4599- impl = g_object_get_data (G_OBJECT (attach_widget), "GtkFileChooserDefault");
4600- g_assert (GTK_IS_FILE_CHOOSER_DEFAULT (impl));
4601-
4602- impl->browse_files_popup_menu = NULL;
4603- impl->browse_files_popup_menu_add_shortcut_item = NULL;
4604- impl->browse_files_popup_menu_hidden_files_item = NULL;
4605-}
4606-
4607-/* Callback used when the "Add to Bookmarks" menu item is activated */
4608-static void
4609-add_to_shortcuts_cb (GtkMenuItem *item,
4610- GtkFileChooserDefault *impl)
4611-{
4612- bookmarks_add_selected_folder (impl);
4613-}
4614-
4615-/* Callback used when the "Show Hidden Files" menu item is toggled */
4616-static void
4617-show_hidden_toggled_cb (GtkCheckMenuItem *item,
4618- GtkFileChooserDefault *impl)
4619-{
4620- g_object_set (impl,
4621- "show-hidden", gtk_check_menu_item_get_active (item),
4622- NULL);
4623-}
4624-
4625-/* Shows an error dialog about not being able to select a dragged file */
4626-static void
4627-error_selecting_dragged_file_dialog (GtkFileChooserDefault *impl,
4628- const GtkFilePath *path,
4629- GError *error)
4630-{
4631- error_dialog (impl,
4632- _("Could not select file"),
4633- path, error);
4634-}
4635-
4636-static void
4637-file_list_drag_data_select_uris (GtkFileChooserDefault *impl,
4638- gchar **uris)
4639-{
4640- int i;
4641- char *uri;
4642- GtkFileChooser *chooser = GTK_FILE_CHOOSER (impl);
4643-
4644- for (i = 1; uris[i]; i++)
4645- {
4646- GtkFilePath *path;
4647-
4648- uri = uris[i];
4649- path = gtk_file_system_uri_to_path (impl->file_system, uri);
4650-
4651- if (path)
4652- {
4653- GError *error = NULL;
4654-
4655- gtk_file_chooser_default_select_path (chooser, path, &error);
4656- if (error)
4657- error_selecting_dragged_file_dialog (impl, path, error);
4658-
4659- gtk_file_path_free (path);
4660- }
4661- }
4662-}
4663-
4664-struct FileListDragData
4665-{
4666- GtkFileChooserDefault *impl;
4667- gchar **uris;
4668- GtkFilePath *path;
4669-};
4670-
4671-static void
4672-file_list_drag_data_received_get_info_cb (GtkFileSystemHandle *handle,
4673- const GtkFileInfo *info,
4674- const GError *error,
4675- gpointer user_data)
4676-{
4677- gboolean cancelled = handle->cancelled;
4678- struct FileListDragData *data = user_data;
4679- GtkFileChooser *chooser = GTK_FILE_CHOOSER (data->impl);
4680-
4681- if (handle != data->impl->file_list_drag_data_received_handle)
4682- goto out;
4683-
4684- data->impl->file_list_drag_data_received_handle = NULL;
4685-
4686- if (cancelled || error)
4687- goto out;
4688-
4689- if ((data->impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
4690- data->impl->action == GTK_FILE_CHOOSER_ACTION_SAVE) &&
4691- data->uris[1] == 0 && !error &&
4692- gtk_file_info_get_is_folder (info))
4693- change_folder_and_display_error (data->impl, data->path, FALSE);
4694- else
4695- {
4696- GError *error = NULL;
4697-
4698- gtk_file_chooser_default_unselect_all (chooser);
4699- gtk_file_chooser_default_select_path (chooser, data->path, &error);
4700- if (error)
4701- error_selecting_dragged_file_dialog (data->impl, data->path, error);
4702- else
4703- browse_files_center_selected_row (data->impl);
4704- }
4705-
4706- if (data->impl->select_multiple)
4707- file_list_drag_data_select_uris (data->impl, data->uris);
4708-
4709-out:
4710- g_object_unref (data->impl);
4711- g_strfreev (data->uris);
4712- gtk_file_path_free (data->path);
4713- g_free (data);
4714-
4715- g_object_unref (handle);
4716-}
4717-
4718-static void
4719-file_list_drag_data_received_cb (GtkWidget *widget,
4720- GdkDragContext *context,
4721- gint x,
4722- gint y,
4723- GtkSelectionData *selection_data,
4724- guint info,
4725- guint time_,
4726- gpointer data)
4727-{
4728- GtkFileChooserDefault *impl;
4729- GtkFileChooser *chooser;
4730- gchar **uris;
4731- char *uri;
4732- GtkFilePath *path;
4733- GError *error = NULL;
4734-
4735- impl = GTK_FILE_CHOOSER_DEFAULT (data);
4736- chooser = GTK_FILE_CHOOSER (data);
4737-
4738- /* Parse the text/uri-list string, navigate to the first one */
4739- uris = g_uri_list_extract_uris ((const char *) selection_data->data);
4740- if (uris[0])
4741- {
4742- uri = uris[0];
4743- path = gtk_file_system_uri_to_path (impl->file_system, uri);
4744-
4745- if (path)
4746- {
4747- struct FileListDragData *data;
4748-
4749- data = g_new0 (struct FileListDragData, 1);
4750- data->impl = g_object_ref (impl);
4751- data->uris = uris;
4752- data->path = path;
4753-
4754- if (impl->file_list_drag_data_received_handle)
4755- gtk_file_system_cancel_operation (impl->file_list_drag_data_received_handle);
4756-
4757- impl->file_list_drag_data_received_handle =
4758- gtk_file_system_get_info (impl->file_system, path,
4759- GTK_FILE_INFO_IS_FOLDER,
4760- file_list_drag_data_received_get_info_cb,
4761- data);
4762- goto out;
4763- }
4764- else
4765- {
4766- g_set_error (&error,
4767- GTK_FILE_CHOOSER_ERROR,
4768- GTK_FILE_CHOOSER_ERROR_BAD_FILENAME,
4769- _("Could not select file '%s' "
4770- "because it is an invalid path name."),
4771- uri);
4772- error_selecting_dragged_file_dialog (impl, NULL, error);
4773- }
4774-
4775- if (impl->select_multiple)
4776- file_list_drag_data_select_uris (impl, uris);
4777- }
4778-
4779- g_strfreev (uris);
4780-
4781-out:
4782- g_signal_stop_emission_by_name (widget, "drag_data_received");
4783-}
4784-
4785-/* Don't do anything with the drag_drop signal */
4786-static gboolean
4787-file_list_drag_drop_cb (GtkWidget *widget,
4788- GdkDragContext *context,
4789- gint x,
4790- gint y,
4791- guint time_,
4792- GtkFileChooserDefault *impl)
4793-{
4794- g_signal_stop_emission_by_name (widget, "drag_drop");
4795- return TRUE;
4796-}
4797-
4798-/* Disable the normal tree drag motion handler, it makes it look like you're
4799- dropping the dragged item onto a tree item */
4800-static gboolean
4801-file_list_drag_motion_cb (GtkWidget *widget,
4802- GdkDragContext *context,
4803- gint x,
4804- gint y,
4805- guint time_,
4806- GtkFileChooserDefault *impl)
4807-{
4808- g_signal_stop_emission_by_name (widget, "drag_motion");
4809- return TRUE;
4810-}
4811-
4812-/* Constructs the popup menu for the file list if needed */
4813-static void
4814-file_list_build_popup_menu (GtkFileChooserDefault *impl)
4815-{
4816- GtkWidget *item;
4817-
4818- if (impl->browse_files_popup_menu)
4819- return;
4820-
4821- impl->browse_files_popup_menu = gtk_menu_new ();
4822- gtk_menu_attach_to_widget (GTK_MENU (impl->browse_files_popup_menu),
4823- impl->browse_files_tree_view,
4824- popup_menu_detach_cb);
4825-
4826- item = gtk_image_menu_item_new_with_mnemonic (_("_Add to Bookmarks"));
4827- impl->browse_files_popup_menu_add_shortcut_item = item;
4828- gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item),
4829- gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU));
4830- gtk_widget_set_sensitive (item, FALSE);
4831- g_signal_connect (item, "activate",
4832- G_CALLBACK (add_to_shortcuts_cb), impl);
4833- gtk_widget_show (item);
4834- gtk_menu_shell_append (GTK_MENU_SHELL (impl->browse_files_popup_menu), item);
4835-
4836- item = gtk_separator_menu_item_new ();
4837- gtk_widget_show (item);
4838- gtk_menu_shell_append (GTK_MENU_SHELL (impl->browse_files_popup_menu), item);
4839-
4840- item = gtk_check_menu_item_new_with_mnemonic (_("Show _Hidden Files"));
4841- impl->browse_files_popup_menu_hidden_files_item = item;
4842- g_signal_connect (item, "toggled",
4843- G_CALLBACK (show_hidden_toggled_cb), impl);
4844- gtk_widget_show (item);
4845- gtk_menu_shell_append (GTK_MENU_SHELL (impl->browse_files_popup_menu), item);
4846-}
4847-
4848-/* Updates the popup menu for the file list, creating it if necessary */
4849-static void
4850-file_list_update_popup_menu (GtkFileChooserDefault *impl)
4851-{
4852- file_list_build_popup_menu (impl);
4853-
4854- /* FIXME - handle OPERATION_MODE_SEARCH and OPERATION_MODE_RECENT */
4855-
4856- /* The sensitivity of the Add to Bookmarks item is set in
4857- * bookmarks_check_add_sensitivity()
4858- */
4859-
4860- g_signal_handlers_block_by_func (impl->browse_files_popup_menu_hidden_files_item,
4861- G_CALLBACK (show_hidden_toggled_cb), impl);
4862- gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (impl->browse_files_popup_menu_hidden_files_item),
4863- impl->show_hidden);
4864- g_signal_handlers_unblock_by_func (impl->browse_files_popup_menu_hidden_files_item,
4865- G_CALLBACK (show_hidden_toggled_cb), impl);
4866-}
4867-
4868-static void
4869-popup_position_func (GtkMenu *menu,
4870- gint *x,
4871- gint *y,
4872- gboolean *push_in,
4873- gpointer user_data)
4874-{
4875- GtkWidget *widget = GTK_WIDGET (user_data);
4876- GdkScreen *screen = gtk_widget_get_screen (widget);
4877- GtkRequisition req;
4878- gint monitor_num;
4879- GdkRectangle monitor;
4880-
4881- g_return_if_fail (GTK_WIDGET_REALIZED (widget));
4882-
4883- gdk_window_get_origin (widget->window, x, y);
4884-
4885- gtk_widget_size_request (GTK_WIDGET (menu), &req);
4886-
4887- *x += (widget->allocation.width - req.width) / 2;
4888- *y += (widget->allocation.height - req.height) / 2;
4889-
4890- monitor_num = gdk_screen_get_monitor_at_point (screen, *x, *y);
4891- gtk_menu_set_monitor (menu, monitor_num);
4892- gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
4893-
4894- *x = CLAMP (*x, monitor.x, monitor.x + MAX (0, monitor.width - req.width));
4895- *y = CLAMP (*y, monitor.y, monitor.y + MAX (0, monitor.height - req.height));
4896-
4897- *push_in = FALSE;
4898-}
4899-
4900-static void
4901-file_list_popup_menu (GtkFileChooserDefault *impl,
4902- GdkEventButton *event)
4903-{
4904- file_list_update_popup_menu (impl);
4905- if (event)
4906- gtk_menu_popup (GTK_MENU (impl->browse_files_popup_menu),
4907- NULL, NULL, NULL, NULL,
4908- event->button, event->time);
4909- else
4910- {
4911- gtk_menu_popup (GTK_MENU (impl->browse_files_popup_menu),
4912- NULL, NULL,
4913- popup_position_func, impl->browse_files_tree_view,
4914- 0, GDK_CURRENT_TIME);
4915- gtk_menu_shell_select_first (GTK_MENU_SHELL (impl->browse_files_popup_menu),
4916- FALSE);
4917- }
4918-
4919-}
4920-
4921-/* Callback used for the GtkWidget::popup-menu signal of the file list */
4922-static gboolean
4923-list_popup_menu_cb (GtkWidget *widget,
4924- GtkFileChooserDefault *impl)
4925-{
4926- file_list_popup_menu (impl, NULL);
4927- return TRUE;
4928-}
4929-
4930-/* Callback used when a button is pressed on the file list. We trap button 3 to
4931- * bring up a popup menu.
4932- */
4933-static gboolean
4934-list_button_press_event_cb (GtkWidget *widget,
4935- GdkEventButton *event,
4936- GtkFileChooserDefault *impl)
4937-{
4938- static gboolean in_press = FALSE;
4939- gboolean handled;
4940-
4941- if (in_press)
4942- return FALSE;
4943-
4944- if (event->button != 3)
4945- return FALSE;
4946-
4947- in_press = TRUE;
4948- handled = gtk_widget_event (impl->browse_files_tree_view, (GdkEvent *) event);
4949- in_press = FALSE;
4950-
4951- file_list_popup_menu (impl, event);
4952- return TRUE;
4953-}
4954-
4955-/* Sets the sort column IDs for the file list based on the operation mode */
4956-static void
4957-file_list_set_sort_column_ids (GtkFileChooserDefault *impl)
4958-{
4959- int name_id, mtime_id;
4960-
4961- name_id = mtime_id = 0;
4962-
4963- switch (impl->operation_mode)
4964- {
4965- case OPERATION_MODE_BROWSE:
4966- name_id = FILE_LIST_COL_NAME;
4967- mtime_id = FILE_LIST_COL_MTIME;
4968- break;
4969- case OPERATION_MODE_SEARCH:
4970- name_id = SEARCH_MODEL_COL_PATH;
4971- mtime_id = SEARCH_MODEL_COL_STAT;
4972- break;
4973- case OPERATION_MODE_RECENT:
4974- name_id = RECENT_MODEL_COL_PATH;
4975- mtime_id = RECENT_MODEL_COL_INFO;
4976- break;
4977- }
4978-
4979- gtk_tree_view_column_set_sort_column_id (impl->list_name_column, name_id);
4980- gtk_tree_view_column_set_sort_column_id (impl->list_mtime_column, mtime_id);
4981-}
4982-
4983-static gboolean
4984-file_list_query_tooltip_cb (GtkWidget *widget,
4985- gint x,
4986- gint y,
4987- gboolean keyboard_tip,
4988- GtkTooltip *tooltip,
4989- gpointer user_data)
4990-{
4991- GtkFileChooserDefault *impl = user_data;
4992- GtkTreeIter iter, child_iter;
4993- GtkTreePath *path = NULL;
4994- GtkFilePath *file_path = NULL;
4995- gchar *filename;
4996-
4997- if (impl->operation_mode == OPERATION_MODE_BROWSE)
4998- return FALSE;
4999-
5000-
5001- gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (impl->browse_files_tree_view),
5002- &x, &y,
5003- keyboard_tip,
5004- NULL, &path, NULL);
5005-
5006- if (!path)
5007- return FALSE;
5008-
5009- switch (impl->operation_mode)
5010- {
5011- case OPERATION_MODE_SEARCH:
5012- if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->search_model_sort), &iter, path))
5013- {
5014- gtk_tree_path_free (path);
5015- return FALSE;
5016- }
5017-
5018- search_get_valid_child_iter (impl, &child_iter, &iter);
5019- gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &child_iter,
5020- SEARCH_MODEL_COL_PATH, &file_path,
5021- -1);
5022- break;
5023-
5024- case OPERATION_MODE_RECENT:
5025- if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->recent_model_sort), &iter, path))
5026- {
5027- gtk_tree_path_free (path);
5028- return FALSE;
5029- }
5030-
5031- recent_get_valid_child_iter (impl, &child_iter, &iter);
5032- gtk_tree_model_get (GTK_TREE_MODEL (impl->recent_model), &child_iter,
5033- RECENT_MODEL_COL_PATH, &file_path,
5034- -1);
5035- break;
5036-
5037- case OPERATION_MODE_BROWSE:
5038- g_assert_not_reached ();
5039- return FALSE;
5040- }
5041-
5042- if (!file_path)
5043- {
5044- gtk_tree_path_free (path);
5045- return FALSE;
5046- }
5047-
5048- filename = gtk_file_system_path_to_filename (impl->file_system, file_path);
5049- gtk_tooltip_set_text (tooltip, filename);
5050- gtk_tree_view_set_tooltip_row (GTK_TREE_VIEW (impl->browse_files_tree_view),
5051- tooltip,
5052- path);
5053-
5054- g_free (filename);
5055- gtk_tree_path_free (path);
5056-
5057- return TRUE;
5058-}
5059-
5060-/* Creates the widgets for the file list */
5061-static GtkWidget *
5062-create_file_list (GtkFileChooserDefault *impl)
5063-{
5064- GtkWidget *swin;
5065- GtkTreeSelection *selection;
5066- GtkTreeViewColumn *column;
5067- GtkCellRenderer *renderer;
5068-
5069- /* Scrolled window */
5070-
5071- swin = gtk_scrolled_window_new (NULL, NULL);
5072- gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swin),
5073- GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
5074- gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (swin),
5075- GTK_SHADOW_IN);
5076-
5077- /* Tree/list view */
5078-
5079- impl->browse_files_tree_view = gtk_tree_view_new ();
5080-#ifdef PROFILE_FILE_CHOOSER
5081- g_object_set_data (G_OBJECT (impl->browse_files_tree_view), "fmq-name", "file_list");
5082-#endif
5083- g_object_set_data (G_OBJECT (impl->browse_files_tree_view), I_("GtkFileChooserDefault"), impl);
5084- atk_object_set_name (gtk_widget_get_accessible (impl->browse_files_tree_view), _("Files"));
5085-
5086- gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (impl->browse_files_tree_view), TRUE);
5087- gtk_container_add (GTK_CONTAINER (swin), impl->browse_files_tree_view);
5088-
5089- gtk_drag_dest_set (impl->browse_files_tree_view,
5090- GTK_DEST_DEFAULT_ALL,
5091- file_list_dest_targets,
5092- num_file_list_dest_targets,
5093- GDK_ACTION_COPY | GDK_ACTION_MOVE);
5094-
5095- g_signal_connect (impl->browse_files_tree_view, "row_activated",
5096- G_CALLBACK (list_row_activated), impl);
5097- g_signal_connect (impl->browse_files_tree_view, "key_press_event",
5098- G_CALLBACK (trap_activate_cb), impl);
5099- g_signal_connect (impl->browse_files_tree_view, "popup_menu",
5100- G_CALLBACK (list_popup_menu_cb), impl);
5101- g_signal_connect (impl->browse_files_tree_view, "button_press_event",
5102- G_CALLBACK (list_button_press_event_cb), impl);
5103-
5104- g_signal_connect (impl->browse_files_tree_view, "drag_data_received",
5105- G_CALLBACK (file_list_drag_data_received_cb), impl);
5106- g_signal_connect (impl->browse_files_tree_view, "drag_drop",
5107- G_CALLBACK (file_list_drag_drop_cb), impl);
5108- g_signal_connect (impl->browse_files_tree_view, "drag_motion",
5109- G_CALLBACK (file_list_drag_motion_cb), impl);
5110-
5111- g_object_set (impl->browse_files_tree_view, "has-tooltip", TRUE, NULL);
5112- g_signal_connect (impl->browse_files_tree_view, "query-tooltip",
5113- G_CALLBACK (file_list_query_tooltip_cb), impl);
5114-
5115- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
5116- gtk_tree_selection_set_select_function (selection,
5117- list_select_func,
5118- impl, NULL);
5119- gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (impl->browse_files_tree_view),
5120- GDK_BUTTON1_MASK,
5121- file_list_source_targets,
5122- num_file_list_source_targets,
5123- GDK_ACTION_COPY);
5124-
5125- g_signal_connect (selection, "changed",
5126- G_CALLBACK (list_selection_changed), impl);
5127-
5128- /* Filename column */
5129-
5130- impl->list_name_column = gtk_tree_view_column_new ();
5131- gtk_tree_view_column_set_expand (impl->list_name_column, TRUE);
5132- gtk_tree_view_column_set_resizable (impl->list_name_column, TRUE);
5133- gtk_tree_view_column_set_title (impl->list_name_column, _("Name"));
5134- gtk_tree_view_column_set_sort_column_id (impl->list_name_column, FILE_LIST_COL_NAME);
5135-
5136- renderer = gtk_cell_renderer_pixbuf_new ();
5137- gtk_tree_view_column_pack_start (impl->list_name_column, renderer, FALSE);
5138- gtk_tree_view_column_set_cell_data_func (impl->list_name_column, renderer,
5139- list_icon_data_func, impl, NULL);
5140-
5141- impl->list_name_renderer = gtk_cell_renderer_text_new ();
5142- g_object_set (impl->list_name_renderer,
5143- "ellipsize", PANGO_ELLIPSIZE_END,
5144- NULL);
5145- g_signal_connect (impl->list_name_renderer, "edited",
5146- G_CALLBACK (renderer_edited_cb), impl);
5147- g_signal_connect (impl->list_name_renderer, "editing_canceled",
5148- G_CALLBACK (renderer_editing_canceled_cb), impl);
5149- gtk_tree_view_column_pack_start (impl->list_name_column, impl->list_name_renderer, TRUE);
5150- gtk_tree_view_column_set_cell_data_func (impl->list_name_column, impl->list_name_renderer,
5151- list_name_data_func, impl, NULL);
5152-
5153- gtk_tree_view_append_column (GTK_TREE_VIEW (impl->browse_files_tree_view), impl->list_name_column);
5154-#if 0
5155- /* Size column */
5156-
5157- column = gtk_tree_view_column_new ();
5158- gtk_tree_view_column_set_title (column, _("Size"));
5159-
5160- renderer = gtk_cell_renderer_text_new ();
5161- gtk_tree_view_column_pack_start (column, renderer, TRUE); /* bug: it doesn't expand */
5162- gtk_tree_view_column_set_cell_data_func (column, renderer,
5163- list_size_data_func, impl, NULL);
5164- gtk_tree_view_column_set_sort_column_id (column, FILE_LIST_COL_SIZE);
5165- gtk_tree_view_append_column (GTK_TREE_VIEW (impl->browse_files_tree_view), column);
5166-#endif
5167-
5168- /* Modification time column */
5169-
5170- column = gtk_tree_view_column_new ();
5171- gtk_tree_view_column_set_resizable (column, TRUE);
5172- gtk_tree_view_column_set_title (column, _("Modified"));
5173-
5174- renderer = gtk_cell_renderer_text_new ();
5175- gtk_tree_view_column_pack_start (column, renderer, TRUE);
5176- gtk_tree_view_column_set_cell_data_func (column, renderer,
5177- list_mtime_data_func, impl, NULL);
5178- gtk_tree_view_append_column (GTK_TREE_VIEW (impl->browse_files_tree_view), column);
5179- impl->list_mtime_column = column;
5180-
5181- file_list_set_sort_column_ids (impl);
5182-
5183- gtk_widget_show_all (swin);
5184-
5185- return swin;
5186-}
5187-
5188-static GtkWidget *
5189-create_path_bar (GtkFileChooserDefault *impl)
5190-{
5191- GtkWidget *path_bar;
5192-
5193- path_bar = g_object_new (GTK_TYPE_PATH_BAR, NULL);
5194- _gtk_path_bar_set_file_system (GTK_PATH_BAR (path_bar), impl->file_system);
5195-
5196- return path_bar;
5197-}
5198-
5199-/* Creates the widgets for the files/folders pane */
5200-static GtkWidget *
5201-file_pane_create (GtkFileChooserDefault *impl,
5202- GtkSizeGroup *size_group)
5203-{
5204- GtkWidget *vbox;
5205- GtkWidget *hbox;
5206- GtkWidget *widget;
5207-
5208- vbox = gtk_vbox_new (FALSE, 6);
5209- gtk_widget_show (vbox);
5210-
5211- /* Box for lists and preview */
5212-
5213- hbox = gtk_hbox_new (FALSE, PREVIEW_HBOX_SPACING);
5214- gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
5215- gtk_widget_show (hbox);
5216-
5217- /* File list */
5218-
5219- widget = create_file_list (impl);
5220- gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 0);
5221-
5222- /* Preview */
5223-
5224- impl->preview_box = gtk_vbox_new (FALSE, 12);
5225- gtk_box_pack_start (GTK_BOX (hbox), impl->preview_box, FALSE, FALSE, 0);
5226- /* Don't show preview box initially */
5227-
5228- /* Filter combo */
5229-
5230- impl->filter_combo_hbox = gtk_hbox_new (FALSE, 12);
5231-
5232- widget = filter_create (impl);
5233-
5234- gtk_widget_show (widget);
5235- gtk_box_pack_end (GTK_BOX (impl->filter_combo_hbox), widget, FALSE, FALSE, 0);
5236-
5237- gtk_size_group_add_widget (size_group, impl->filter_combo_hbox);
5238- gtk_box_pack_end (GTK_BOX (vbox), impl->filter_combo_hbox, FALSE, FALSE, 0);
5239-
5240- return vbox;
5241-}
5242-
5243-/* Callback used when the "Browse for more folders" expander is toggled */
5244-static void
5245-expander_changed_cb (GtkExpander *expander,
5246- GParamSpec *pspec,
5247- GtkFileChooserDefault *impl)
5248-{
5249- impl->expand_folders = gtk_expander_get_expanded(GTK_EXPANDER (impl->save_expander));
5250- update_appearance (impl);
5251-}
5252-
5253-/* Callback used when the selection changes in the save folder combo box */
5254-static void
5255-save_folder_combo_changed_cb (GtkComboBox *combo,
5256- GtkFileChooserDefault *impl)
5257-{
5258- GtkTreeIter iter;
5259-
5260- if (impl->changing_folder)
5261- return;
5262-
5263- if (gtk_combo_box_get_active_iter (combo, &iter))
5264- {
5265- GtkTreeIter child_iter;
5266-
5267- gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (impl->shortcuts_combo_filter_model),
5268- &child_iter,
5269- &iter);
5270- shortcuts_activate_iter (impl, &child_iter);
5271- }
5272-}
5273-
5274-/* Filter function used to filter out the Search item and its separator.
5275- * Used for the "Save in folder" combo box, so that these items do not appear in it.
5276- */
5277-static gboolean
5278-shortcuts_combo_filter_func (GtkTreeModel *model,
5279- GtkTreeIter *iter,
5280- gpointer data)
5281-{
5282- GtkFileChooserDefault *impl;
5283- GtkTreePath *tree_path;
5284- gint *indices;
5285- int idx;
5286- gboolean retval;
5287-
5288- impl = GTK_FILE_CHOOSER_DEFAULT (data);
5289-
5290- g_assert (model == GTK_TREE_MODEL (impl->shortcuts_model));
5291-
5292- tree_path = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->shortcuts_model), iter);
5293- g_assert (tree_path != NULL);
5294-
5295- indices = gtk_tree_path_get_indices (tree_path);
5296-
5297- retval = TRUE;
5298-
5299- if (impl->has_search)
5300- {
5301- idx = shortcuts_get_index (impl, SHORTCUTS_SEARCH);
5302- if (idx == indices[0])
5303- retval = FALSE;
5304- }
5305-
5306- if (impl->has_recent)
5307- {
5308- idx = shortcuts_get_index (impl, SHORTCUTS_RECENT);
5309- if (idx == indices[0])
5310- retval = FALSE;
5311- else
5312- {
5313- idx = shortcuts_get_index (impl, SHORTCUTS_RECENT_SEPARATOR);
5314- if (idx == indices[0])
5315- retval = FALSE;
5316- }
5317- }
5318-
5319- gtk_tree_path_free (tree_path);
5320-
5321- return retval;
5322- }
5323-
5324-/* Creates the combo box with the save folders */
5325-static GtkWidget *
5326-save_folder_combo_create (GtkFileChooserDefault *impl)
5327-{
5328- GtkWidget *combo;
5329- GtkCellRenderer *cell;
5330-
5331- impl->shortcuts_combo_filter_model = gtk_tree_model_filter_new (GTK_TREE_MODEL (impl->shortcuts_model), NULL);
5332- gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (impl->shortcuts_combo_filter_model),
5333- shortcuts_combo_filter_func,
5334- impl,
5335- NULL);
5336-
5337- combo = g_object_new (GTK_TYPE_COMBO_BOX,
5338- "model", impl->shortcuts_combo_filter_model,
5339- "focus-on-click", FALSE,
5340- NULL);
5341- gtk_widget_show (combo);
5342-
5343- cell = gtk_cell_renderer_pixbuf_new ();
5344- gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, FALSE);
5345- gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), cell,
5346- "pixbuf", SHORTCUTS_COL_PIXBUF,
5347- "visible", SHORTCUTS_COL_PIXBUF_VISIBLE,
5348- "sensitive", SHORTCUTS_COL_PIXBUF_VISIBLE,
5349- NULL);
5350-
5351- cell = gtk_cell_renderer_text_new ();
5352- gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, TRUE);
5353- gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), cell,
5354- "text", SHORTCUTS_COL_NAME,
5355- "sensitive", SHORTCUTS_COL_PIXBUF_VISIBLE,
5356- NULL);
5357-
5358- gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (combo),
5359- shortcuts_row_separator_func,
5360- NULL, NULL);
5361-
5362- g_signal_connect (combo, "changed",
5363- G_CALLBACK (save_folder_combo_changed_cb), impl);
5364-
5365- return combo;
5366-}
5367-
5368-/* Creates the widgets specific to Save mode */
5369-static void
5370-save_widgets_create (GtkFileChooserDefault *impl)
5371-{
5372- GtkWidget *vbox;
5373- GtkWidget *table;
5374- GtkWidget *widget;
5375- GtkWidget *alignment;
5376-
5377- if (impl->save_widgets != NULL)
5378- return;
5379-
5380- location_switch_to_path_bar (impl);
5381-
5382- vbox = gtk_vbox_new (FALSE, 12);
5383-
5384- table = gtk_table_new (2, 2, FALSE);
5385- gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
5386- gtk_widget_show (table);
5387- gtk_table_set_row_spacings (GTK_TABLE (table), 12);
5388- gtk_table_set_col_spacings (GTK_TABLE (table), 12);
5389-
5390- /* Label */
5391-
5392- widget = gtk_label_new_with_mnemonic (_("_Name:"));
5393- gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
5394- gtk_table_attach (GTK_TABLE (table), widget,
5395- 0, 1, 0, 1,
5396- GTK_FILL, GTK_FILL,
5397- 0, 0);
5398- gtk_widget_show (widget);
5399-
5400- /* Location entry */
5401-
5402- impl->location_entry = _gtk_file_chooser_entry_new (TRUE);
5403- _gtk_file_chooser_entry_set_file_system (GTK_FILE_CHOOSER_ENTRY (impl->location_entry),
5404- impl->file_system);
5405- gtk_entry_set_width_chars (GTK_ENTRY (impl->location_entry), 45);
5406- gtk_entry_set_activates_default (GTK_ENTRY (impl->location_entry), TRUE);
5407- gtk_table_attach (GTK_TABLE (table), impl->location_entry,
5408- 1, 2, 0, 1,
5409- GTK_EXPAND | GTK_FILL, 0,
5410- 0, 0);
5411- gtk_widget_show (impl->location_entry);
5412- gtk_label_set_mnemonic_widget (GTK_LABEL (widget), impl->location_entry);
5413-
5414- /* Folder combo */
5415- impl->save_folder_label = gtk_label_new (NULL);
5416- gtk_misc_set_alignment (GTK_MISC (impl->save_folder_label), 0.0, 0.5);
5417- gtk_table_attach (GTK_TABLE (table), impl->save_folder_label,
5418- 0, 1, 1, 2,
5419- GTK_FILL, GTK_FILL,
5420- 0, 0);
5421- gtk_widget_show (impl->save_folder_label);
5422-
5423- impl->save_folder_combo = save_folder_combo_create (impl);
5424- gtk_table_attach (GTK_TABLE (table), impl->save_folder_combo,
5425- 1, 2, 1, 2,
5426- GTK_EXPAND | GTK_FILL, GTK_FILL,
5427- 0, 0);
5428- gtk_label_set_mnemonic_widget (GTK_LABEL (impl->save_folder_label), impl->save_folder_combo);
5429-
5430- /* Expander */
5431- alignment = gtk_alignment_new (0.0, 0.5, 1.0, 1.0);
5432- gtk_box_pack_start (GTK_BOX (vbox), alignment, FALSE, FALSE, 0);
5433-
5434- impl->save_expander = gtk_expander_new_with_mnemonic (_("_Browse for other folders"));
5435- gtk_container_add (GTK_CONTAINER (alignment), impl->save_expander);
5436- g_signal_connect (impl->save_expander, "notify::expanded",
5437- G_CALLBACK (expander_changed_cb),
5438- impl);
5439- gtk_widget_show_all (alignment);
5440-
5441- impl->save_widgets = vbox;
5442- gtk_box_pack_start (GTK_BOX (impl), impl->save_widgets, FALSE, FALSE, 0);
5443- gtk_box_reorder_child (GTK_BOX (impl), impl->save_widgets, 0);
5444- gtk_widget_show (impl->save_widgets);
5445-}
5446-
5447-/* Destroys the widgets specific to Save mode */
5448-static void
5449-save_widgets_destroy (GtkFileChooserDefault *impl)
5450-{
5451- if (impl->save_widgets == NULL)
5452- return;
5453-
5454- gtk_widget_destroy (impl->save_widgets);
5455- impl->save_widgets = NULL;
5456- impl->location_entry = NULL;
5457- impl->save_folder_label = NULL;
5458- impl->save_folder_combo = NULL;
5459- impl->save_expander = NULL;
5460-}
5461-
5462-/* Turns on the path bar widget. Can be called even if we are already in that
5463- * mode.
5464- */
5465-static void
5466-location_switch_to_path_bar (GtkFileChooserDefault *impl)
5467-{
5468- if (impl->location_entry)
5469- {
5470- gtk_widget_destroy (impl->location_entry);
5471- impl->location_entry = NULL;
5472- }
5473-
5474- gtk_widget_hide (impl->location_entry_box);
5475-}
5476-
5477-/* Sets the full path of the current folder as the text in the location entry. */
5478-static void
5479-location_entry_set_initial_text (GtkFileChooserDefault *impl)
5480-{
5481- char *text;
5482-
5483- if (!impl->current_folder)
5484- return;
5485-
5486- if (gtk_file_system_path_is_local (impl->file_system, impl->current_folder))
5487- {
5488- char *filename;
5489-
5490- filename = gtk_file_system_path_to_filename (impl->file_system, impl->current_folder);
5491- if (filename)
5492- {
5493- text = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL);
5494- g_free (filename);
5495- }
5496- else
5497- text = NULL;
5498- }
5499- else
5500- text = gtk_file_system_path_to_uri (impl->file_system, impl->current_folder);
5501-
5502- if (text)
5503- {
5504- gboolean need_slash;
5505- int len;
5506-
5507- len = strlen (text);
5508- need_slash = (text[len - 1] != G_DIR_SEPARATOR);
5509-
5510- if (need_slash)
5511- {
5512- char *slash_text;
5513-
5514- slash_text = g_new (char, len + 2);
5515- strcpy (slash_text, text);
5516- slash_text[len] = G_DIR_SEPARATOR;
5517- slash_text[len + 1] = 0;
5518-
5519- g_free (text);
5520- text = slash_text;
5521- }
5522-
5523- _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), text);
5524- g_free (text);
5525- }
5526-}
5527-
5528-/* Turns on the location entry. Can be called even if we are already in that
5529- * mode.
5530- */
5531-static void
5532-location_switch_to_filename_entry (GtkFileChooserDefault *impl)
5533-{
5534- /* when in search or recent files mode, we are not showing the
5535- * location_entry_box container, so there's no point in switching
5536- * to it.
5537- */
5538- if (impl->operation_mode == OPERATION_MODE_SEARCH ||
5539- impl->operation_mode == OPERATION_MODE_RECENT)
5540- return;
5541-
5542- if (impl->location_entry)
5543- gtk_widget_destroy (impl->location_entry);
5544-
5545- /* Box */
5546-
5547- gtk_widget_show (impl->location_entry_box);
5548-
5549- /* Entry */
5550-
5551- impl->location_entry = _gtk_file_chooser_entry_new (TRUE);
5552- _gtk_file_chooser_entry_set_file_system (GTK_FILE_CHOOSER_ENTRY (impl->location_entry),
5553- impl->file_system);
5554- gtk_entry_set_activates_default (GTK_ENTRY (impl->location_entry), TRUE);
5555- _gtk_file_chooser_entry_set_action (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), impl->action);
5556-
5557- gtk_box_pack_start (GTK_BOX (impl->location_entry_box), impl->location_entry, TRUE, TRUE, 0);
5558- gtk_label_set_mnemonic_widget (GTK_LABEL (impl->location_label), impl->location_entry);
5559-
5560- /* Configure the entry */
5561-
5562- _gtk_file_chooser_entry_set_base_folder (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), impl->current_folder);
5563-
5564- /* Done */
5565-
5566- gtk_widget_show (impl->location_entry);
5567- gtk_widget_grab_focus (impl->location_entry);
5568-}
5569-
5570-/* Sets a new location mode. set_buttons determines whether the toggle button
5571- * for the mode will also be changed.
5572- */
5573-static void
5574-location_mode_set (GtkFileChooserDefault *impl,
5575- LocationMode new_mode,
5576- gboolean set_button)
5577-{
5578- if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
5579- impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
5580- {
5581- GtkWindow *toplevel;
5582- GtkWidget *current_focus;
5583- gboolean button_active;
5584- gboolean switch_to_file_list;
5585-
5586- switch (new_mode)
5587- {
5588- case LOCATION_MODE_PATH_BAR:
5589- button_active = FALSE;
5590-
5591- /* The location_entry will disappear when we switch to path bar mode. So,
5592- * we'll focus the file list in that case, to avoid having a window with
5593- * no focused widget.
5594- */
5595- toplevel = get_toplevel (GTK_WIDGET (impl));
5596- switch_to_file_list = FALSE;
5597- if (toplevel)
5598- {
5599- current_focus = gtk_window_get_focus (toplevel);
5600- if (!current_focus || current_focus == impl->location_entry)
5601- switch_to_file_list = TRUE;
5602- }
5603-
5604- location_switch_to_path_bar (impl);
5605-
5606- if (switch_to_file_list)
5607- gtk_widget_grab_focus (impl->browse_files_tree_view);
5608-
5609- break;
5610-
5611- case LOCATION_MODE_FILENAME_ENTRY:
5612- button_active = TRUE;
5613- location_switch_to_filename_entry (impl);
5614- break;
5615-
5616- default:
5617- g_assert_not_reached ();
5618- return;
5619- }
5620-
5621- if (set_button)
5622- {
5623- g_signal_handlers_block_by_func (impl->location_button,
5624- G_CALLBACK (location_button_toggled_cb), impl);
5625-
5626- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (impl->location_button), button_active);
5627-
5628- g_signal_handlers_unblock_by_func (impl->location_button,
5629- G_CALLBACK (location_button_toggled_cb), impl);
5630- }
5631- }
5632-
5633- impl->location_mode = new_mode;
5634-}
5635-
5636-static void
5637-location_toggle_popup_handler (GtkFileChooserDefault *impl)
5638-{
5639- /* If the file entry is not visible, show it.
5640- * If it is visible, turn it off only if it is focused. Otherwise, switch to the entry.
5641- */
5642- if (impl->location_mode == LOCATION_MODE_PATH_BAR)
5643- {
5644- location_mode_set (impl, LOCATION_MODE_FILENAME_ENTRY, TRUE);
5645- }
5646- else if (impl->location_mode == LOCATION_MODE_FILENAME_ENTRY)
5647- {
5648- if (GTK_WIDGET_HAS_FOCUS (impl->location_entry))
5649- {
5650- location_mode_set (impl, LOCATION_MODE_PATH_BAR, TRUE);
5651- }
5652- else
5653- {
5654- gtk_widget_grab_focus (impl->location_entry);
5655- }
5656- }
5657-}
5658-
5659-/* Callback used when one of the location mode buttons is toggled */
5660-static void
5661-location_button_toggled_cb (GtkToggleButton *toggle,
5662- GtkFileChooserDefault *impl)
5663-{
5664- gboolean is_active;
5665- LocationMode new_mode;
5666-
5667- is_active = gtk_toggle_button_get_active (toggle);
5668-
5669- if (is_active)
5670- {
5671- g_assert (impl->location_mode == LOCATION_MODE_PATH_BAR);
5672- new_mode = LOCATION_MODE_FILENAME_ENTRY;
5673- }
5674- else
5675- {
5676- g_assert (impl->location_mode == LOCATION_MODE_FILENAME_ENTRY);
5677- new_mode = LOCATION_MODE_PATH_BAR;
5678- }
5679-
5680- location_mode_set (impl, new_mode, FALSE);
5681-}
5682-
5683-/* Creates a toggle button for the location entry. */
5684-static void
5685-location_button_create (GtkFileChooserDefault *impl)
5686-{
5687- GtkWidget *image;
5688- const char *str;
5689-
5690- image = gtk_image_new_from_stock (GTK_STOCK_EDIT, GTK_ICON_SIZE_BUTTON);
5691- gtk_widget_show (image);
5692-
5693- impl->location_button = g_object_new (GTK_TYPE_TOGGLE_BUTTON,
5694- "image", image,
5695- NULL);
5696-
5697- g_signal_connect (impl->location_button, "toggled",
5698- G_CALLBACK (location_button_toggled_cb), impl);
5699-
5700- str = _("Type a file name");
5701-
5702- gtk_widget_set_tooltip_text (impl->location_button, str);
5703- atk_object_set_name (gtk_widget_get_accessible (impl->location_button), str);
5704-}
5705-
5706-/* Creates the main hpaned with the widgets shared by Open and Save mode */
5707-static GtkWidget *
5708-browse_widgets_create (GtkFileChooserDefault *impl)
5709-{
5710- GtkWidget *vbox;
5711- GtkWidget *hbox;
5712- GtkWidget *hpaned;
5713- GtkWidget *widget;
5714- GtkSizeGroup *size_group;
5715-
5716- /* size group is used by the [+][-] buttons and the filter combo */
5717- size_group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL);
5718- vbox = gtk_vbox_new (FALSE, 12);
5719-
5720- /* Location widgets */
5721- hbox = gtk_hbox_new (FALSE, 12);
5722- gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
5723- gtk_widget_show (hbox);
5724- impl->browse_path_bar_hbox = hbox;
5725-
5726- location_button_create (impl);
5727- gtk_box_pack_start (GTK_BOX (hbox), impl->location_button, FALSE, FALSE, 0);
5728-
5729- /* Path bar */
5730-
5731- impl->browse_path_bar = create_path_bar (impl);
5732- g_signal_connect (impl->browse_path_bar, "path-clicked", G_CALLBACK (path_bar_clicked), impl);
5733- gtk_widget_show_all (impl->browse_path_bar);
5734- gtk_box_pack_start (GTK_BOX (hbox), impl->browse_path_bar, TRUE, TRUE, 0);
5735-
5736- /* Create Folder */
5737- impl->browse_new_folder_button = gtk_button_new_with_mnemonic (_("Create Fo_lder"));
5738- g_signal_connect (impl->browse_new_folder_button, "clicked",
5739- G_CALLBACK (new_folder_button_clicked), impl);
5740- gtk_box_pack_end (GTK_BOX (hbox), impl->browse_new_folder_button, FALSE, FALSE, 0);
5741-
5742- /* Box for the location label and entry */
5743-
5744- impl->location_entry_box = gtk_hbox_new (FALSE, 12);
5745- gtk_box_pack_start (GTK_BOX (vbox), impl->location_entry_box, FALSE, FALSE, 0);
5746-
5747- impl->location_label = gtk_label_new_with_mnemonic (_("_Location:"));
5748- gtk_widget_show (impl->location_label);
5749- gtk_box_pack_start (GTK_BOX (impl->location_entry_box), impl->location_label, FALSE, FALSE, 0);
5750-
5751- /* Paned widget */
5752- hpaned = gtk_hpaned_new ();
5753- gtk_widget_show (hpaned);
5754- gtk_box_pack_start (GTK_BOX (vbox), hpaned, TRUE, TRUE, 0);
5755-
5756- widget = shortcuts_pane_create (impl, size_group);
5757- gtk_paned_pack1 (GTK_PANED (hpaned), widget, FALSE, FALSE);
5758- widget = file_pane_create (impl, size_group);
5759- gtk_paned_pack2 (GTK_PANED (hpaned), widget, TRUE, FALSE);
5760-
5761- g_object_unref (size_group);
5762-
5763- return vbox;
5764-}
5765-
5766-static GObject*
5767-gtk_file_chooser_default_constructor (GType type,
5768- guint n_construct_properties,
5769- GObjectConstructParam *construct_params)
5770-{
5771- GtkFileChooserDefault *impl;
5772- GObject *object;
5773-
5774- profile_start ("start", NULL);
5775-
5776- object = G_OBJECT_CLASS (_gtk_file_chooser_default_parent_class)->constructor (type,
5777- n_construct_properties,
5778- construct_params);
5779- impl = GTK_FILE_CHOOSER_DEFAULT (object);
5780-
5781- g_assert (impl->file_system);
5782-
5783- gtk_widget_push_composite_child ();
5784-
5785- /* Recent files manager */
5786- recent_manager_update (impl);
5787-
5788- /* Shortcuts model */
5789- shortcuts_model_create (impl);
5790-
5791- /* The browse widgets */
5792- impl->browse_widgets = browse_widgets_create (impl);
5793- gtk_box_pack_start (GTK_BOX (impl), impl->browse_widgets, TRUE, TRUE, 0);
5794-
5795- /* Alignment to hold extra widget */
5796- impl->extra_align = gtk_alignment_new (0.0, 0.5, 1.0, 1.0);
5797- gtk_box_pack_start (GTK_BOX (impl), impl->extra_align, FALSE, FALSE, 0);
5798-
5799- gtk_widget_pop_composite_child ();
5800- update_appearance (impl);
5801-
5802- profile_end ("end", NULL);
5803-
5804- return object;
5805-}
5806-
5807-/* Sets the extra_widget by packing it in the appropriate place */
5808-static void
5809-set_extra_widget (GtkFileChooserDefault *impl,
5810- GtkWidget *extra_widget)
5811-{
5812- if (extra_widget)
5813- {
5814- g_object_ref (extra_widget);
5815- /* FIXME: is this right ? */
5816- gtk_widget_show (extra_widget);
5817- }
5818-
5819- if (impl->extra_widget)
5820- {
5821- gtk_container_remove (GTK_CONTAINER (impl->extra_align), impl->extra_widget);
5822- g_object_unref (impl->extra_widget);
5823- }
5824-
5825- impl->extra_widget = extra_widget;
5826- if (impl->extra_widget)
5827- {
5828- gtk_container_add (GTK_CONTAINER (impl->extra_align), impl->extra_widget);
5829- gtk_widget_show (impl->extra_align);
5830- }
5831- else
5832- gtk_widget_hide (impl->extra_align);
5833-}
5834-
5835-static void
5836-set_local_only (GtkFileChooserDefault *impl,
5837- gboolean local_only)
5838-{
5839- if (local_only != impl->local_only)
5840- {
5841- impl->local_only = local_only;
5842-
5843- if (impl->shortcuts_model && impl->file_system)
5844- {
5845- shortcuts_add_volumes (impl);
5846- shortcuts_add_bookmarks (impl);
5847- }
5848-
5849- if (local_only &&
5850- !gtk_file_system_path_is_local (impl->file_system, impl->current_folder))
5851- {
5852- /* If we are pointing to a non-local folder, make an effort to change
5853- * back to a local folder, but it's really up to the app to not cause
5854- * such a situation, so we ignore errors.
5855- */
5856- const gchar *home = g_get_home_dir ();
5857- GtkFilePath *home_path;
5858-
5859- if (home == NULL)
5860- return;
5861-
5862- home_path = gtk_file_system_filename_to_path (impl->file_system, home);
5863-
5864- _gtk_file_chooser_set_current_folder_path (GTK_FILE_CHOOSER (impl), home_path, NULL);
5865-
5866- gtk_file_path_free (home_path);
5867- }
5868- }
5869-}
5870-
5871-static void
5872-volumes_changed_cb (GtkFileSystem *file_system,
5873- GtkFileChooserDefault *impl)
5874-{
5875- shortcuts_add_volumes (impl);
5876-}
5877-
5878-/* Callback used when the set of bookmarks changes in the file system */
5879-static void
5880-bookmarks_changed_cb (GtkFileSystem *file_system,
5881- GtkFileChooserDefault *impl)
5882-{
5883- shortcuts_add_bookmarks (impl);
5884-
5885- bookmarks_check_add_sensitivity (impl);
5886- bookmarks_check_remove_sensitivity (impl);
5887- shortcuts_check_popup_sensitivity (impl);
5888-}
5889-
5890-/* Sets the file chooser to multiple selection mode */
5891-static void
5892-set_select_multiple (GtkFileChooserDefault *impl,
5893- gboolean select_multiple,
5894- gboolean property_notify)
5895-{
5896- GtkTreeSelection *selection;
5897- GtkSelectionMode mode;
5898-
5899- if (select_multiple == impl->select_multiple)
5900- return;
5901-
5902- mode = select_multiple ? GTK_SELECTION_MULTIPLE : GTK_SELECTION_BROWSE;
5903-
5904- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
5905- gtk_tree_selection_set_mode (selection, mode);
5906-
5907- impl->select_multiple = select_multiple;
5908- g_object_notify (G_OBJECT (impl), "select-multiple");
5909-
5910- check_preview_change (impl);
5911-}
5912-
5913-static void
5914-set_file_system_backend (GtkFileChooserDefault *impl,
5915- const char *backend)
5916-{
5917- profile_start ("start for backend", backend ? backend : "default");
5918-
5919- if (impl->file_system)
5920- {
5921- g_signal_handler_disconnect (impl->file_system, impl->volumes_changed_id);
5922- impl->volumes_changed_id = 0;
5923- g_signal_handler_disconnect (impl->file_system, impl->bookmarks_changed_id);
5924- impl->bookmarks_changed_id = 0;
5925- g_object_unref (impl->file_system);
5926- }
5927-
5928- impl->file_system = NULL;
5929- if (backend)
5930- impl->file_system = gtk_file_system_create (backend);
5931- else
5932- {
5933- GtkSettings *settings = gtk_settings_get_default ();
5934- gchar *default_backend = NULL;
5935-
5936- g_object_get (settings, "gtk-file-chooser-backend", &default_backend, NULL);
5937- if (default_backend)
5938- {
5939- impl->file_system = gtk_file_system_create (default_backend);
5940- g_free (default_backend);
5941- }
5942- }
5943-
5944- if (!impl->file_system)
5945- {
5946-#if defined (G_OS_UNIX)
5947- impl->file_system = gtk_file_system_unix_new ();
5948-#elif defined (G_OS_WIN32)
5949- impl->file_system = gtk_file_system_win32_new ();
5950-#else
5951-#error "No default filesystem implementation on the platform"
5952-#endif
5953- }
5954-
5955- if (impl->file_system)
5956- {
5957- impl->volumes_changed_id = g_signal_connect (impl->file_system, "volumes-changed",
5958- G_CALLBACK (volumes_changed_cb),
5959- impl);
5960- impl->bookmarks_changed_id = g_signal_connect (impl->file_system, "bookmarks-changed",
5961- G_CALLBACK (bookmarks_changed_cb),
5962- impl);
5963- }
5964-
5965- profile_end ("end", NULL);
5966-}
5967-
5968-/* This function is basically a do_all function.
5969- *
5970- * It sets the visibility on all the widgets based on the current state, and
5971- * moves the custom_widget if needed.
5972- */
5973-static void
5974-update_appearance (GtkFileChooserDefault *impl)
5975-{
5976- if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE ||
5977- impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
5978- {
5979- const char *text;
5980-
5981- gtk_widget_hide (impl->location_button);
5982- save_widgets_create (impl);
5983-
5984- if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
5985- text = _("Save in _folder:");
5986- else
5987- text = _("Create in _folder:");
5988-
5989- gtk_label_set_text_with_mnemonic (GTK_LABEL (impl->save_folder_label), text);
5990-
5991- if (gtk_expander_get_expanded (GTK_EXPANDER (impl->save_expander)))
5992- {
5993- gtk_widget_set_sensitive (impl->save_folder_label, FALSE);
5994- gtk_widget_set_sensitive (impl->save_folder_combo, FALSE);
5995- gtk_widget_show (impl->browse_widgets);
5996- }
5997- else
5998- {
5999- gtk_widget_set_sensitive (impl->save_folder_label, TRUE);
6000- gtk_widget_set_sensitive (impl->save_folder_combo, TRUE);
6001- gtk_widget_hide (impl->browse_widgets);
6002- }
6003-
6004- gtk_widget_show (impl->browse_new_folder_button);
6005-
6006- if (impl->select_multiple)
6007- {
6008- g_warning ("Save mode cannot be set in conjunction with multiple selection mode. "
6009- "Re-setting to single selection mode.");
6010- set_select_multiple (impl, FALSE, TRUE);
6011- }
6012- }
6013- else if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
6014- impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
6015- {
6016- gtk_widget_show (impl->location_button);
6017- save_widgets_destroy (impl);
6018- gtk_widget_show (impl->browse_widgets);
6019- location_mode_set (impl, impl->location_mode, TRUE);
6020- }
6021-
6022- if (impl->location_entry)
6023- _gtk_file_chooser_entry_set_action (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), impl->action);
6024-
6025- if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN)
6026- gtk_widget_hide (impl->browse_new_folder_button);
6027- else
6028- gtk_widget_show (impl->browse_new_folder_button);
6029-
6030- /* This *is* needed; we need to redraw the file list because the "sensitivity"
6031- * of files may change depending whether we are in a file or folder-only mode.
6032- */
6033- gtk_widget_queue_draw (impl->browse_files_tree_view);
6034-
6035- g_signal_emit_by_name (impl, "default-size-changed");
6036-}
6037-
6038-static void
6039-gtk_file_chooser_default_set_property (GObject *object,
6040- guint prop_id,
6041- const GValue *value,
6042- GParamSpec *pspec)
6043-
6044-{
6045- GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (object);
6046-
6047- switch (prop_id)
6048- {
6049- case GTK_FILE_CHOOSER_PROP_ACTION:
6050- {
6051- GtkFileChooserAction action = g_value_get_enum (value);
6052-
6053- if (action != impl->action)
6054- {
6055- gtk_file_chooser_default_unselect_all (GTK_FILE_CHOOSER (impl));
6056-
6057- if ((action == GTK_FILE_CHOOSER_ACTION_SAVE ||
6058- action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
6059- && impl->select_multiple)
6060- {
6061- g_warning ("Tried to change the file chooser action to SAVE or CREATE_FOLDER, but "
6062- "this is not allowed in multiple selection mode. Resetting the file chooser "
6063- "to single selection mode.");
6064- set_select_multiple (impl, FALSE, TRUE);
6065- }
6066- impl->action = action;
6067- update_appearance (impl);
6068- settings_load (impl);
6069- }
6070- }
6071- break;
6072-
6073- case GTK_FILE_CHOOSER_PROP_FILE_SYSTEM_BACKEND:
6074- set_file_system_backend (impl, g_value_get_string (value));
6075- break;
6076-
6077- case GTK_FILE_CHOOSER_PROP_FILTER:
6078- set_current_filter (impl, g_value_get_object (value));
6079- break;
6080-
6081- case GTK_FILE_CHOOSER_PROP_LOCAL_ONLY:
6082- set_local_only (impl, g_value_get_boolean (value));
6083- break;
6084-
6085- case GTK_FILE_CHOOSER_PROP_PREVIEW_WIDGET:
6086- set_preview_widget (impl, g_value_get_object (value));
6087- break;
6088-
6089- case GTK_FILE_CHOOSER_PROP_PREVIEW_WIDGET_ACTIVE:
6090- impl->preview_widget_active = g_value_get_boolean (value);
6091- update_preview_widget_visibility (impl);
6092- break;
6093-
6094- case GTK_FILE_CHOOSER_PROP_USE_PREVIEW_LABEL:
6095- impl->use_preview_label = g_value_get_boolean (value);
6096- update_preview_widget_visibility (impl);
6097- break;
6098-
6099- case GTK_FILE_CHOOSER_PROP_EXTRA_WIDGET:
6100- set_extra_widget (impl, g_value_get_object (value));
6101- break;
6102-
6103- case GTK_FILE_CHOOSER_PROP_SELECT_MULTIPLE:
6104- {
6105- gboolean select_multiple = g_value_get_boolean (value);
6106- if ((impl->action == GTK_FILE_CHOOSER_ACTION_SAVE ||
6107- impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
6108- && select_multiple)
6109- {
6110- g_warning ("Tried to set the file chooser to multiple selection mode, but this is "
6111- "not allowed in SAVE or CREATE_FOLDER modes. Ignoring the change and "
6112- "leaving the file chooser in single selection mode.");
6113- return;
6114- }
6115-
6116- set_select_multiple (impl, select_multiple, FALSE);
6117- }
6118- break;
6119-
6120- case GTK_FILE_CHOOSER_PROP_SHOW_HIDDEN:
6121- {
6122- gboolean show_hidden = g_value_get_boolean (value);
6123- if (show_hidden != impl->show_hidden)
6124- {
6125- impl->show_hidden = show_hidden;
6126-
6127- if (impl->browse_files_model)
6128- _gtk_file_system_model_set_show_hidden (impl->browse_files_model, show_hidden);
6129- }
6130- }
6131- break;
6132-
6133- case GTK_FILE_CHOOSER_PROP_DO_OVERWRITE_CONFIRMATION:
6134- {
6135- gboolean do_overwrite_confirmation = g_value_get_boolean (value);
6136- impl->do_overwrite_confirmation = do_overwrite_confirmation;
6137- }
6138- break;
6139-
6140- default:
6141- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
6142- break;
6143- }
6144-}
6145-
6146-static void
6147-gtk_file_chooser_default_get_property (GObject *object,
6148- guint prop_id,
6149- GValue *value,
6150- GParamSpec *pspec)
6151-{
6152- GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (object);
6153-
6154- switch (prop_id)
6155- {
6156- case GTK_FILE_CHOOSER_PROP_ACTION:
6157- g_value_set_enum (value, impl->action);
6158- break;
6159-
6160- case GTK_FILE_CHOOSER_PROP_FILTER:
6161- g_value_set_object (value, impl->current_filter);
6162- break;
6163-
6164- case GTK_FILE_CHOOSER_PROP_LOCAL_ONLY:
6165- g_value_set_boolean (value, impl->local_only);
6166- break;
6167-
6168- case GTK_FILE_CHOOSER_PROP_PREVIEW_WIDGET:
6169- g_value_set_object (value, impl->preview_widget);
6170- break;
6171-
6172- case GTK_FILE_CHOOSER_PROP_PREVIEW_WIDGET_ACTIVE:
6173- g_value_set_boolean (value, impl->preview_widget_active);
6174- break;
6175-
6176- case GTK_FILE_CHOOSER_PROP_USE_PREVIEW_LABEL:
6177- g_value_set_boolean (value, impl->use_preview_label);
6178- break;
6179-
6180- case GTK_FILE_CHOOSER_PROP_EXTRA_WIDGET:
6181- g_value_set_object (value, impl->extra_widget);
6182- break;
6183-
6184- case GTK_FILE_CHOOSER_PROP_SELECT_MULTIPLE:
6185- g_value_set_boolean (value, impl->select_multiple);
6186- break;
6187-
6188- case GTK_FILE_CHOOSER_PROP_SHOW_HIDDEN:
6189- g_value_set_boolean (value, impl->show_hidden);
6190- break;
6191-
6192- case GTK_FILE_CHOOSER_PROP_DO_OVERWRITE_CONFIRMATION:
6193- g_value_set_boolean (value, impl->do_overwrite_confirmation);
6194- break;
6195-
6196- default:
6197- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
6198- break;
6199- }
6200-}
6201-
6202-/* Removes the settings signal handler. It's safe to call multiple times */
6203-static void
6204-remove_settings_signal (GtkFileChooserDefault *impl,
6205- GdkScreen *screen)
6206-{
6207- if (impl->settings_signal_id)
6208- {
6209- GtkSettings *settings;
6210-
6211- settings = gtk_settings_get_for_screen (screen);
6212- g_signal_handler_disconnect (settings,
6213- impl->settings_signal_id);
6214- impl->settings_signal_id = 0;
6215- }
6216-}
6217-
6218-static void
6219-gtk_file_chooser_default_dispose (GObject *object)
6220-{
6221- GSList *l;
6222- GtkFileChooserDefault *impl = (GtkFileChooserDefault *) object;
6223-
6224- if (impl->extra_widget)
6225- {
6226- g_object_unref (impl->extra_widget);
6227- impl->extra_widget = NULL;
6228- }
6229-
6230- if (impl->volumes_changed_id > 0)
6231- {
6232- g_signal_handler_disconnect (impl->file_system, impl->volumes_changed_id);
6233- impl->volumes_changed_id = 0;
6234- }
6235-
6236- if (impl->bookmarks_changed_id > 0)
6237- {
6238- g_signal_handler_disconnect (impl->file_system, impl->bookmarks_changed_id);
6239- impl->bookmarks_changed_id = 0;
6240- }
6241-
6242- pending_select_paths_free (impl);
6243-
6244- /* cancel all pending operations */
6245- if (impl->pending_handles)
6246- {
6247- for (l = impl->pending_handles; l; l = l->next)
6248- {
6249- GtkFileSystemHandle *handle =l->data;
6250- gtk_file_system_cancel_operation (handle);
6251- }
6252- g_slist_free (impl->pending_handles);
6253- impl->pending_handles = NULL;
6254- }
6255-
6256- if (impl->reload_icon_handles)
6257- {
6258- for (l = impl->reload_icon_handles; l; l = l->next)
6259- {
6260- GtkFileSystemHandle *handle =l->data;
6261- gtk_file_system_cancel_operation (handle);
6262- }
6263- g_slist_free (impl->reload_icon_handles);
6264- impl->reload_icon_handles = NULL;
6265- }
6266-
6267- if (impl->loading_shortcuts)
6268- {
6269- for (l = impl->loading_shortcuts; l; l = l->next)
6270- {
6271- GtkFileSystemHandle *handle =l->data;
6272- gtk_file_system_cancel_operation (handle);
6273- }
6274- g_slist_free (impl->loading_shortcuts);
6275- impl->loading_shortcuts = NULL;
6276- }
6277-
6278- if (impl->file_list_drag_data_received_handle)
6279- {
6280- gtk_file_system_cancel_operation (impl->file_list_drag_data_received_handle);
6281- impl->file_list_drag_data_received_handle = NULL;
6282- }
6283-
6284- if (impl->update_current_folder_handle)
6285- {
6286- gtk_file_system_cancel_operation (impl->update_current_folder_handle);
6287- impl->update_current_folder_handle = NULL;
6288- }
6289-
6290- if (impl->show_and_select_paths_handle)
6291- {
6292- gtk_file_system_cancel_operation (impl->show_and_select_paths_handle);
6293- impl->show_and_select_paths_handle = NULL;
6294- }
6295-
6296- if (impl->should_respond_get_info_handle)
6297- {
6298- gtk_file_system_cancel_operation (impl->should_respond_get_info_handle);
6299- impl->should_respond_get_info_handle = NULL;
6300- }
6301-
6302- if (impl->update_from_entry_handle)
6303- {
6304- gtk_file_system_cancel_operation (impl->update_from_entry_handle);
6305- impl->update_from_entry_handle = NULL;
6306- }
6307-
6308- if (impl->shortcuts_activate_iter_handle)
6309- {
6310- gtk_file_system_cancel_operation (impl->shortcuts_activate_iter_handle);
6311- impl->shortcuts_activate_iter_handle = NULL;
6312- }
6313-
6314- search_stop_searching (impl, TRUE);
6315- recent_stop_loading (impl);
6316-
6317- remove_settings_signal (impl, gtk_widget_get_screen (GTK_WIDGET (impl)));
6318-
6319- G_OBJECT_CLASS (_gtk_file_chooser_default_parent_class)->dispose (object);
6320-}
6321-
6322-/* We override show-all since we have internal widgets that
6323- * shouldn't be shown when you call show_all(), like the filter
6324- * combo box.
6325- */
6326-static void
6327-gtk_file_chooser_default_show_all (GtkWidget *widget)
6328-{
6329- GtkFileChooserDefault *impl = (GtkFileChooserDefault *) widget;
6330-
6331- gtk_widget_show (widget);
6332-
6333- if (impl->extra_widget)
6334- gtk_widget_show_all (impl->extra_widget);
6335-}
6336-
6337-/* Handler for GtkWindow::set-focus; this is where we save the last-focused
6338- * widget on our toplevel. See gtk_file_chooser_default_hierarchy_changed()
6339- */
6340-static void
6341-toplevel_set_focus_cb (GtkWindow *window,
6342- GtkWidget *focus,
6343- GtkFileChooserDefault *impl)
6344-{
6345- impl->toplevel_last_focus_widget = gtk_window_get_focus (window);
6346-}
6347-
6348-/* We monitor the focus widget on our toplevel to be able to know which widget
6349- * was last focused at the time our "should_respond" method gets called.
6350- */
6351-static void
6352-gtk_file_chooser_default_hierarchy_changed (GtkWidget *widget,
6353- GtkWidget *previous_toplevel)
6354-{
6355- GtkFileChooserDefault *impl;
6356- GtkWidget *toplevel;
6357-
6358- impl = GTK_FILE_CHOOSER_DEFAULT (widget);
6359-
6360- if (previous_toplevel)
6361- {
6362- g_assert (impl->toplevel_set_focus_id != 0);
6363- g_signal_handler_disconnect (previous_toplevel, impl->toplevel_set_focus_id);
6364- impl->toplevel_set_focus_id = 0;
6365- impl->toplevel_last_focus_widget = NULL;
6366- }
6367- else
6368- g_assert (impl->toplevel_set_focus_id == 0);
6369-
6370- toplevel = gtk_widget_get_toplevel (widget);
6371- if (GTK_IS_WINDOW (toplevel))
6372- {
6373- impl->toplevel_set_focus_id = g_signal_connect (toplevel, "set_focus",
6374- G_CALLBACK (toplevel_set_focus_cb), impl);
6375- impl->toplevel_last_focus_widget = gtk_window_get_focus (GTK_WINDOW (toplevel));
6376- }
6377-}
6378-
6379-/* Changes the icons wherever it is needed */
6380-static void
6381-change_icon_theme (GtkFileChooserDefault *impl)
6382-{
6383- GtkSettings *settings;
6384- gint width, height;
6385-
6386- profile_start ("start", NULL);
6387-
6388- settings = gtk_settings_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (impl)));
6389-
6390- if (gtk_icon_size_lookup_for_settings (settings, GTK_ICON_SIZE_MENU, &width, &height))
6391- impl->icon_size = MAX (width, height);
6392- else
6393- impl->icon_size = FALLBACK_ICON_SIZE;
6394-
6395- shortcuts_reload_icons (impl);
6396- gtk_widget_queue_resize (impl->browse_files_tree_view);
6397-
6398- profile_end ("end", NULL);
6399-}
6400-
6401-/* Callback used when a GtkSettings value changes */
6402-static void
6403-settings_notify_cb (GObject *object,
6404- GParamSpec *pspec,
6405- GtkFileChooserDefault *impl)
6406-{
6407- const char *name;
6408-
6409- profile_start ("start", NULL);
6410-
6411- name = g_param_spec_get_name (pspec);
6412-
6413- if (strcmp (name, "gtk-icon-theme-name") == 0 ||
6414- strcmp (name, "gtk-icon-sizes") == 0)
6415- change_icon_theme (impl);
6416-
6417- profile_end ("end", NULL);
6418-}
6419-
6420-/* Installs a signal handler for GtkSettings so that we can monitor changes in
6421- * the icon theme.
6422- */
6423-static void
6424-check_icon_theme (GtkFileChooserDefault *impl)
6425-{
6426- GtkSettings *settings;
6427-
6428- profile_start ("start", NULL);
6429-
6430- if (impl->settings_signal_id)
6431- {
6432- profile_end ("end", NULL);
6433- return;
6434- }
6435-
6436- if (gtk_widget_has_screen (GTK_WIDGET (impl)))
6437- {
6438- settings = gtk_settings_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (impl)));
6439- impl->settings_signal_id = g_signal_connect (settings, "notify",
6440- G_CALLBACK (settings_notify_cb), impl);
6441-
6442- change_icon_theme (impl);
6443- }
6444-
6445- profile_end ("end", NULL);
6446-}
6447-
6448-static void
6449-recent_manager_update (GtkFileChooserDefault *impl)
6450-{
6451- GtkRecentManager *manager;
6452-
6453- profile_start ("start", NULL);
6454-
6455- if (gtk_widget_has_screen (GTK_WIDGET (impl)))
6456- manager = gtk_recent_manager_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (impl)));
6457- else
6458- manager = gtk_recent_manager_get_default ();
6459-
6460- if (impl->recent_manager != manager)
6461- impl->recent_manager = manager;
6462-
6463- profile_end ("end", NULL);
6464-}
6465-
6466-static void
6467-gtk_file_chooser_default_style_set (GtkWidget *widget,
6468- GtkStyle *previous_style)
6469-{
6470- GtkFileChooserDefault *impl;
6471-
6472- profile_start ("start", NULL);
6473-
6474- impl = GTK_FILE_CHOOSER_DEFAULT (widget);
6475-
6476- profile_msg (" parent class style_set start", NULL);
6477- if (GTK_WIDGET_CLASS (_gtk_file_chooser_default_parent_class)->style_set)
6478- GTK_WIDGET_CLASS (_gtk_file_chooser_default_parent_class)->style_set (widget, previous_style);
6479- profile_msg (" parent class style_set end", NULL);
6480-
6481- if (gtk_widget_has_screen (GTK_WIDGET (impl)))
6482- change_icon_theme (impl);
6483-
6484- profile_msg (" emit default-size-changed start", NULL);
6485- g_signal_emit_by_name (widget, "default-size-changed");
6486- profile_msg (" emit default-size-changed end", NULL);
6487-
6488- profile_end ("end", NULL);
6489-}
6490-
6491-static void
6492-gtk_file_chooser_default_screen_changed (GtkWidget *widget,
6493- GdkScreen *previous_screen)
6494-{
6495- GtkFileChooserDefault *impl;
6496-
6497- profile_start ("start", NULL);
6498-
6499- impl = GTK_FILE_CHOOSER_DEFAULT (widget);
6500-
6501- if (GTK_WIDGET_CLASS (_gtk_file_chooser_default_parent_class)->screen_changed)
6502- GTK_WIDGET_CLASS (_gtk_file_chooser_default_parent_class)->screen_changed (widget, previous_screen);
6503-
6504- remove_settings_signal (impl, previous_screen);
6505- check_icon_theme (impl);
6506- recent_manager_update (impl);
6507-
6508- g_signal_emit_by_name (widget, "default-size-changed");
6509-
6510- profile_end ("end", NULL);
6511-}
6512-
6513-static void
6514-gtk_file_chooser_default_size_allocate (GtkWidget *widget,
6515- GtkAllocation *allocation)
6516-{
6517- GtkFileChooserDefault *impl;
6518-
6519- impl = GTK_FILE_CHOOSER_DEFAULT (widget);
6520-
6521- GTK_WIDGET_CLASS (_gtk_file_chooser_default_parent_class)->size_allocate (widget, allocation);
6522-
6523- if (!gtk_file_chooser_default_get_resizable (GTK_FILE_CHOOSER_EMBED (impl)))
6524- {
6525- /* The dialog is not resizable, we shouldn't
6526- * trust in the size it has in this stage
6527- */
6528- return;
6529- }
6530-
6531- impl->default_width = allocation->width;
6532- impl->default_height = allocation->height;
6533-
6534- if (impl->preview_widget_active &&
6535- impl->preview_widget &&
6536- GTK_WIDGET_DRAWABLE (impl->preview_widget))
6537- impl->default_width -= impl->preview_widget->allocation.width + PREVIEW_HBOX_SPACING;
6538-
6539- if (impl->extra_widget &&
6540- GTK_WIDGET_DRAWABLE (impl->extra_widget))
6541- impl->default_height -= GTK_BOX (widget)->spacing + impl->extra_widget->allocation.height;
6542-}
6543-
6544-static gboolean
6545-get_is_file_filtered (GtkFileChooserDefault *impl,
6546- const GtkFilePath *path,
6547- GtkFileInfo *file_info)
6548-{
6549- GtkFileFilterInfo filter_info;
6550- GtkFileFilterFlags needed;
6551- gboolean result;
6552-
6553- if (!impl->current_filter)
6554- return FALSE;
6555-
6556- filter_info.contains = GTK_FILE_FILTER_DISPLAY_NAME | GTK_FILE_FILTER_MIME_TYPE;
6557-
6558- needed = gtk_file_filter_get_needed (impl->current_filter);
6559-
6560- filter_info.display_name = gtk_file_info_get_display_name (file_info);
6561- filter_info.mime_type = gtk_file_info_get_mime_type (file_info);
6562-
6563- if (needed & GTK_FILE_FILTER_FILENAME)
6564- {
6565- filter_info.filename = gtk_file_system_path_to_filename (impl->file_system, path);
6566- if (filter_info.filename)
6567- filter_info.contains |= GTK_FILE_FILTER_FILENAME;
6568- }
6569- else
6570- filter_info.filename = NULL;
6571-
6572- if (needed & GTK_FILE_FILTER_URI)
6573- {
6574- filter_info.uri = gtk_file_system_path_to_uri (impl->file_system, path);
6575- if (filter_info.uri)
6576- filter_info.contains |= GTK_FILE_FILTER_URI;
6577- }
6578- else
6579- filter_info.uri = NULL;
6580-
6581- result = gtk_file_filter_filter (impl->current_filter, &filter_info);
6582-
6583- if (filter_info.filename)
6584- g_free ((gchar *)filter_info.filename);
6585- if (filter_info.uri)
6586- g_free ((gchar *)filter_info.uri);
6587-
6588- return !result;
6589-}
6590-
6591-static void
6592-settings_load (GtkFileChooserDefault *impl)
6593-{
6594- GtkFileChooserSettings *settings;
6595- LocationMode location_mode;
6596- gboolean show_hidden;
6597- gboolean expand_folders;
6598-
6599- settings = _gtk_file_chooser_settings_new ();
6600-
6601- location_mode = _gtk_file_chooser_settings_get_location_mode (settings);
6602- show_hidden = _gtk_file_chooser_settings_get_show_hidden (settings);
6603- expand_folders = _gtk_file_chooser_settings_get_expand_folders (settings);
6604-
6605- g_object_unref (settings);
6606-
6607- location_mode_set (impl, location_mode, TRUE);
6608- gtk_file_chooser_set_show_hidden (GTK_FILE_CHOOSER (impl), show_hidden);
6609- impl->expand_folders = expand_folders;
6610- if (impl->save_expander)
6611- gtk_expander_set_expanded (GTK_EXPANDER (impl->save_expander), expand_folders);
6612-}
6613-
6614-static void
6615-settings_save (GtkFileChooserDefault *impl)
6616-{
6617- GtkFileChooserSettings *settings;
6618-
6619- settings = _gtk_file_chooser_settings_new ();
6620-
6621- _gtk_file_chooser_settings_set_location_mode (settings, impl->location_mode);
6622- _gtk_file_chooser_settings_set_show_hidden (settings, gtk_file_chooser_get_show_hidden (GTK_FILE_CHOOSER (impl)));
6623- _gtk_file_chooser_settings_set_expand_folders (settings, impl->expand_folders);
6624-
6625- /* NULL GError */
6626- _gtk_file_chooser_settings_save (settings, NULL);
6627-
6628- g_object_unref (settings);
6629-}
6630-
6631-/* GtkWidget::map method */
6632-static void
6633-gtk_file_chooser_default_map (GtkWidget *widget)
6634-{
6635- GtkFileChooserDefault *impl;
6636- char *current_working_dir;
6637-
6638- profile_start ("start", NULL);
6639-
6640- impl = GTK_FILE_CHOOSER_DEFAULT (widget);
6641-
6642- GTK_WIDGET_CLASS (_gtk_file_chooser_default_parent_class)->map (widget);
6643-
6644- if (impl->operation_mode == OPERATION_MODE_BROWSE)
6645- {
6646- switch (impl->reload_state)
6647- {
6648- case RELOAD_EMPTY:
6649- /* The user didn't explicitly give us a folder to
6650- * display, so we'll use the cwd
6651- */
6652- current_working_dir = g_get_current_dir ();
6653- gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (impl),
6654- current_working_dir);
6655- g_free (current_working_dir);
6656- break;
6657-
6658- case RELOAD_HAS_FOLDER:
6659- /* Nothing; we are already loading or loaded, so we
6660- * don't need to reload
6661- */
6662- break;
6663-
6664- case RELOAD_WAS_UNMAPPED:
6665- /* Just reload the current folder; else continue
6666- * the pending load.
6667- */
6668- if (impl->current_folder)
6669- {
6670- pending_select_paths_store_selection (impl);
6671- change_folder_and_display_error (impl, impl->current_folder, FALSE);
6672- }
6673- break;
6674-
6675- default:
6676- g_assert_not_reached ();
6677- }
6678- }
6679-
6680- bookmarks_changed_cb (impl->file_system, impl);
6681-
6682- settings_load (impl);
6683-
6684- profile_end ("end", NULL);
6685-}
6686-
6687-/* GtkWidget::unmap method */
6688-static void
6689-gtk_file_chooser_default_unmap (GtkWidget *widget)
6690-{
6691- GtkFileChooserDefault *impl;
6692-
6693- impl = GTK_FILE_CHOOSER_DEFAULT (widget);
6694-
6695- settings_save (impl);
6696-
6697- GTK_WIDGET_CLASS (_gtk_file_chooser_default_parent_class)->unmap (widget);
6698-
6699- impl->reload_state = RELOAD_WAS_UNMAPPED;
6700-}
6701-
6702-static gboolean
6703-list_model_filter_func (GtkFileSystemModel *model,
6704- GtkFilePath *path,
6705- const GtkFileInfo *file_info,
6706- gpointer user_data)
6707-{
6708- GtkFileChooserDefault *impl = user_data;
6709-
6710- if (!impl->current_filter)
6711- return TRUE;
6712-
6713- if (gtk_file_info_get_is_folder (file_info))
6714- return TRUE;
6715-
6716- return !get_is_file_filtered (impl, path, (GtkFileInfo *) file_info);
6717-}
6718-
6719-static void
6720-install_list_model_filter (GtkFileChooserDefault *impl)
6721-{
6722- GtkFileSystemModelFilter filter;
6723- gpointer data;
6724-
6725- g_assert (impl->browse_files_model != NULL);
6726-
6727- if (impl->current_filter)
6728- {
6729- filter = list_model_filter_func;
6730- data = impl;
6731- }
6732- else
6733- {
6734- filter = NULL;
6735- data = NULL;
6736- }
6737-
6738- _gtk_file_system_model_set_filter (impl->browse_files_model,
6739- filter,
6740- data);
6741-}
6742-
6743-#define COMPARE_DIRECTORIES \
6744- GtkFileChooserDefault *impl = user_data; \
6745- const GtkFileInfo *info_a = _gtk_file_system_model_get_info (impl->browse_files_model, a); \
6746- const GtkFileInfo *info_b = _gtk_file_system_model_get_info (impl->browse_files_model, b); \
6747- gboolean dir_a, dir_b; \
6748- \
6749- if (info_a) \
6750- dir_a = gtk_file_info_get_is_folder (info_a); \
6751- else \
6752- return impl->list_sort_ascending ? -1 : 1; \
6753- \
6754- if (info_b) \
6755- dir_b = gtk_file_info_get_is_folder (info_b); \
6756- else \
6757- return impl->list_sort_ascending ? 1 : -1; \
6758- \
6759- if (dir_a != dir_b) \
6760- return impl->list_sort_ascending ? (dir_a ? -1 : 1) : (dir_a ? 1 : -1) /* Directories *always* go first */
6761-
6762-/* Sort callback for the filename column */
6763-static gint
6764-name_sort_func (GtkTreeModel *model,
6765- GtkTreeIter *a,
6766- GtkTreeIter *b,
6767- gpointer user_data)
6768-{
6769- COMPARE_DIRECTORIES;
6770- else
6771- return strcmp (gtk_file_info_get_display_key (info_a), gtk_file_info_get_display_key (info_b));
6772-}
6773-
6774-/* Sort callback for the size column */
6775-static gint
6776-size_sort_func (GtkTreeModel *model,
6777- GtkTreeIter *a,
6778- GtkTreeIter *b,
6779- gpointer user_data)
6780-{
6781- COMPARE_DIRECTORIES;
6782- else
6783- {
6784- gint64 size_a = gtk_file_info_get_size (info_a);
6785- gint64 size_b = gtk_file_info_get_size (info_b);
6786-
6787- return size_a > size_b ? -1 : (size_a == size_b ? 0 : 1);
6788- }
6789-}
6790-
6791-/* Sort callback for the mtime column */
6792-static gint
6793-mtime_sort_func (GtkTreeModel *model,
6794- GtkTreeIter *a,
6795- GtkTreeIter *b,
6796- gpointer user_data)
6797-{
6798- COMPARE_DIRECTORIES;
6799- else
6800- {
6801- GtkFileTime ta = gtk_file_info_get_modification_time (info_a);
6802- GtkFileTime tb = gtk_file_info_get_modification_time (info_b);
6803-
6804- return ta > tb ? -1 : (ta == tb ? 0 : 1);
6805- }
6806-}
6807-
6808-/* Callback used when the sort column changes. We cache the sort order for use
6809- * in name_sort_func().
6810- */
6811-static void
6812-list_sort_column_changed_cb (GtkTreeSortable *sortable,
6813- GtkFileChooserDefault *impl)
6814-{
6815- GtkSortType sort_type;
6816-
6817- if (gtk_tree_sortable_get_sort_column_id (sortable, NULL, &sort_type))
6818- impl->list_sort_ascending = (sort_type == GTK_SORT_ASCENDING);
6819-}
6820-
6821-static void
6822-set_busy_cursor (GtkFileChooserDefault *impl,
6823- gboolean busy)
6824-{
6825- GtkWindow *toplevel;
6826- GdkDisplay *display;
6827- GdkCursor *cursor;
6828-
6829- toplevel = get_toplevel (GTK_WIDGET (impl));
6830- if (!toplevel || !GTK_WIDGET_REALIZED (toplevel))
6831- return;
6832-
6833- display = gtk_widget_get_display (GTK_WIDGET (toplevel));
6834-
6835- if (busy)
6836- cursor = gdk_cursor_new_for_display (display, GDK_WATCH);
6837- else
6838- cursor = NULL;
6839-
6840- gdk_window_set_cursor (GTK_WIDGET (toplevel)->window, cursor);
6841- gdk_display_flush (display);
6842-
6843- if (cursor)
6844- gdk_cursor_unref (cursor);
6845-}
6846-
6847-/* Creates a sort model to wrap the file system model and sets it on the tree view */
6848-static void
6849-load_set_model (GtkFileChooserDefault *impl)
6850-{
6851- profile_start ("start", NULL);
6852-
6853- g_assert (impl->browse_files_model != NULL);
6854- g_assert (impl->sort_model == NULL);
6855-
6856- profile_msg (" gtk_tree_model_sort_new_with_model start", NULL);
6857- impl->sort_model = (GtkTreeModelSort *)gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (impl->browse_files_model));
6858- gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->sort_model), FILE_LIST_COL_NAME, name_sort_func, impl, NULL);
6859- gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->sort_model), FILE_LIST_COL_SIZE, size_sort_func, impl, NULL);
6860- gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->sort_model), FILE_LIST_COL_MTIME, mtime_sort_func, impl, NULL);
6861- gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (impl->sort_model), NULL, NULL, NULL);
6862- gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (impl->sort_model), FILE_LIST_COL_NAME, GTK_SORT_ASCENDING);
6863- impl->list_sort_ascending = TRUE;
6864- profile_msg (" gtk_tree_model_sort_new_with_model end", NULL);
6865-
6866- g_signal_connect (impl->sort_model, "sort_column_changed",
6867- G_CALLBACK (list_sort_column_changed_cb), impl);
6868-
6869- profile_msg (" gtk_tree_view_set_model start", NULL);
6870- gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view),
6871- GTK_TREE_MODEL (impl->sort_model));
6872- gtk_tree_view_columns_autosize (GTK_TREE_VIEW (impl->browse_files_tree_view));
6873- gtk_tree_view_set_search_column (GTK_TREE_VIEW (impl->browse_files_tree_view),
6874- GTK_FILE_SYSTEM_MODEL_DISPLAY_NAME);
6875- profile_msg (" gtk_tree_view_set_model end", NULL);
6876-
6877- profile_end ("end", NULL);
6878-}
6879-
6880-/* Timeout callback used when the loading timer expires */
6881-static gboolean
6882-load_timeout_cb (gpointer data)
6883-{
6884- GtkFileChooserDefault *impl;
6885-
6886- profile_start ("start", NULL);
6887-
6888- impl = GTK_FILE_CHOOSER_DEFAULT (data);
6889- g_assert (impl->load_state == LOAD_PRELOAD);
6890- g_assert (impl->load_timeout_id != 0);
6891- g_assert (impl->browse_files_model != NULL);
6892-
6893- impl->load_timeout_id = 0;
6894- impl->load_state = LOAD_LOADING;
6895-
6896- load_set_model (impl);
6897-
6898- profile_end ("end", NULL);
6899-
6900- return FALSE;
6901-}
6902-
6903-/* Sets up a new load timer for the model and switches to the LOAD_PRELOAD state */
6904-static void
6905-load_setup_timer (GtkFileChooserDefault *impl)
6906-{
6907- g_assert (impl->load_timeout_id == 0);
6908- g_assert (impl->load_state != LOAD_PRELOAD);
6909-
6910- impl->load_timeout_id = gdk_threads_add_timeout (MAX_LOADING_TIME, load_timeout_cb, impl);
6911- impl->load_state = LOAD_PRELOAD;
6912-}
6913-
6914-/* Removes the load timeout and switches to the LOAD_FINISHED state */
6915-static void
6916-load_remove_timer (GtkFileChooserDefault *impl)
6917-{
6918- if (impl->load_timeout_id != 0)
6919- {
6920- g_assert (impl->load_state == LOAD_PRELOAD);
6921-
6922- g_source_remove (impl->load_timeout_id);
6923- impl->load_timeout_id = 0;
6924- impl->load_state = LOAD_EMPTY;
6925- }
6926- else
6927- g_assert (impl->load_state == LOAD_EMPTY ||
6928- impl->load_state == LOAD_LOADING ||
6929- impl->load_state == LOAD_FINISHED);
6930-}
6931-
6932-/* Selects the first row in the file list */
6933-static void
6934-browse_files_select_first_row (GtkFileChooserDefault *impl)
6935-{
6936- GtkTreePath *path;
6937-
6938- if (!impl->sort_model)
6939- return;
6940-
6941- path = gtk_tree_path_new_from_indices (0, -1);
6942- gtk_tree_view_set_cursor (GTK_TREE_VIEW (impl->browse_files_tree_view), path, NULL, FALSE);
6943- gtk_tree_path_free (path);
6944-}
6945-
6946-struct center_selected_row_closure {
6947- GtkFileChooserDefault *impl;
6948- gboolean already_centered;
6949-};
6950-
6951-/* Callback used from gtk_tree_selection_selected_foreach(); centers the
6952- * selected row in the tree view.
6953- */
6954-static void
6955-center_selected_row_foreach_cb (GtkTreeModel *model,
6956- GtkTreePath *path,
6957- GtkTreeIter *iter,
6958- gpointer data)
6959-{
6960- struct center_selected_row_closure *closure;
6961-
6962- closure = data;
6963- if (closure->already_centered)
6964- return;
6965-
6966- gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (closure->impl->browse_files_tree_view), path, NULL, TRUE, 0.5, 0.0);
6967- closure->already_centered = TRUE;
6968-}
6969-
6970-/* Centers the selected row in the tree view */
6971-static void
6972-browse_files_center_selected_row (GtkFileChooserDefault *impl)
6973-{
6974- struct center_selected_row_closure closure;
6975- GtkTreeSelection *selection;
6976-
6977- closure.impl = impl;
6978- closure.already_centered = FALSE;
6979-
6980- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
6981- gtk_tree_selection_selected_foreach (selection, center_selected_row_foreach_cb, &closure);
6982-}
6983-
6984-struct ShowAndSelectPathsData
6985-{
6986- GtkFileChooserDefault *impl;
6987- GSList *paths;
6988-};
6989-
6990-static void
6991-show_and_select_paths_finished_loading (GtkFileFolder *folder,
6992- gpointer user_data)
6993-{
6994- gboolean have_hidden;
6995- gboolean have_filtered;
6996- GSList *l;
6997- struct ShowAndSelectPathsData *data = user_data;
6998-
6999- have_hidden = FALSE;
7000- have_filtered = FALSE;
7001-
7002- for (l = data->paths; l; l = l->next)
7003- {
7004- const GtkFilePath *path;
7005- GtkFileInfo *info;
7006-
7007- path = l->data;
7008-
7009- /* NULL GError */
7010- info = gtk_file_folder_get_info (folder, path, NULL);
7011- if (info)
7012- {
7013- if (!have_hidden)
7014- have_hidden = gtk_file_info_get_is_hidden (info);
7015-
7016- if (!have_filtered)
7017- have_filtered = !gtk_file_info_get_is_folder (info) && get_is_file_filtered (data->impl, path, info);
7018-
7019- gtk_file_info_free (info);
7020-
7021- if (have_hidden && have_filtered)
7022- break; /* we now have all the information we need */
7023- }
7024- }
7025-
7026- g_signal_handlers_disconnect_by_func (folder,
7027- show_and_select_paths_finished_loading,
7028- user_data);
7029-
7030- g_object_unref (folder);
7031-
7032- if (have_hidden)
7033- g_object_set (data->impl, "show-hidden", TRUE, NULL);
7034-
7035- if (have_filtered)
7036- set_current_filter (data->impl, NULL);
7037-
7038- for (l = data->paths; l; l = l->next)
7039- {
7040- const GtkFilePath *path;
7041-
7042- path = l->data;
7043- _gtk_file_system_model_path_do (data->impl->browse_files_model, path,
7044- select_func, data->impl);
7045- }
7046-
7047- browse_files_center_selected_row (data->impl);
7048-
7049- g_object_unref (data->impl);
7050- gtk_file_paths_free (data->paths);
7051- g_free (data);
7052-}
7053-
7054-static void
7055-show_and_select_paths_get_folder_cb (GtkFileSystemHandle *handle,
7056- GtkFileFolder *folder,
7057- const GError *error,
7058- gpointer user_data)
7059-{
7060- gboolean cancelled = handle->cancelled;
7061- struct ShowAndSelectPathsData *data = user_data;
7062-
7063- if (data->impl->show_and_select_paths_handle != handle)
7064- goto out;
7065-
7066- data->impl->show_and_select_paths_handle = NULL;
7067-
7068- if (cancelled || error)
7069- goto out;
7070-
7071- g_object_unref (handle);
7072-
7073- if (gtk_file_folder_is_finished_loading (folder))
7074- show_and_select_paths_finished_loading (folder, user_data);
7075- else
7076- g_signal_connect (folder, "finished-loading",
7077- G_CALLBACK (show_and_select_paths_finished_loading),
7078- user_data);
7079-
7080- return;
7081-
7082-out:
7083- g_object_unref (data->impl);
7084- gtk_file_paths_free (data->paths);
7085- g_free (data);
7086-
7087- g_object_unref (handle);
7088-}
7089-
7090-static gboolean
7091-show_and_select_paths (GtkFileChooserDefault *impl,
7092- const GtkFilePath *parent_path,
7093- GSList *paths,
7094- GError **error)
7095-{
7096- struct ShowAndSelectPathsData *info;
7097-
7098- profile_start ("start", NULL);
7099-
7100- if (!paths)
7101- {
7102- profile_end ("end", NULL);
7103- return TRUE;
7104- }
7105-
7106- info = g_new (struct ShowAndSelectPathsData, 1);
7107- info->impl = g_object_ref (impl);
7108- info->paths = gtk_file_paths_copy (paths);
7109-
7110- if (impl->show_and_select_paths_handle)
7111- gtk_file_system_cancel_operation (impl->show_and_select_paths_handle);
7112-
7113- impl->show_and_select_paths_handle =
7114- gtk_file_system_get_folder (impl->file_system, parent_path,
7115- GTK_FILE_INFO_IS_FOLDER | GTK_FILE_INFO_IS_HIDDEN,
7116- show_and_select_paths_get_folder_cb, info);
7117-
7118- profile_end ("end", NULL);
7119- return TRUE;
7120-}
7121-
7122-/* Processes the pending operation when a folder is finished loading */
7123-static void
7124-pending_select_paths_process (GtkFileChooserDefault *impl)
7125-{
7126- g_assert (impl->load_state == LOAD_FINISHED);
7127- g_assert (impl->browse_files_model != NULL);
7128- g_assert (impl->sort_model != NULL);
7129-
7130- if (impl->pending_select_paths)
7131- {
7132- /* NULL GError */
7133- show_and_select_paths (impl, impl->current_folder, impl->pending_select_paths, NULL);
7134- pending_select_paths_free (impl);
7135- browse_files_center_selected_row (impl);
7136- }
7137- else
7138- {
7139- /* We only select the first row if the chooser is actually mapped ---
7140- * selecting the first row is to help the user when he is interacting with
7141- * the chooser, but sometimes a chooser works not on behalf of the user,
7142- * but rather on behalf of something else like GtkFileChooserButton. In
7143- * that case, the chooser's selection should be what the caller expects,
7144- * as the user can't see that something else got selected. See bug #165264.
7145- */
7146- if (GTK_WIDGET_MAPPED (impl) && impl->action == GTK_FILE_CHOOSER_ACTION_OPEN)
7147- browse_files_select_first_row (impl);
7148- }
7149-
7150- g_assert (impl->pending_select_paths == NULL);
7151-}
7152-
7153-/* Callback used when the file system model finishes loading */
7154-static void
7155-browse_files_model_finished_loading_cb (GtkFileSystemModel *model,
7156- GtkFileChooserDefault *impl)
7157-{
7158- profile_start ("start", NULL);
7159-
7160- if (impl->load_state == LOAD_PRELOAD)
7161- {
7162- load_remove_timer (impl);
7163- load_set_model (impl);
7164- }
7165- else if (impl->load_state == LOAD_LOADING)
7166- {
7167- /* Nothing */
7168- }
7169- else
7170- {
7171- /* We can't g_assert_not_reached(), as something other than us may have
7172- * initiated a folder reload. See #165556.
7173- */
7174- profile_end ("end", NULL);
7175- return;
7176- }
7177-
7178- g_assert (impl->load_timeout_id == 0);
7179-
7180- impl->load_state = LOAD_FINISHED;
7181-
7182- pending_select_paths_process (impl);
7183- set_busy_cursor (impl, FALSE);
7184-#ifdef PROFILE_FILE_CHOOSER
7185- access ("MARK: *** FINISHED LOADING", F_OK);
7186-#endif
7187-
7188- profile_end ("end", NULL);
7189-}
7190-
7191-static void
7192-stop_loading_and_clear_list_model (GtkFileChooserDefault *impl)
7193-{
7194- load_remove_timer (impl); /* This changes the state to LOAD_EMPTY */
7195-
7196- if (impl->browse_files_model)
7197- {
7198- g_object_unref (impl->browse_files_model);
7199- impl->browse_files_model = NULL;
7200- }
7201-
7202- if (impl->sort_model)
7203- {
7204- g_object_unref (impl->sort_model);
7205- impl->sort_model = NULL;
7206- }
7207-
7208- gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view), NULL);
7209-}
7210-
7211-/* Gets rid of the old list model and creates a new one for the current folder */
7212-static gboolean
7213-set_list_model (GtkFileChooserDefault *impl,
7214- GError **error)
7215-{
7216- g_assert (impl->current_folder != NULL);
7217-
7218- profile_start ("start", NULL);
7219-
7220- stop_loading_and_clear_list_model (impl);
7221-
7222- set_busy_cursor (impl, TRUE);
7223- gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view), NULL);
7224-
7225- impl->browse_files_model = _gtk_file_system_model_new (impl->file_system,
7226- impl->current_folder, 0,
7227- GTK_FILE_INFO_ALL,
7228- error);
7229- if (!impl->browse_files_model)
7230- {
7231- set_busy_cursor (impl, FALSE);
7232- profile_end ("end", NULL);
7233- return FALSE;
7234- }
7235-
7236- load_setup_timer (impl); /* This changes the state to LOAD_PRELOAD */
7237-
7238- g_signal_connect (impl->browse_files_model, "finished-loading",
7239- G_CALLBACK (browse_files_model_finished_loading_cb), impl);
7240-
7241- _gtk_file_system_model_set_show_hidden (impl->browse_files_model, impl->show_hidden);
7242-
7243- install_list_model_filter (impl);
7244-
7245- profile_end ("end", NULL);
7246-
7247- return TRUE;
7248-}
7249-
7250-struct update_chooser_entry_selected_foreach_closure {
7251- int num_selected;
7252- GtkTreeIter first_selected_iter;
7253-};
7254-
7255-static gint
7256-compare_utf8_filenames (const gchar *a,
7257- const gchar *b)
7258-{
7259- gchar *a_folded, *b_folded;
7260- gint retval;
7261-
7262- a_folded = g_utf8_strdown (a, -1);
7263- b_folded = g_utf8_strdown (b, -1);
7264-
7265- retval = strcmp (a_folded, b_folded);
7266-
7267- g_free (a_folded);
7268- g_free (b_folded);
7269-
7270- return retval;
7271-}
7272-
7273-static void
7274-update_chooser_entry_selected_foreach (GtkTreeModel *model,
7275- GtkTreePath *path,
7276- GtkTreeIter *iter,
7277- gpointer data)
7278-{
7279- struct update_chooser_entry_selected_foreach_closure *closure;
7280-
7281- closure = data;
7282- closure->num_selected++;
7283-
7284- if (closure->num_selected == 1)
7285- closure->first_selected_iter = *iter;
7286-}
7287-
7288-static void
7289-update_chooser_entry (GtkFileChooserDefault *impl)
7290-{
7291- GtkTreeSelection *selection;
7292- struct update_chooser_entry_selected_foreach_closure closure;
7293- const char *file_part;
7294-
7295- /* no need to update the file chooser's entry if there's no entry */
7296- if (impl->operation_mode == OPERATION_MODE_SEARCH ||
7297- impl->operation_mode == OPERATION_MODE_RECENT ||
7298- !impl->location_entry)
7299- return;
7300-
7301- if (!(impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
7302- || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER
7303- || ((impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
7304- || impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
7305- && impl->location_mode == LOCATION_MODE_FILENAME_ENTRY)))
7306- return;
7307-
7308- g_assert (impl->location_entry != NULL);
7309-
7310- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
7311- closure.num_selected = 0;
7312- gtk_tree_selection_selected_foreach (selection, update_chooser_entry_selected_foreach, &closure);
7313-
7314- file_part = NULL;
7315-
7316- if (closure.num_selected == 0)
7317- {
7318- goto maybe_clear_entry;
7319- }
7320- else if (closure.num_selected == 1)
7321- {
7322- GtkTreeIter child_iter;
7323-
7324- if (impl->operation_mode == OPERATION_MODE_BROWSE)
7325- {
7326- const GtkFileInfo *info;
7327- gboolean change_entry;
7328-
7329- gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model,
7330- &child_iter,
7331- &closure.first_selected_iter);
7332-
7333- info = _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
7334-
7335- /* If the cursor moved to the row of the newly created folder,
7336- * retrieving info will return NULL.
7337- */
7338- if (!info)
7339- return;
7340-
7341- g_free (impl->browse_files_last_selected_name);
7342- impl->browse_files_last_selected_name =
7343- g_strdup (gtk_file_info_get_display_name (info));
7344-
7345- if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
7346- impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
7347- change_entry = !gtk_file_info_get_is_folder (info); /* We don't want the name to change when clicking on a folder... */
7348- else
7349- change_entry = TRUE; /* ... unless we are in one of the folder modes */
7350-
7351- if (change_entry)
7352- _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry),
7353- impl->browse_files_last_selected_name);
7354-
7355- return;
7356- }
7357- }
7358- else
7359- {
7360- g_assert (!(impl->action == GTK_FILE_CHOOSER_ACTION_SAVE ||
7361- impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER));
7362-
7363- /* Multiple selection, so just clear the entry. */
7364-
7365- g_free (impl->browse_files_last_selected_name);
7366- impl->browse_files_last_selected_name = NULL;
7367-
7368- _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), "");
7369- return;
7370- }
7371-
7372- maybe_clear_entry:
7373-
7374- if (impl->browse_files_last_selected_name)
7375- {
7376- const char *entry_text;
7377- int len;
7378- gboolean clear_entry;
7379-
7380- entry_text = gtk_entry_get_text (GTK_ENTRY (impl->location_entry));
7381- len = strlen (entry_text);
7382- if (len != 0)
7383- {
7384- /* The file chooser entry may have appended a "/" to its text. So
7385- * take it out, and compare the result to the old selection.
7386- */
7387- if (entry_text[len - 1] == G_DIR_SEPARATOR)
7388- {
7389- char *tmp;
7390-
7391- tmp = g_strndup (entry_text, len - 1);
7392- clear_entry = (compare_utf8_filenames (impl->browse_files_last_selected_name, tmp) == 0);
7393- g_free (tmp);
7394- }
7395- else
7396- clear_entry = (compare_utf8_filenames (impl->browse_files_last_selected_name, entry_text) == 0);
7397- }
7398- else
7399- clear_entry = FALSE;
7400-
7401- if (clear_entry)
7402- _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), "");
7403- }
7404-}
7405-
7406-static gboolean
7407-gtk_file_chooser_default_set_current_folder (GtkFileChooser *chooser,
7408- const GtkFilePath *path,
7409- GError **error)
7410-{
7411- return gtk_file_chooser_default_update_current_folder (chooser, path, FALSE, FALSE, error);
7412-}
7413-
7414-
7415-struct UpdateCurrentFolderData
7416-{
7417- GtkFileChooserDefault *impl;
7418- GtkFilePath *path;
7419- gboolean keep_trail;
7420- gboolean clear_entry;
7421- GtkFilePath *original_path;
7422- GError *original_error;
7423-};
7424-
7425-static void
7426-update_current_folder_get_info_cb (GtkFileSystemHandle *handle,
7427- const GtkFileInfo *info,
7428- const GError *error,
7429- gpointer user_data)
7430-{
7431- gboolean cancelled = handle->cancelled;
7432- struct UpdateCurrentFolderData *data = user_data;
7433- GtkFileChooserDefault *impl = data->impl;
7434-
7435- if (handle != impl->update_current_folder_handle)
7436- goto out;
7437-
7438- impl->update_current_folder_handle = NULL;
7439- impl->reload_state = RELOAD_EMPTY;
7440-
7441- set_busy_cursor (impl, FALSE);
7442-
7443- if (cancelled)
7444- goto out;
7445-
7446- if (error)
7447- {
7448- GtkFilePath *parent_path;
7449-
7450- if (!data->original_path)
7451- {
7452- data->original_path = gtk_file_path_copy (data->path);
7453- data->original_error = g_error_copy (error);
7454- }
7455-
7456- /* get parent path and try to change the folder to that */
7457- if (gtk_file_system_get_parent (impl->file_system, data->path, &parent_path, NULL) &&
7458- parent_path != NULL)
7459- {
7460- gtk_file_path_free (data->path);
7461- data->path = parent_path;
7462-
7463- g_object_unref (handle);
7464-
7465- /* restart the update current folder operation */
7466- impl->reload_state = RELOAD_HAS_FOLDER;
7467-
7468- impl->update_current_folder_handle =
7469- gtk_file_system_get_info (impl->file_system, data->path,
7470- GTK_FILE_INFO_IS_FOLDER,
7471- update_current_folder_get_info_cb,
7472- data);
7473-
7474- set_busy_cursor (impl, TRUE);
7475-
7476- return;
7477- }
7478- else
7479- {
7480- /* error and bail out */
7481- error_changing_folder_dialog (impl, data->original_path, data->original_error);
7482-
7483- gtk_file_path_free (data->original_path);
7484-
7485- goto out;
7486- }
7487- }
7488-
7489- if (data->original_path)
7490- {
7491- error_changing_folder_dialog (impl, data->original_path, data->original_error);
7492-
7493- gtk_file_path_free (data->original_path);
7494- }
7495-
7496- if (!gtk_file_info_get_is_folder (info))
7497- goto out;
7498-
7499- if (!_gtk_path_bar_set_path (GTK_PATH_BAR (impl->browse_path_bar), data->path, data->keep_trail, NULL))
7500- goto out;
7501-
7502- if (impl->current_folder != data->path)
7503- {
7504- if (impl->current_folder)
7505- gtk_file_path_free (impl->current_folder);
7506-
7507- impl->current_folder = gtk_file_path_copy (data->path);
7508-
7509- impl->reload_state = RELOAD_HAS_FOLDER;
7510- }
7511-
7512- /* Update the widgets that may trigger a folder change themselves. */
7513-
7514- if (!impl->changing_folder)
7515- {
7516- impl->changing_folder = TRUE;
7517-
7518- shortcuts_update_current_folder (impl);
7519-
7520- impl->changing_folder = FALSE;
7521- }
7522-
7523- /* Set the folder on the save entry */
7524-
7525- if (impl->location_entry)
7526- {
7527- _gtk_file_chooser_entry_set_base_folder (GTK_FILE_CHOOSER_ENTRY (impl->location_entry),
7528- impl->current_folder);
7529-
7530- if (data->clear_entry)
7531- _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), "");
7532- }
7533-
7534- /* Create a new list model. This is slightly evil; we store the result value
7535- * but perform more actions rather than returning immediately even if it
7536- * generates an error.
7537- */
7538- set_list_model (impl, NULL);
7539-
7540- /* Refresh controls */
7541-
7542- shortcuts_find_current_folder (impl);
7543-
7544- g_signal_emit_by_name (impl, "current-folder-changed", 0);
7545-
7546- check_preview_change (impl);
7547- bookmarks_check_add_sensitivity (impl);
7548-
7549- g_signal_emit_by_name (impl, "selection-changed", 0);
7550-
7551-out:
7552- gtk_file_path_free (data->path);
7553- g_free (data);
7554-
7555- g_object_unref (handle);
7556-}
7557-
7558-static gboolean
7559-gtk_file_chooser_default_update_current_folder (GtkFileChooser *chooser,
7560- const GtkFilePath *path,
7561- gboolean keep_trail,
7562- gboolean clear_entry,
7563- GError **error)
7564-{
7565- GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
7566- struct UpdateCurrentFolderData *data;
7567-
7568- profile_start ("start", (char *) path);
7569-
7570- switch (impl->operation_mode)
7571- {
7572- case OPERATION_MODE_SEARCH:
7573- search_switch_to_browse_mode (impl);
7574- break;
7575- case OPERATION_MODE_RECENT:
7576- recent_switch_to_browse_mode (impl);
7577- break;
7578- case OPERATION_MODE_BROWSE:
7579- break;
7580- }
7581-
7582- g_assert (path != NULL);
7583-
7584- if (impl->local_only &&
7585- !gtk_file_system_path_is_local (impl->file_system, path))
7586- {
7587- g_set_error (error,
7588- GTK_FILE_CHOOSER_ERROR,
7589- GTK_FILE_CHOOSER_ERROR_BAD_FILENAME,
7590- _("Cannot change to folder because it is not local"));
7591-
7592- profile_end ("end - not local", (char *) path);
7593- return FALSE;
7594- }
7595-
7596- if (impl->update_current_folder_handle)
7597- gtk_file_system_cancel_operation (impl->update_current_folder_handle);
7598-
7599- /* Test validity of path here. */
7600- data = g_new0 (struct UpdateCurrentFolderData, 1);
7601- data->impl = impl;
7602- data->path = gtk_file_path_copy (path);
7603- data->keep_trail = keep_trail;
7604- data->clear_entry = clear_entry;
7605-
7606- impl->reload_state = RELOAD_HAS_FOLDER;
7607-
7608- impl->update_current_folder_handle =
7609- gtk_file_system_get_info (impl->file_system, path, GTK_FILE_INFO_IS_FOLDER,
7610- update_current_folder_get_info_cb,
7611- data);
7612-
7613- set_busy_cursor (impl, TRUE);
7614-
7615- profile_end ("end", NULL);
7616- return TRUE;
7617-}
7618-
7619-static GtkFilePath *
7620-gtk_file_chooser_default_get_current_folder (GtkFileChooser *chooser)
7621-{
7622- GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
7623-
7624- if (impl->operation_mode == OPERATION_MODE_SEARCH ||
7625- impl->operation_mode == OPERATION_MODE_RECENT)
7626- return NULL;
7627-
7628- if (impl->reload_state == RELOAD_EMPTY)
7629- {
7630- char *current_working_dir;
7631- GtkFilePath *path;
7632-
7633- /* We are unmapped, or we had an error while loading the last folder. We'll return
7634- * the $cwd since once we get (re)mapped, we'll load $cwd anyway unless the caller
7635- * explicitly calls set_current_folder() on us.
7636- */
7637- current_working_dir = g_get_current_dir ();
7638- path = gtk_file_system_filename_to_path (impl->file_system, current_working_dir);
7639- g_free (current_working_dir);
7640- return path;
7641- }
7642-
7643- return gtk_file_path_copy (impl->current_folder);
7644-}
7645-
7646-static void
7647-gtk_file_chooser_default_set_current_name (GtkFileChooser *chooser,
7648- const gchar *name)
7649-{
7650- GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
7651-
7652- g_return_if_fail (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE ||
7653- impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER);
7654-
7655- pending_select_paths_free (impl);
7656- _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), name);
7657-}
7658-
7659-static void
7660-select_func (GtkFileSystemModel *model,
7661- GtkTreePath *path,
7662- GtkTreeIter *iter,
7663- gpointer user_data)
7664-{
7665- GtkFileChooserDefault *impl = user_data;
7666- GtkTreeSelection *selection;
7667- GtkTreeIter sorted_iter;
7668-
7669- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
7670-
7671- gtk_tree_model_sort_convert_child_iter_to_iter (impl->sort_model, &sorted_iter, iter);
7672- gtk_tree_selection_select_iter (selection, &sorted_iter);
7673-}
7674-
7675-static gboolean
7676-gtk_file_chooser_default_select_path (GtkFileChooser *chooser,
7677- const GtkFilePath *path,
7678- GError **error)
7679-{
7680- GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
7681- GtkFilePath *parent_path;
7682- gboolean same_path;
7683-
7684- if (!gtk_file_system_get_parent (impl->file_system, path, &parent_path, error))
7685- return FALSE;
7686-
7687- if (!parent_path)
7688- return _gtk_file_chooser_set_current_folder_path (chooser, path, error);
7689-
7690- if (impl->operation_mode == OPERATION_MODE_SEARCH ||
7691- impl->operation_mode == OPERATION_MODE_RECENT ||
7692- impl->load_state == LOAD_EMPTY)
7693- {
7694- same_path = FALSE;
7695- }
7696- else
7697- {
7698- g_assert (impl->current_folder != NULL);
7699-
7700- same_path = gtk_file_path_compare (parent_path, impl->current_folder) == 0;
7701- }
7702-
7703- if (same_path && impl->load_state == LOAD_FINISHED)
7704- {
7705- gboolean result;
7706- GSList paths;
7707-
7708- paths.data = (gpointer) path;
7709- paths.next = NULL;
7710-
7711- result = show_and_select_paths (impl, parent_path, &paths, error);
7712- gtk_file_path_free (parent_path);
7713- return result;
7714- }
7715-
7716- pending_select_paths_add (impl, path);
7717-
7718- if (!same_path)
7719- {
7720- gboolean result;
7721-
7722- result = _gtk_file_chooser_set_current_folder_path (chooser, parent_path, error);
7723- gtk_file_path_free (parent_path);
7724- return result;
7725- }
7726-
7727- gtk_file_path_free (parent_path);
7728- return TRUE;
7729-}
7730-
7731-static void
7732-unselect_func (GtkFileSystemModel *model,
7733- GtkTreePath *path,
7734- GtkTreeIter *iter,
7735- gpointer user_data)
7736-{
7737- GtkFileChooserDefault *impl = user_data;
7738- GtkTreeView *tree_view = GTK_TREE_VIEW (impl->browse_files_tree_view);
7739- GtkTreePath *sorted_path;
7740-
7741- sorted_path = gtk_tree_model_sort_convert_child_path_to_path (impl->sort_model,
7742- path);
7743- gtk_tree_selection_unselect_path (gtk_tree_view_get_selection (tree_view),
7744- sorted_path);
7745- gtk_tree_path_free (sorted_path);
7746-}
7747-
7748-static void
7749-gtk_file_chooser_default_unselect_path (GtkFileChooser *chooser,
7750- const GtkFilePath *path)
7751-{
7752- GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
7753-
7754- if (!impl->browse_files_model)
7755- return;
7756-
7757- _gtk_file_system_model_path_do (impl->browse_files_model, path,
7758- unselect_func, impl);
7759-}
7760-
7761-static gboolean
7762-maybe_select (GtkTreeModel *model,
7763- GtkTreePath *path,
7764- GtkTreeIter *iter,
7765- gpointer data)
7766-{
7767- GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (data);
7768- GtkTreeSelection *selection;
7769- const GtkFileInfo *info;
7770- gboolean is_folder;
7771-
7772- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
7773-
7774- info = get_list_file_info (impl, iter);
7775- is_folder = gtk_file_info_get_is_folder (info);
7776-
7777- if ((is_folder && impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER) ||
7778- (!is_folder && impl->action == GTK_FILE_CHOOSER_ACTION_OPEN))
7779- gtk_tree_selection_select_iter (selection, iter);
7780- else
7781- gtk_tree_selection_unselect_iter (selection, iter);
7782-
7783- return FALSE;
7784-}
7785-
7786-static void
7787-gtk_file_chooser_default_select_all (GtkFileChooser *chooser)
7788-{
7789- GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
7790-
7791- if (impl->operation_mode == OPERATION_MODE_SEARCH ||
7792- impl->operation_mode == OPERATION_MODE_RECENT)
7793- {
7794- GtkTreeSelection *selection;
7795-
7796- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
7797- gtk_tree_selection_select_all (selection);
7798- return;
7799- }
7800-
7801- if (impl->select_multiple)
7802- gtk_tree_model_foreach (GTK_TREE_MODEL (impl->sort_model),
7803- maybe_select, impl);
7804-}
7805-
7806-static void
7807-gtk_file_chooser_default_unselect_all (GtkFileChooser *chooser)
7808-{
7809- GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
7810- GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
7811-
7812- gtk_tree_selection_unselect_all (selection);
7813- pending_select_paths_free (impl);
7814-}
7815-
7816-/* Checks whether the filename entry for the Save modes contains a well-formed filename.
7817- *
7818- * is_well_formed_ret - whether what the user typed passes gkt_file_system_make_path()
7819- *
7820- * is_empty_ret - whether the file entry is totally empty
7821- *
7822- * is_file_part_empty_ret - whether the file part is empty (will be if user types "foobar/", and
7823- * the path will be "$cwd/foobar")
7824- */
7825-static void
7826-check_save_entry (GtkFileChooserDefault *impl,
7827- GtkFilePath **path_ret,
7828- gboolean *is_well_formed_ret,
7829- gboolean *is_empty_ret,
7830- gboolean *is_file_part_empty_ret,
7831- gboolean *is_folder)
7832-{
7833- GtkFileChooserEntry *chooser_entry;
7834- const GtkFilePath *current_folder;
7835- const char *file_part;
7836- GtkFilePath *path;
7837- GError *error;
7838-
7839- g_assert (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
7840- || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER
7841- || ((impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
7842- || impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
7843- && impl->location_mode == LOCATION_MODE_FILENAME_ENTRY));
7844-
7845- chooser_entry = GTK_FILE_CHOOSER_ENTRY (impl->location_entry);
7846-
7847- if (strlen (gtk_entry_get_text (GTK_ENTRY (chooser_entry))) == 0)
7848- {
7849- *path_ret = NULL;
7850- *is_well_formed_ret = TRUE;
7851- *is_empty_ret = TRUE;
7852- *is_file_part_empty_ret = TRUE;
7853- *is_folder = FALSE;
7854-
7855- return;
7856- }
7857-
7858- *is_empty_ret = FALSE;
7859-
7860- current_folder = _gtk_file_chooser_entry_get_current_folder (chooser_entry);
7861- if (!current_folder)
7862- {
7863- *path_ret = NULL;
7864- *is_well_formed_ret = FALSE;
7865- *is_file_part_empty_ret = FALSE;
7866- *is_folder = FALSE;
7867-
7868- return;
7869- }
7870-
7871- file_part = _gtk_file_chooser_entry_get_file_part (chooser_entry);
7872-
7873- if (!file_part || file_part[0] == '\0')
7874- {
7875- *path_ret = gtk_file_path_copy (current_folder);
7876- *is_well_formed_ret = TRUE;
7877- *is_file_part_empty_ret = TRUE;
7878- *is_folder = TRUE;
7879-
7880- return;
7881- }
7882-
7883- *is_file_part_empty_ret = FALSE;
7884-
7885- error = NULL;
7886- path = gtk_file_system_make_path (impl->file_system, current_folder, file_part, &error);
7887-
7888- if (!path)
7889- {
7890- error_building_filename_dialog (impl, current_folder, file_part, error);
7891- *path_ret = NULL;
7892- *is_well_formed_ret = FALSE;
7893- *is_folder = FALSE;
7894-
7895- return;
7896- }
7897-
7898- *path_ret = path;
7899- *is_well_formed_ret = TRUE;
7900- *is_folder = _gtk_file_chooser_entry_get_is_folder (chooser_entry, path);
7901-}
7902-
7903-struct get_paths_closure {
7904- GtkFileChooserDefault *impl;
7905- GSList *result;
7906- GtkFilePath *path_from_entry;
7907-};
7908-
7909-static void
7910-get_paths_foreach (GtkTreeModel *model,
7911- GtkTreePath *path,
7912- GtkTreeIter *iter,
7913- gpointer data)
7914-{
7915- struct get_paths_closure *info;
7916- const GtkFilePath *file_path;
7917- GtkFileSystemModel *fs_model;
7918- GtkTreeIter sel_iter;
7919-
7920- info = data;
7921- fs_model = info->impl->browse_files_model;
7922- gtk_tree_model_sort_convert_iter_to_child_iter (info->impl->sort_model, &sel_iter, iter);
7923-
7924- file_path = _gtk_file_system_model_get_path (fs_model, &sel_iter);
7925- if (!file_path)
7926- return; /* We are on the editable row */
7927+ case GTK_FILE_CHOOSER_PROP_FILTER:
7928+ g_value_set_object (value, impl->current_filter);
7929+ break;
7930
7931- if (!info->path_from_entry
7932- || gtk_file_path_compare (info->path_from_entry, file_path) != 0)
7933- info->result = g_slist_prepend (info->result, gtk_file_path_copy (file_path));
7934-}
7935+ case GTK_FILE_CHOOSER_PROP_LOCAL_ONLY:
7936+ g_value_set_boolean (value, impl->local_only);
7937+ break;
7938
7939-static GSList *
7940-gtk_file_chooser_default_get_paths (GtkFileChooser *chooser)
7941-{
7942- GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
7943- struct get_paths_closure info;
7944- GtkWindow *toplevel;
7945- GtkWidget *current_focus;
7946- gboolean file_list_seen;
7947+ case GTK_FILE_CHOOSER_PROP_SELECT_MULTIPLE:
7948+ g_value_set_boolean (value, impl->select_multiple);
7949+ break;
7950
7951- if (impl->operation_mode == OPERATION_MODE_SEARCH)
7952- return search_get_selected_paths (impl);
7953+ case GTK_FILE_CHOOSER_PROP_SHOW_HIDDEN:
7954+ g_value_set_boolean (value, impl->show_hidden);
7955+ break;
7956
7957- if (impl->operation_mode == OPERATION_MODE_RECENT)
7958- return recent_get_selected_paths (impl);
7959+ case GTK_FILE_CHOOSER_PROP_ROOT_FOLDER:
7960+ g_value_set_string (value, impl->root_folder);
7961+ break;
7962
7963- info.impl = impl;
7964- info.result = NULL;
7965- info.path_from_entry = NULL;
7966+ case GTK_FILE_CHOOSER_PROP_SHOW_CREATE_FOLDER:
7967+ g_value_set_boolean (value, impl->show_create_folder);
7968+ break;
7969
7970- toplevel = get_toplevel (GTK_WIDGET (impl));
7971- if (toplevel)
7972- current_focus = gtk_window_get_focus (toplevel);
7973- else
7974- current_focus = NULL;
7975+ case GTK_FILE_CHOOSER_PROP_PREVIEW_WIDGET:
7976+ g_value_set_object (value, NULL);
7977+ break;
7978
7979- file_list_seen = FALSE;
7980- if (current_focus == impl->browse_files_tree_view)
7981- {
7982- GtkTreeSelection *selection;
7983+ case GTK_FILE_CHOOSER_PROP_PREVIEW_WIDGET_ACTIVE:
7984+ g_value_set_boolean (value, FALSE);
7985+ break;
7986
7987- file_list:
7988+ case GTK_FILE_CHOOSER_PROP_USE_PREVIEW_LABEL:
7989+ g_value_set_boolean (value, FALSE);
7990+ break;
7991
7992- file_list_seen = TRUE;
7993- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
7994- gtk_tree_selection_selected_foreach (selection, get_paths_foreach, &info);
7995+ case GTK_FILE_CHOOSER_PROP_DO_OVERWRITE_CONFIRMATION:
7996+ g_value_set_boolean (value, impl->do_overwrite_confirmation);
7997+ break;
7998
7999- /* If there is no selection in the file list, we probably have this situation:
8000- *
8001- * 1. The user typed a filename in the SAVE filename entry ("foo.txt").
8002- * 2. He then double-clicked on a folder ("bar") in the file list
8003- *
8004- * So we want the selection to be "bar/foo.txt". Jump to the case for the
8005- * filename entry to see if that is the case.
8006- */
8007- if (info.result == NULL && impl->location_entry)
8008- goto file_entry;
8009+ default:
8010+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
8011+ break;
8012 }
8013- else if (impl->location_entry && current_focus == impl->location_entry)
8014+}
8015+
8016+/* Removes the settings signal handler. It's safe to call multiple times */
8017+static void
8018+remove_settings_signal (GtkFileChooserDefault *impl,
8019+ GdkScreen *screen)
8020+{
8021+ if (impl->settings_signal_id)
8022 {
8023- gboolean is_well_formed, is_empty, is_file_part_empty, is_folder;
8024+ GtkSettings *settings;
8025
8026- file_entry:
8027+ settings = gtk_settings_get_for_screen (screen);
8028+ g_signal_handler_disconnect (settings,
8029+ impl->settings_signal_id);
8030+ impl->settings_signal_id = 0;
8031+ }
8032+}
8033
8034- check_save_entry (impl, &info.path_from_entry, &is_well_formed, &is_empty, &is_file_part_empty, &is_folder);
8035+static void
8036+gtk_file_chooser_default_dispose (GObject *object)
8037+{
8038+ GSList *l;
8039+ GtkFileChooserDefault *impl = (GtkFileChooserDefault *) object;
8040
8041- if (is_empty)
8042- goto out;
8043+ if (impl->volumes_changed_id > 0)
8044+ {
8045+ g_signal_handler_disconnect (impl->file_system, impl->volumes_changed_id);
8046+ impl->volumes_changed_id = 0;
8047+ }
8048
8049- if (!is_well_formed)
8050- return NULL;
8051+ pending_select_paths_free (impl);
8052
8053- if (is_file_part_empty && impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
8054- {
8055- gtk_file_path_free (info.path_from_entry);
8056- return NULL;
8057- }
8058+ /* cancel all pending operations */
8059+ if (impl->pending_handles)
8060+ {
8061+ for (l = impl->pending_handles; l; l = l->next)
8062+ {
8063+ GtkFileSystemHandle *handle =l->data;
8064+ gtk_file_system_cancel_operation (handle);
8065+ }
8066+ g_slist_free (impl->pending_handles);
8067+ impl->pending_handles = NULL;
8068+ }
8069
8070- if (info.path_from_entry)
8071- info.result = g_slist_prepend (info.result, info.path_from_entry);
8072- else if (!file_list_seen)
8073- goto file_list;
8074- else
8075- return NULL;
8076+ if (impl->reload_icon_handles)
8077+ {
8078+ for (l = impl->reload_icon_handles; l; l = l->next)
8079+ {
8080+ GtkFileSystemHandle *handle =l->data;
8081+ gtk_file_system_cancel_operation (handle);
8082+ }
8083+ g_slist_free (impl->reload_icon_handles);
8084+ impl->reload_icon_handles = NULL;
8085 }
8086- else if (impl->toplevel_last_focus_widget == impl->browse_files_tree_view)
8087- goto file_list;
8088- else if (impl->location_entry && impl->toplevel_last_focus_widget == impl->location_entry)
8089- goto file_entry;
8090- else
8091+
8092+ if (impl->update_current_folder_handle)
8093 {
8094- /* The focus is on a dialog's action area button or something else */
8095- if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE ||
8096- impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
8097- goto file_entry;
8098- else
8099- goto file_list;
8100+ gtk_file_system_cancel_operation (impl->update_current_folder_handle);
8101+ impl->update_current_folder_handle = NULL;
8102 }
8103
8104- out:
8105+ if (impl->show_and_select_paths_handle)
8106+ {
8107+ gtk_file_system_cancel_operation (impl->show_and_select_paths_handle);
8108+ impl->show_and_select_paths_handle = NULL;
8109+ }
8110
8111- /* If there's no folder selected, and we're in SELECT_FOLDER mode, then we
8112- * fall back to the current directory */
8113- if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER &&
8114- info.result == NULL)
8115+ if (impl->should_respond_get_info_handle)
8116 {
8117- info.result = g_slist_prepend (info.result, _gtk_file_chooser_get_current_folder_path (chooser));
8118+ gtk_file_system_cancel_operation (impl->should_respond_get_info_handle);
8119+ impl->should_respond_get_info_handle = NULL;
8120 }
8121
8122- return g_slist_reverse (info.result);
8123-}
8124+ if (impl->update_from_entry_handle)
8125+ {
8126+ gtk_file_system_cancel_operation (impl->update_from_entry_handle);
8127+ impl->update_from_entry_handle = NULL;
8128+ }
8129
8130-static GtkFilePath *
8131-gtk_file_chooser_default_get_preview_path (GtkFileChooser *chooser)
8132-{
8133- GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
8134+ remove_settings_signal (impl, gtk_widget_get_screen (GTK_WIDGET (impl)));
8135
8136- if (impl->preview_path)
8137- return gtk_file_path_copy (impl->preview_path);
8138- else
8139- return NULL;
8140+ G_OBJECT_CLASS (_gtk_file_chooser_default_parent_class)->dispose (object);
8141 }
8142
8143-static GtkFileSystem *
8144-gtk_file_chooser_default_get_file_system (GtkFileChooser *chooser)
8145+/* We override show-all since we have internal widgets that
8146+ * shouldn't be shown when you call show_all(), like the filter
8147+ * combo box.
8148+ */
8149+static void
8150+gtk_file_chooser_default_show_all (GtkWidget *widget)
8151 {
8152- GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
8153-
8154- return impl->file_system;
8155+ gtk_widget_show (widget);
8156 }
8157
8158-/* Shows or hides the filter widgets */
8159+/* Handler for GtkWindow::set-focus; this is where we save the last-focused
8160+ * widget on our toplevel. See gtk_file_chooser_default_hierarchy_changed()
8161+ */
8162 static void
8163-show_filters (GtkFileChooserDefault *impl,
8164- gboolean show)
8165+toplevel_set_focus_cb (GtkWindow *window,
8166+ GtkWidget *focus,
8167+ GtkFileChooserDefault *impl)
8168 {
8169- if (show)
8170- gtk_widget_show (impl->filter_combo_hbox);
8171- else
8172- gtk_widget_hide (impl->filter_combo_hbox);
8173+ impl->toplevel_last_focus_widget = gtk_window_get_focus (window);
8174 }
8175
8176+/* We monitor the focus widget on our toplevel to be able to know which widget
8177+ * was last focused at the time our "should_respond" method gets called.
8178+ */
8179 static void
8180-gtk_file_chooser_default_add_filter (GtkFileChooser *chooser,
8181- GtkFileFilter *filter)
8182+gtk_file_chooser_default_hierarchy_changed (GtkWidget *widget,
8183+ GtkWidget *previous_toplevel)
8184 {
8185- GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
8186- const gchar *name;
8187+ GtkFileChooserDefault *impl;
8188+ GtkWidget *toplevel;
8189
8190- if (g_slist_find (impl->filters, filter))
8191+ impl = GTK_FILE_CHOOSER_DEFAULT (widget);
8192+
8193+ if (previous_toplevel)
8194 {
8195- g_warning ("gtk_file_chooser_add_filter() called on filter already in list\n");
8196- return;
8197+ g_assert (impl->toplevel_set_focus_id != 0);
8198+ g_signal_handler_disconnect (previous_toplevel, impl->toplevel_set_focus_id);
8199+ impl->toplevel_set_focus_id = 0;
8200+ impl->toplevel_last_focus_widget = NULL;
8201 }
8202+ else
8203+ g_assert (impl->toplevel_set_focus_id == 0);
8204
8205- g_object_ref_sink (filter);
8206- impl->filters = g_slist_append (impl->filters, filter);
8207+ toplevel = gtk_widget_get_toplevel (widget);
8208+ if (GTK_IS_WINDOW (toplevel))
8209+ {
8210+ impl->toplevel_set_focus_id = g_signal_connect (toplevel, "set_focus",
8211+ G_CALLBACK (toplevel_set_focus_cb), impl);
8212+ impl->toplevel_last_focus_widget = gtk_window_get_focus (GTK_WINDOW (toplevel));
8213+ }
8214+}
8215
8216- name = gtk_file_filter_get_name (filter);
8217- if (!name)
8218- name = "Untitled filter"; /* Place-holder, doesn't need to be marked for translation */
8219+/* Changes the icons wherever it is needed */
8220+static void
8221+change_icon_theme (GtkFileChooserDefault *impl)
8222+{
8223+ GtkSettings *settings;
8224+ gint width, height;
8225
8226- gtk_combo_box_append_text (GTK_COMBO_BOX (impl->filter_combo), name);
8227+ profile_start ("start", NULL);
8228
8229- if (!g_slist_find (impl->filters, impl->current_filter))
8230- set_current_filter (impl, filter);
8231+ settings = gtk_settings_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (impl)));
8232+
8233+ if (gtk_icon_size_lookup_for_settings (settings, GTK_ICON_SIZE_MENU, &width, &height))
8234+ impl->icon_size = MAX (width, height);
8235+ else
8236+ impl->icon_size = FALLBACK_ICON_SIZE;
8237+
8238+ gtk_widget_queue_resize (impl->browse_files_tree_view);
8239+
8240+ profile_end ("end", NULL);
8241+}
8242+
8243+/* Callback used when a GtkSettings value changes */
8244+static void
8245+settings_notify_cb (GObject *object,
8246+ GParamSpec *pspec,
8247+ GtkFileChooserDefault *impl)
8248+{
8249+ const char *name;
8250+
8251+ profile_start ("start", NULL);
8252+
8253+ name = g_param_spec_get_name (pspec);
8254+
8255+ if (strcmp (name, "gtk-icon-theme-name") == 0
8256+ || strcmp (name, "gtk-icon-sizes") == 0)
8257+ change_icon_theme (impl);
8258
8259- show_filters (impl, TRUE);
8260+ profile_end ("end", NULL);
8261 }
8262
8263+/* Installs a signal handler for GtkSettings so that we can monitor changes in
8264+ * the icon theme.
8265+ */
8266 static void
8267-gtk_file_chooser_default_remove_filter (GtkFileChooser *chooser,
8268- GtkFileFilter *filter)
8269+check_icon_theme (GtkFileChooserDefault *impl)
8270 {
8271- GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
8272- GtkTreeModel *model;
8273- GtkTreeIter iter;
8274- gint filter_index;
8275+ GtkSettings *settings;
8276
8277- filter_index = g_slist_index (impl->filters, filter);
8278+ profile_start ("start", NULL);
8279
8280- if (filter_index < 0)
8281+ if (impl->settings_signal_id)
8282 {
8283- g_warning ("gtk_file_chooser_remove_filter() called on filter not in list\n");
8284+ profile_end ("end", NULL);
8285 return;
8286 }
8287
8288- impl->filters = g_slist_remove (impl->filters, filter);
8289-
8290- if (filter == impl->current_filter)
8291+ if (gtk_widget_has_screen (GTK_WIDGET (impl)))
8292 {
8293- if (impl->filters)
8294- set_current_filter (impl, impl->filters->data);
8295- else
8296- set_current_filter (impl, NULL);
8297+ settings = gtk_settings_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (impl)));
8298+ impl->settings_signal_id = g_signal_connect (settings, "notify",
8299+ G_CALLBACK (settings_notify_cb), impl);
8300+
8301+ change_icon_theme (impl);
8302 }
8303
8304- /* Remove row from the combo box */
8305- model = gtk_combo_box_get_model (GTK_COMBO_BOX (impl->filter_combo));
8306- if (!gtk_tree_model_iter_nth_child (model, &iter, NULL, filter_index))
8307- g_assert_not_reached ();
8308+ profile_end ("end", NULL);
8309+}
8310
8311- gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
8312+static void
8313+gtk_file_chooser_default_style_set (GtkWidget *widget,
8314+ GtkStyle *previous_style)
8315+{
8316+ GtkFileChooserDefault *impl;
8317
8318- g_object_unref (filter);
8319+ profile_start ("start", NULL);
8320
8321- if (!impl->filters)
8322- show_filters (impl, FALSE);
8323-}
8324+ impl = GTK_FILE_CHOOSER_DEFAULT (widget);
8325
8326-static GSList *
8327-gtk_file_chooser_default_list_filters (GtkFileChooser *chooser)
8328-{
8329- GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
8330+ profile_msg (" parent class style_set start", NULL);
8331+ if (GTK_WIDGET_CLASS (_gtk_file_chooser_default_parent_class)->style_set)
8332+ GTK_WIDGET_CLASS (_gtk_file_chooser_default_parent_class)->style_set (widget, previous_style);
8333+ profile_msg (" parent class style_set end", NULL);
8334
8335- return g_slist_copy (impl->filters);
8336-}
8337+ if (gtk_widget_has_screen (GTK_WIDGET (impl)))
8338+ change_icon_theme (impl);
8339
8340-/* Returns the position in the shortcuts tree where the nth specified shortcut would appear */
8341-static int
8342-shortcuts_get_pos_for_shortcut_folder (GtkFileChooserDefault *impl,
8343- int pos)
8344-{
8345- return pos + shortcuts_get_index (impl, SHORTCUTS_SHORTCUTS);
8346-}
8347+ profile_msg (" emit default-size-changed start", NULL);
8348+ g_signal_emit_by_name (widget, "default-size-changed");
8349+ profile_msg (" emit default-size-changed end", NULL);
8350
8351-struct AddShortcutData
8352-{
8353- GtkFileChooserDefault *impl;
8354- GtkFilePath *path;
8355-};
8356+ profile_end ("end", NULL);
8357+}
8358
8359 static void
8360-add_shortcut_get_info_cb (GtkFileSystemHandle *handle,
8361- const GtkFileInfo *info,
8362- const GError *error,
8363- gpointer user_data)
8364+gtk_file_chooser_default_screen_changed (GtkWidget *widget,
8365+ GdkScreen *previous_screen)
8366 {
8367- int pos;
8368- gboolean cancelled = handle->cancelled;
8369- struct AddShortcutData *data = user_data;
8370-
8371- if (!g_slist_find (data->impl->loading_shortcuts, handle))
8372- goto out;
8373+ GtkFileChooserDefault *impl;
8374
8375- data->impl->loading_shortcuts = g_slist_remove (data->impl->loading_shortcuts, handle);
8376+ profile_start ("start", NULL);
8377
8378- if (cancelled || error || !gtk_file_info_get_is_folder (info))
8379- goto out;
8380+ impl = GTK_FILE_CHOOSER_DEFAULT (widget);
8381
8382- pos = shortcuts_get_pos_for_shortcut_folder (data->impl, data->impl->num_shortcuts);
8383+ if (GTK_WIDGET_CLASS (_gtk_file_chooser_default_parent_class)->screen_changed)
8384+ GTK_WIDGET_CLASS (_gtk_file_chooser_default_parent_class)->screen_changed (widget, previous_screen);
8385
8386- shortcuts_insert_path (data->impl, pos, SHORTCUT_TYPE_PATH, NULL, data->path, NULL, FALSE, SHORTCUTS_SHORTCUTS);
8387+ remove_settings_signal (impl, previous_screen);
8388+ check_icon_theme (impl);
8389
8390-out:
8391- g_object_unref (data->impl);
8392- gtk_file_path_free (data->path);
8393- g_free (data);
8394+ g_signal_emit_by_name (widget, "default-size-changed");
8395
8396- g_object_unref (handle);
8397+ profile_end ("end", NULL);
8398 }
8399
8400-static gboolean
8401-gtk_file_chooser_default_add_shortcut_folder (GtkFileChooser *chooser,
8402- const GtkFilePath *path,
8403- GError **error)
8404+static void
8405+gtk_file_chooser_default_size_allocate (GtkWidget *widget,
8406+ GtkAllocation *allocation)
8407 {
8408- GtkFileSystemHandle *handle;
8409- GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
8410- struct AddShortcutData *data;
8411- GSList *l;
8412- int pos;
8413-
8414- /* Avoid adding duplicates */
8415- pos = shortcut_find_position (impl, path);
8416- if (pos >= 0 && pos < shortcuts_get_index (impl, SHORTCUTS_BOOKMARKS_SEPARATOR))
8417- {
8418- gchar *uri;
8419+ GtkFileChooserDefault *impl;
8420
8421- uri = gtk_file_system_path_to_uri (impl->file_system, path);
8422- /* translators, "Shortcut" means "Bookmark" here */
8423- g_set_error (error,
8424- GTK_FILE_CHOOSER_ERROR,
8425- GTK_FILE_CHOOSER_ERROR_ALREADY_EXISTS,
8426- _("Shortcut %s already exists"),
8427- uri);
8428- g_free (uri);
8429+ impl = GTK_FILE_CHOOSER_DEFAULT (widget);
8430
8431- return FALSE;
8432- }
8433+ GTK_WIDGET_CLASS (_gtk_file_chooser_default_parent_class)->size_allocate (widget, allocation);
8434
8435- for (l = impl->loading_shortcuts; l; l = l->next)
8436+ if (!gtk_file_chooser_default_get_resizable (GTK_FILE_CHOOSER_EMBED (impl)))
8437 {
8438- GtkFileSystemHandle *h = l->data;
8439- GtkFilePath *p;
8440-
8441- p = g_object_get_data (G_OBJECT (h), "add-shortcut-path-key");
8442- if (p && !gtk_file_path_compare (path, p))
8443- {
8444- gchar *uri;
8445-
8446- uri = gtk_file_system_path_to_uri (impl->file_system, path);
8447- g_set_error (error,
8448- GTK_FILE_CHOOSER_ERROR,
8449- GTK_FILE_CHOOSER_ERROR_ALREADY_EXISTS,
8450- _("Shortcut %s already exists"),
8451- uri);
8452- g_free (uri);
8453-
8454- return FALSE;
8455- }
8456+ /* The dialog is not resizable, we shouldn't
8457+ * trust in the size it has in this stage
8458+ */
8459+ return;
8460 }
8461
8462- data = g_new0 (struct AddShortcutData, 1);
8463- data->impl = g_object_ref (impl);
8464- data->path = gtk_file_path_copy (path);
8465-
8466- handle = gtk_file_system_get_info (impl->file_system, path,
8467- GTK_FILE_INFO_IS_FOLDER,
8468- add_shortcut_get_info_cb, data);
8469-
8470- if (!handle)
8471- return FALSE;
8472-
8473- impl->loading_shortcuts = g_slist_append (impl->loading_shortcuts, handle);
8474- g_object_set_data (G_OBJECT (handle), "add-shortcut-path-key", data->path);
8475-
8476- return TRUE;
8477+ impl->default_width = allocation->width;
8478+ impl->default_height = allocation->height;
8479 }
8480
8481 static gboolean
8482-gtk_file_chooser_default_remove_shortcut_folder (GtkFileChooser *chooser,
8483- const GtkFilePath *path,
8484- GError **error)
8485+get_is_file_filtered (GtkFileChooserDefault *impl,
8486+ const GtkFilePath *path,
8487+ GtkFileInfo *file_info)
8488 {
8489- GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
8490- int pos;
8491- GtkTreeIter iter;
8492- GSList *l;
8493- char *uri;
8494- int i;
8495+ GtkFileFilterInfo filter_info;
8496+ GtkFileFilterFlags needed;
8497+ gboolean result;
8498
8499- for (l = impl->loading_shortcuts; l; l = l->next)
8500- {
8501- GtkFileSystemHandle *h = l->data;
8502- GtkFilePath *p;
8503+ if (!impl->current_filter)
8504+ return FALSE;
8505
8506- p = g_object_get_data (G_OBJECT (h), "add-shortcut-path-key");
8507- if (p && !gtk_file_path_compare (path, p))
8508- {
8509- impl->loading_shortcuts = g_slist_remove (impl->loading_shortcuts, h);
8510- gtk_file_system_cancel_operation (h);
8511- return TRUE;
8512- }
8513- }
8514+ filter_info.contains = GTK_FILE_FILTER_DISPLAY_NAME | GTK_FILE_FILTER_MIME_TYPE;
8515
8516- if (impl->num_shortcuts == 0)
8517- goto out;
8518+ needed = gtk_file_filter_get_needed (impl->current_filter);
8519
8520- pos = shortcuts_get_pos_for_shortcut_folder (impl, 0);
8521- if (!gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (impl->shortcuts_model), &iter, NULL, pos))
8522- g_assert_not_reached ();
8523+ filter_info.display_name = gtk_file_info_get_display_name (file_info);
8524+ filter_info.mime_type = gtk_file_info_get_mime_type (file_info);
8525
8526- for (i = 0; i < impl->num_shortcuts; i++)
8527+ if (needed & GTK_FILE_FILTER_FILENAME)
8528 {
8529- gpointer col_data;
8530- ShortcutType shortcut_type;
8531- GtkFilePath *shortcut;
8532-
8533- gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter,
8534- SHORTCUTS_COL_DATA, &col_data,
8535- SHORTCUTS_COL_TYPE, &shortcut_type,
8536- -1);
8537- g_assert (col_data != NULL);
8538- g_assert (shortcut_type == SHORTCUT_TYPE_PATH);
8539-
8540- shortcut = col_data;
8541- if (gtk_file_path_compare (shortcut, path) == 0)
8542- {
8543- shortcuts_remove_rows (impl, pos + i, 1);
8544- impl->num_shortcuts--;
8545- return TRUE;
8546- }
8547+ filter_info.filename = gtk_file_system_path_to_filename (impl->file_system, path);
8548+ if (filter_info.filename)
8549+ filter_info.contains |= GTK_FILE_FILTER_FILENAME;
8550+ }
8551+ else
8552+ filter_info.filename = NULL;
8553
8554- if (!gtk_tree_model_iter_next (GTK_TREE_MODEL (impl->shortcuts_model), &iter))
8555- g_assert_not_reached ();
8556+ if (needed & GTK_FILE_FILTER_URI)
8557+ {
8558+ filter_info.uri = gtk_file_system_path_to_uri (impl->file_system, path);
8559+ if (filter_info.uri)
8560+ filter_info.contains |= GTK_FILE_FILTER_URI;
8561 }
8562+ else
8563+ filter_info.uri = NULL;
8564
8565- out:
8566+ result = gtk_file_filter_filter (impl->current_filter, &filter_info);
8567
8568- uri = gtk_file_system_path_to_uri (impl->file_system, path);
8569- /* translators, "Shortcut" means "Bookmark" here */
8570- g_set_error (error,
8571- GTK_FILE_CHOOSER_ERROR,
8572- GTK_FILE_CHOOSER_ERROR_NONEXISTENT,
8573- _("Shortcut %s does not exist"),
8574- uri);
8575- g_free (uri);
8576+ if (filter_info.filename)
8577+ g_free ((gchar *)filter_info.filename);
8578+ if (filter_info.uri)
8579+ g_free ((gchar *)filter_info.uri);
8580
8581- return FALSE;
8582+ return !result;
8583 }
8584
8585-static GSList *
8586-gtk_file_chooser_default_list_shortcut_folders (GtkFileChooser *chooser)
8587+static void
8588+settings_load (GtkFileChooserDefault *impl)
8589 {
8590- GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
8591- int pos;
8592- GtkTreeIter iter;
8593- int i;
8594- GSList *list;
8595+ GtkFileChooserSettings *settings;
8596+ gboolean show_hidden;
8597+ gboolean expand_folders;
8598
8599- if (impl->num_shortcuts == 0)
8600- return NULL;
8601+ settings = _gtk_file_chooser_settings_new ();
8602
8603- pos = shortcuts_get_pos_for_shortcut_folder (impl, 0);
8604- if (!gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (impl->shortcuts_model), &iter, NULL, pos))
8605- g_assert_not_reached ();
8606+ show_hidden = _gtk_file_chooser_settings_get_show_hidden (settings);
8607+ expand_folders = _gtk_file_chooser_settings_get_expand_folders (settings);
8608
8609- list = NULL;
8610+ g_object_unref (settings);
8611
8612- for (i = 0; i < impl->num_shortcuts; i++)
8613- {
8614- gpointer col_data;
8615- ShortcutType shortcut_type;
8616- GtkFilePath *shortcut;
8617+ gtk_file_chooser_set_show_hidden (GTK_FILE_CHOOSER (impl), show_hidden);
8618+ impl->expand_folders = expand_folders;
8619+}
8620+
8621+static void
8622+settings_save (GtkFileChooserDefault *impl)
8623+{
8624+ GtkFileChooserSettings *settings;
8625
8626- gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter,
8627- SHORTCUTS_COL_DATA, &col_data,
8628- SHORTCUTS_COL_TYPE, &shortcut_type,
8629- -1);
8630- g_assert (col_data != NULL);
8631- g_assert (shortcut_type == SHORTCUT_TYPE_PATH);
8632+ settings = _gtk_file_chooser_settings_new ();
8633
8634- shortcut = col_data;
8635- list = g_slist_prepend (list, gtk_file_path_copy (shortcut));
8636+ _gtk_file_chooser_settings_set_show_hidden (settings, gtk_file_chooser_get_show_hidden (GTK_FILE_CHOOSER (impl)));
8637+ _gtk_file_chooser_settings_set_expand_folders (settings, impl->expand_folders);
8638
8639- if (i != impl->num_shortcuts - 1)
8640- {
8641- if (!gtk_tree_model_iter_next (GTK_TREE_MODEL (impl->shortcuts_model), &iter))
8642- g_assert_not_reached ();
8643- }
8644- }
8645+ /* NULL GError */
8646+ _gtk_file_chooser_settings_save (settings, NULL);
8647
8648- return g_slist_reverse (list);
8649+ g_object_unref (settings);
8650 }
8651
8652-/* Guesses a size based upon font sizes */
8653+/* GtkWidget::map method */
8654 static void
8655-find_good_size_from_style (GtkWidget *widget,
8656- gint *width,
8657- gint *height)
8658+gtk_file_chooser_default_map (GtkWidget *widget)
8659 {
8660 GtkFileChooserDefault *impl;
8661- int font_size;
8662- GdkScreen *screen;
8663- double resolution;
8664-
8665- g_assert (widget->style != NULL);
8666- impl = GTK_FILE_CHOOSER_DEFAULT (widget);
8667+ char *current_working_dir;
8668
8669- if (impl->default_width == 0 &&
8670- impl->default_height == 0)
8671- {
8672- screen = gtk_widget_get_screen (widget);
8673- if (screen)
8674- {
8675- resolution = gdk_screen_get_resolution (screen);
8676- if (resolution < 0.0) /* will be -1 if the resolution is not defined in the GdkScreen */
8677- resolution = 96.0;
8678- }
8679- else
8680- resolution = 96.0; /* wheeee */
8681+ profile_start ("start", NULL);
8682
8683- font_size = pango_font_description_get_size (widget->style->font_desc);
8684- font_size = PANGO_PIXELS (font_size) * resolution / 72.0;
8685+ impl = GTK_FILE_CHOOSER_DEFAULT (widget);
8686
8687- impl->default_width = font_size * NUM_CHARS;
8688- impl->default_height = font_size * NUM_LINES;
8689- }
8690+ GTK_WIDGET_CLASS (_gtk_file_chooser_default_parent_class)->map (widget);
8691
8692- *width = impl->default_width;
8693- *height = impl->default_height;
8694-}
8695+ switch (impl->reload_state)
8696+ {
8697+ case RELOAD_EMPTY:
8698+ /* The user didn't explicitly give us a folder to display, so we'll use the cwd */
8699+ current_working_dir = g_get_current_dir ();
8700+ gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (impl), current_working_dir);
8701+ g_free (current_working_dir);
8702+ break;
8703
8704-static void
8705-gtk_file_chooser_default_get_default_size (GtkFileChooserEmbed *chooser_embed,
8706- gint *default_width,
8707- gint *default_height)
8708-{
8709- GtkFileChooserDefault *impl;
8710- GtkRequisition req;
8711+ case RELOAD_HAS_FOLDER:
8712+ /* Nothing; we are already loading or loaded, so we don't need to reload */
8713+ break;
8714
8715- impl = GTK_FILE_CHOOSER_DEFAULT (chooser_embed);
8716- find_good_size_from_style (GTK_WIDGET (chooser_embed), default_width, default_height);
8717+ case RELOAD_WAS_UNMAPPED:
8718+ /* Just reload the current folder; else continue the pending load. */
8719+ if (impl->current_folder)
8720+ {
8721+ pending_select_paths_store_selection (impl);
8722+ change_folder_and_display_error (impl, impl->current_folder);
8723+ }
8724+ break;
8725
8726- if (impl->preview_widget_active &&
8727- impl->preview_widget &&
8728- GTK_WIDGET_VISIBLE (impl->preview_widget))
8729- {
8730- gtk_widget_size_request (impl->preview_box, &req);
8731- *default_width += PREVIEW_HBOX_SPACING + req.width;
8732+ default:
8733+ g_assert_not_reached ();
8734 }
8735
8736- if (impl->extra_widget &&
8737- GTK_WIDGET_VISIBLE (impl->extra_widget))
8738- {
8739- gtk_widget_size_request (impl->extra_align, &req);
8740- *default_height += GTK_BOX (chooser_embed)->spacing + req.height;
8741- }
8742+ settings_load (impl);
8743+
8744+ profile_end ("end", NULL);
8745 }
8746
8747-static gboolean
8748-gtk_file_chooser_default_get_resizable (GtkFileChooserEmbed *chooser_embed)
8749+/* GtkWidget::unmap method */
8750+static void
8751+gtk_file_chooser_default_unmap (GtkWidget *widget)
8752 {
8753 GtkFileChooserDefault *impl;
8754
8755- impl = GTK_FILE_CHOOSER_DEFAULT (chooser_embed);
8756+ impl = GTK_FILE_CHOOSER_DEFAULT (widget);
8757
8758- return (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
8759- impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
8760- gtk_expander_get_expanded (GTK_EXPANDER (impl->save_expander)));
8761-}
8762+ settings_save (impl);
8763
8764-struct switch_folder_closure {
8765- GtkFileChooserDefault *impl;
8766- const GtkFilePath *path;
8767- int num_selected;
8768-};
8769+ GTK_WIDGET_CLASS (_gtk_file_chooser_default_parent_class)->unmap (widget);
8770
8771-/* Used from gtk_tree_selection_selected_foreach() in switch_to_selected_folder() */
8772-static void
8773-switch_folder_foreach_cb (GtkTreeModel *model,
8774- GtkTreePath *path,
8775- GtkTreeIter *iter,
8776- gpointer data)
8777+ impl->reload_state = RELOAD_WAS_UNMAPPED;
8778+}
8779+
8780+static gboolean
8781+list_model_filter_func (GtkFileSystemModel *model,
8782+ GtkFilePath *path,
8783+ const GtkFileInfo *file_info,
8784+ gpointer user_data)
8785 {
8786- struct switch_folder_closure *closure;
8787- GtkTreeIter child_iter;
8788+ GtkFileChooserDefault *impl = user_data;
8789
8790- closure = data;
8791+ if (!impl->current_filter)
8792+ return TRUE;
8793
8794- gtk_tree_model_sort_convert_iter_to_child_iter (closure->impl->sort_model, &child_iter, iter);
8795+ if (gtk_file_info_get_is_folder (file_info))
8796+ return TRUE;
8797
8798- closure->path = _gtk_file_system_model_get_path (closure->impl->browse_files_model, &child_iter);
8799- closure->num_selected++;
8800+ return !get_is_file_filtered (impl, path, (GtkFileInfo *) file_info);
8801 }
8802
8803-/* Changes to the selected folder in the list view */
8804 static void
8805-switch_to_selected_folder (GtkFileChooserDefault *impl)
8806+install_list_model_filter (GtkFileChooserDefault *impl)
8807 {
8808- GtkTreeSelection *selection;
8809- struct switch_folder_closure closure;
8810-
8811- /* We do this with foreach() rather than get_selected() as we may be in
8812- * multiple selection mode
8813- */
8814+ GtkFileSystemModelFilter filter;
8815+ gpointer data;
8816
8817- closure.impl = impl;
8818- closure.path = NULL;
8819- closure.num_selected = 0;
8820+ g_assert (impl->browse_files_model != NULL);
8821
8822- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
8823- gtk_tree_selection_selected_foreach (selection, switch_folder_foreach_cb, &closure);
8824+ if (impl->current_filter)
8825+ {
8826+ filter = list_model_filter_func;
8827+ data = impl;
8828+ }
8829+ else
8830+ {
8831+ filter = NULL;
8832+ data = NULL;
8833+ }
8834+
8835+ _gtk_file_system_model_set_filter (impl->browse_files_model,
8836+ filter,
8837+ data);
8838+}
8839
8840- g_assert (closure.path && closure.num_selected == 1);
8841+#define COMPARE_DIRECTORIES \
8842+ GtkFileChooserDefault *impl = user_data; \
8843+ const GtkFileInfo *info_a = _gtk_file_system_model_get_info (impl->browse_files_model, a); \
8844+ const GtkFileInfo *info_b = _gtk_file_system_model_get_info (impl->browse_files_model, b); \
8845+ gboolean dir_a, dir_b; \
8846+ \
8847+ if (info_a) \
8848+ dir_a = gtk_file_info_get_is_folder (info_a); \
8849+ else \
8850+ return impl->list_sort_ascending ? -1 : 1; \
8851+ \
8852+ if (info_b) \
8853+ dir_b = gtk_file_info_get_is_folder (info_b); \
8854+ else \
8855+ return impl->list_sort_ascending ? 1 : -1; \
8856+ \
8857+ if (dir_a != dir_b) \
8858+ return impl->list_sort_ascending ? (dir_a ? -1 : 1) : (dir_a ? 1 : -1) /* Directories *always* go first */
8859
8860- change_folder_and_display_error (impl, closure.path, FALSE);
8861+/* Sort callback for the filename column */
8862+static gint
8863+name_sort_func (GtkTreeModel *model,
8864+ GtkTreeIter *a,
8865+ GtkTreeIter *b,
8866+ gpointer user_data)
8867+{
8868+ COMPARE_DIRECTORIES;
8869+ else
8870+ return strcmp (gtk_file_info_get_display_key (info_a), gtk_file_info_get_display_key (info_b));
8871 }
8872
8873-/* Gets the GtkFileInfo for the selected row in the file list; assumes single
8874- * selection mode.
8875- */
8876-static const GtkFileInfo *
8877-get_selected_file_info_from_file_list (GtkFileChooserDefault *impl,
8878- gboolean *had_selection)
8879+/* Sort callback for the size column */
8880+static gint
8881+size_sort_func (GtkTreeModel *model,
8882+ GtkTreeIter *a,
8883+ GtkTreeIter *b,
8884+ gpointer user_data)
8885 {
8886- GtkTreeSelection *selection;
8887- GtkTreeIter iter, child_iter;
8888- const GtkFileInfo *info;
8889-
8890- g_assert (!impl->select_multiple);
8891- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
8892- if (!gtk_tree_selection_get_selected (selection, NULL, &iter))
8893+ COMPARE_DIRECTORIES;
8894+ else
8895 {
8896- *had_selection = FALSE;
8897- return NULL;
8898- }
8899-
8900- *had_selection = TRUE;
8901-
8902- gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model,
8903- &child_iter,
8904- &iter);
8905+ gint64 size_a = gtk_file_info_get_size (info_a);
8906+ gint64 size_b = gtk_file_info_get_size (info_b);
8907
8908- info = _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
8909- return info;
8910+ return size_a > size_b ? -1 : (size_a == size_b ? 0 : 1);
8911+ }
8912 }
8913
8914-/* Gets the display name of the selected file in the file list; assumes single
8915- * selection mode and that something is selected.
8916- */
8917-static const gchar *
8918-get_display_name_from_file_list (GtkFileChooserDefault *impl)
8919+/* Sort callback for the mtime column */
8920+static gint
8921+mtime_sort_func (GtkTreeModel *model,
8922+ GtkTreeIter *a,
8923+ GtkTreeIter *b,
8924+ gpointer user_data)
8925 {
8926- const GtkFileInfo *info;
8927- gboolean had_selection;
8928-
8929- info = get_selected_file_info_from_file_list (impl, &had_selection);
8930- g_assert (had_selection);
8931- g_assert (info != NULL);
8932+ COMPARE_DIRECTORIES;
8933+ else
8934+ {
8935+ GtkFileTime ta = gtk_file_info_get_modification_time (info_a);
8936+ GtkFileTime tb = gtk_file_info_get_modification_time (info_b);
8937
8938- return gtk_file_info_get_display_name (info);
8939+ return ta > tb ? -1 : (ta == tb ? 0 : 1);
8940+ }
8941 }
8942
8943+/* Callback used when the sort column changes. We cache the sort order for use
8944+ * in name_sort_func().
8945+ */
8946 static void
8947-add_custom_button_to_dialog (GtkDialog *dialog,
8948- const gchar *mnemonic_label,
8949- const gchar *stock_id,
8950- gint response_id)
8951+list_sort_column_changed_cb (GtkTreeSortable *sortable,
8952+ GtkFileChooserDefault *impl)
8953 {
8954- GtkWidget *button;
8955-
8956- button = gtk_button_new_with_mnemonic (mnemonic_label);
8957- GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
8958- gtk_button_set_image (GTK_BUTTON (button),
8959- gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_BUTTON));
8960- gtk_widget_show (button);
8961+ GtkSortType sort_type;
8962
8963- gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button, response_id);
8964+ if (gtk_tree_sortable_get_sort_column_id (sortable, NULL, &sort_type))
8965+ impl->list_sort_ascending = (sort_type == GTK_SORT_ASCENDING);
8966 }
8967
8968-/* Presents an overwrite confirmation dialog; returns whether we should accept
8969- * the filename.
8970- */
8971-static gboolean
8972-confirm_dialog_should_accept_filename (GtkFileChooserDefault *impl,
8973- const gchar *file_part,
8974- const gchar *folder_display_name)
8975+static void
8976+set_busy_cursor (GtkFileChooserDefault *impl,
8977+ gboolean busy)
8978 {
8979 GtkWindow *toplevel;
8980- GtkWidget *dialog;
8981- int response;
8982+ GdkDisplay *display;
8983+ GdkCursor *cursor;
8984
8985 toplevel = get_toplevel (GTK_WIDGET (impl));
8986+ if (!toplevel || !GTK_WIDGET_REALIZED (toplevel))
8987+ return;
8988
8989- dialog = gtk_message_dialog_new (toplevel,
8990- GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
8991- GTK_MESSAGE_QUESTION,
8992- GTK_BUTTONS_NONE,
8993- _("A file named \"%s\" already exists. Do you want to replace it?"),
8994- file_part);
8995- gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
8996- _("The file already exists in \"%s\". Replacing it will "
8997- "overwrite its contents."),
8998- folder_display_name);
8999-
9000- gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
9001- add_custom_button_to_dialog (GTK_DIALOG (dialog), _("_Replace"), GTK_STOCK_SAVE_AS, GTK_RESPONSE_ACCEPT);
9002- gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
9003-
9004- if (toplevel->group)
9005- gtk_window_group_add_window (toplevel->group, GTK_WINDOW (dialog));
9006+ display = gtk_widget_get_display (GTK_WIDGET (toplevel));
9007
9008- response = gtk_dialog_run (GTK_DIALOG (dialog));
9009+ if (busy)
9010+ cursor = gdk_cursor_new_for_display (display, GDK_WATCH);
9011+ else
9012+ cursor = NULL;
9013
9014- gtk_widget_destroy (dialog);
9015+ gdk_window_set_cursor (GTK_WIDGET (toplevel)->window, cursor);
9016+ gdk_display_flush (display);
9017
9018- return (response == GTK_RESPONSE_ACCEPT);
9019+ if (cursor)
9020+ gdk_cursor_unref (cursor);
9021 }
9022
9023-struct GetDisplayNameData
9024-{
9025- GtkFileChooserDefault *impl;
9026- gchar *file_part;
9027-};
9028-
9029+/* Creates a sort model to wrap the file system model and sets it on the tree view */
9030 static void
9031-confirmation_confirm_get_info_cb (GtkFileSystemHandle *handle,
9032- const GtkFileInfo *info,
9033- const GError *error,
9034- gpointer user_data)
9035+load_set_model (GtkFileChooserDefault *impl)
9036 {
9037- gboolean cancelled = handle->cancelled;
9038- gboolean should_respond = FALSE;
9039- struct GetDisplayNameData *data = user_data;
9040-
9041- if (handle != data->impl->should_respond_get_info_handle)
9042- goto out;
9043-
9044- data->impl->should_respond_get_info_handle = NULL;
9045+ profile_start ("start", NULL);
9046
9047- if (cancelled)
9048- goto out;
9049+ g_assert (impl->browse_files_model != NULL);
9050+ g_assert (impl->sort_model == NULL);
9051
9052- if (error)
9053- /* Huh? Did the folder disappear? Let the caller deal with it */
9054- should_respond = TRUE;
9055- else
9056- should_respond = confirm_dialog_should_accept_filename (data->impl, data->file_part, gtk_file_info_get_display_name (info));
9057+ profile_msg (" gtk_tree_model_sort_new_with_model start", NULL);
9058+ impl->sort_model = (GtkTreeModelSort *)gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (impl->browse_files_model));
9059+ gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->sort_model), FILE_LIST_COL_NAME, name_sort_func, impl, NULL);
9060+ gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->sort_model), FILE_LIST_COL_SIZE, size_sort_func, impl, NULL);
9061+ gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->sort_model), FILE_LIST_COL_MTIME, mtime_sort_func, impl, NULL);
9062+ gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (impl->sort_model), NULL, NULL, NULL);
9063+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (impl->sort_model), FILE_LIST_COL_NAME, GTK_SORT_ASCENDING);
9064+ impl->list_sort_ascending = TRUE;
9065+ profile_msg (" gtk_tree_model_sort_new_with_model end", NULL);
9066
9067- set_busy_cursor (data->impl, FALSE);
9068- if (should_respond)
9069- g_signal_emit_by_name (data->impl, "response-requested");
9070+ g_signal_connect (impl->sort_model, "sort_column_changed",
9071+ G_CALLBACK (list_sort_column_changed_cb), impl);
9072
9073-out:
9074- g_object_unref (data->impl);
9075- g_free (data->file_part);
9076- g_free (data);
9077+ profile_msg (" gtk_tree_view_set_model start", NULL);
9078+ gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view),
9079+ GTK_TREE_MODEL (impl->sort_model));
9080+ gtk_tree_view_columns_autosize (GTK_TREE_VIEW (impl->browse_files_tree_view));
9081+ gtk_tree_view_set_search_column (GTK_TREE_VIEW (impl->browse_files_tree_view),
9082+ GTK_FILE_SYSTEM_MODEL_DISPLAY_NAME);
9083+ profile_msg (" gtk_tree_view_set_model end", NULL);
9084
9085- g_object_unref (handle);
9086+ profile_end ("end", NULL);
9087 }
9088
9089-/* Does overwrite confirmation if appropriate, and returns whether the dialog
9090- * should respond. Can get the file part from the file list or the save entry.
9091- */
9092+/* Timeout callback used when the loading timer expires */
9093 static gboolean
9094-should_respond_after_confirm_overwrite (GtkFileChooserDefault *impl,
9095- const gchar *file_part,
9096- const GtkFilePath *parent_path)
9097+load_timeout_cb (gpointer data)
9098 {
9099- GtkFileChooserConfirmation conf;
9100+ GtkFileChooserDefault *impl;
9101
9102- if (!impl->do_overwrite_confirmation)
9103- return TRUE;
9104+ profile_start ("start", NULL);
9105
9106- conf = GTK_FILE_CHOOSER_CONFIRMATION_CONFIRM;
9107+ GDK_THREADS_ENTER ();
9108
9109- g_signal_emit_by_name (impl, "confirm-overwrite", &conf);
9110+ impl = GTK_FILE_CHOOSER_DEFAULT (data);
9111+ g_assert (impl->load_state == LOAD_PRELOAD);
9112+ g_assert (impl->load_timeout_id != 0);
9113+ g_assert (impl->browse_files_model != NULL);
9114
9115- switch (conf)
9116- {
9117- case GTK_FILE_CHOOSER_CONFIRMATION_CONFIRM:
9118- {
9119- struct GetDisplayNameData *data;
9120+ impl->load_timeout_id = 0;
9121+ impl->load_state = LOAD_LOADING;
9122
9123- g_assert (file_part != NULL);
9124+ load_set_model (impl);
9125
9126- data = g_new0 (struct GetDisplayNameData, 1);
9127- data->impl = g_object_ref (impl);
9128- data->file_part = g_strdup (file_part);
9129+ GDK_THREADS_LEAVE ();
9130
9131- if (impl->should_respond_get_info_handle)
9132- gtk_file_system_cancel_operation (impl->should_respond_get_info_handle);
9133+ profile_end ("end", NULL);
9134
9135- impl->should_respond_get_info_handle =
9136- gtk_file_system_get_info (impl->file_system, parent_path,
9137- GTK_FILE_INFO_DISPLAY_NAME,
9138- confirmation_confirm_get_info_cb,
9139- data);
9140- set_busy_cursor (data->impl, TRUE);
9141- return FALSE;
9142- }
9143+ return FALSE;
9144+}
9145
9146- case GTK_FILE_CHOOSER_CONFIRMATION_ACCEPT_FILENAME:
9147- return TRUE;
9148+/* Sets up a new load timer for the model and switches to the LOAD_PRELOAD state */
9149+static void
9150+load_setup_timer (GtkFileChooserDefault *impl)
9151+{
9152+ g_assert (impl->load_timeout_id == 0);
9153+ g_assert (impl->load_state != LOAD_PRELOAD);
9154
9155- case GTK_FILE_CHOOSER_CONFIRMATION_SELECT_AGAIN:
9156- return FALSE;
9157+ impl->load_timeout_id = g_timeout_add (MAX_LOADING_TIME, load_timeout_cb, impl);
9158+ impl->load_state = LOAD_PRELOAD;
9159+}
9160
9161- default:
9162- g_assert_not_reached ();
9163- return FALSE;
9164+/* Removes the load timeout and switches to the LOAD_FINISHED state */
9165+static void
9166+load_remove_timer (GtkFileChooserDefault *impl)
9167+{
9168+ if (impl->load_timeout_id != 0)
9169+ {
9170+ g_assert (impl->load_state == LOAD_PRELOAD);
9171+
9172+ g_source_remove (impl->load_timeout_id);
9173+ impl->load_timeout_id = 0;
9174+ impl->load_state = LOAD_EMPTY;
9175 }
9176+ else
9177+ g_assert (impl->load_state == LOAD_EMPTY ||
9178+ impl->load_state == LOAD_LOADING ||
9179+ impl->load_state == LOAD_FINISHED);
9180 }
9181
9182-/* Gives the focus to the browse tree view only if it is visible */
9183+/* Selects the first row in the file list */
9184 static void
9185-focus_browse_tree_view_if_possible (GtkFileChooserDefault *impl)
9186+browse_files_select_first_row (GtkFileChooserDefault *impl)
9187 {
9188- gboolean do_focus;
9189+ GtkTreePath *path;
9190
9191- if ((impl->action == GTK_FILE_CHOOSER_ACTION_SAVE ||
9192- impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
9193- && !gtk_expander_get_expanded (GTK_EXPANDER (impl->save_expander)))
9194- do_focus = FALSE;
9195- else
9196- do_focus = TRUE;
9197+ if (!impl->sort_model)
9198+ return;
9199
9200- if (do_focus)
9201- gtk_widget_grab_focus (impl->browse_files_tree_view);
9202+ path = gtk_tree_path_new_from_indices (0, -1);
9203+ gtk_tree_view_set_cursor (GTK_TREE_VIEW (impl->browse_files_tree_view), path, NULL, FALSE);
9204+ gtk_tree_path_free (path);
9205 }
9206
9207+struct center_selected_row_closure {
9208+ GtkFileChooserDefault *impl;
9209+ gboolean already_centered;
9210+};
9211+
9212+/* Callback used from gtk_tree_selection_selected_foreach(); centers the
9213+ * selected row in the tree view.
9214+ */
9215 static void
9216-action_create_folder_cb (GtkFileSystemHandle *handle,
9217- const GtkFilePath *path,
9218- const GError *error,
9219- gpointer user_data)
9220+center_selected_row_foreach_cb (GtkTreeModel *model,
9221+ GtkTreePath *path,
9222+ GtkTreeIter *iter,
9223+ gpointer data)
9224 {
9225- gboolean cancelled = handle->cancelled;
9226- GtkFileChooserDefault *impl = user_data;
9227-
9228- if (!g_slist_find (impl->pending_handles, handle))
9229- goto out;
9230+ struct center_selected_row_closure *closure;
9231
9232- impl->pending_handles = g_slist_remove (impl->pending_handles, handle);
9233+ closure = data;
9234+ if (closure->already_centered)
9235+ return;
9236
9237- set_busy_cursor (impl, FALSE);
9238+ gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (closure->impl->browse_files_tree_view), path, NULL, TRUE, 0.5, 0.0);
9239+ closure->already_centered = TRUE;
9240+}
9241
9242- if (cancelled)
9243- goto out;
9244+/* Centers the selected row in the tree view */
9245+static void
9246+browse_files_center_selected_row (GtkFileChooserDefault *impl)
9247+{
9248+ struct center_selected_row_closure closure;
9249+ GtkTreeSelection *selection;
9250
9251- if (error)
9252- error_creating_folder_dialog (impl, path, g_error_copy (error));
9253- else
9254- g_signal_emit_by_name (impl, "response-requested");
9255+ closure.impl = impl;
9256+ closure.already_centered = FALSE;
9257
9258-out:
9259- g_object_unref (impl);
9260- g_object_unref (handle);
9261+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
9262+ gtk_tree_selection_selected_foreach (selection, center_selected_row_foreach_cb, &closure);
9263 }
9264
9265-struct FileExistsData
9266+struct ShowAndSelectPathsData
9267 {
9268 GtkFileChooserDefault *impl;
9269- gboolean file_exists_and_is_not_folder;
9270- GtkFilePath *parent_path;
9271- GtkFilePath *path;
9272+ GSList *paths;
9273 };
9274
9275 static void
9276-save_entry_get_info_cb (GtkFileSystemHandle *handle,
9277- const GtkFileInfo *info,
9278- const GError *error,
9279- gpointer user_data)
9280+show_and_select_paths_finished_loading (GtkFileFolder *folder,
9281+ gpointer user_data)
9282 {
9283- gboolean parent_is_folder;
9284- gboolean cancelled = handle->cancelled;
9285- struct FileExistsData *data = user_data;
9286+ gboolean have_hidden;
9287+ GSList *l;
9288+ struct ShowAndSelectPathsData *data = user_data;
9289
9290- if (handle != data->impl->should_respond_get_info_handle)
9291- goto out;
9292+ have_hidden = FALSE;
9293
9294- data->impl->should_respond_get_info_handle = NULL;
9295+ for (l = data->paths; l; l = l->next)
9296+ {
9297+ const GtkFilePath *path;
9298+ GtkFileInfo *info;
9299
9300- set_busy_cursor (data->impl, FALSE);
9301+ path = l->data;
9302
9303- if (cancelled)
9304- goto out;
9305+ /* NULL GError */
9306+ info = gtk_file_folder_get_info (folder, path, NULL);
9307+ if (info)
9308+ {
9309+ if (!have_hidden)
9310+ have_hidden = gtk_file_info_get_is_hidden (info);
9311
9312- if (!info)
9313- parent_is_folder = FALSE;
9314- else
9315- parent_is_folder = gtk_file_info_get_is_folder (info);
9316+ gtk_file_info_free (info);
9317
9318- if (parent_is_folder)
9319- {
9320- if (data->impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
9321- {
9322- if (data->file_exists_and_is_not_folder)
9323- {
9324- gboolean retval;
9325- const char *file_part;
9326+ if (have_hidden)
9327+ break; /* we now have all the information we need */
9328+ }
9329+ }
9330
9331- file_part = _gtk_file_chooser_entry_get_file_part (GTK_FILE_CHOOSER_ENTRY (data->impl->location_entry));
9332- retval = should_respond_after_confirm_overwrite (data->impl, file_part, data->parent_path);
9333+ g_signal_handlers_disconnect_by_func (folder,
9334+ show_and_select_paths_finished_loading,
9335+ user_data);
9336
9337- if (retval)
9338- g_signal_emit_by_name (data->impl, "response-requested");
9339- }
9340- else
9341- g_signal_emit_by_name (data->impl, "response-requested");
9342- }
9343- else /* GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER */
9344- {
9345- GtkFileSystemHandle *handle;
9346+ g_object_unref (folder);
9347
9348- g_object_ref (data->impl);
9349- handle = gtk_file_system_create_folder (data->impl->file_system,
9350- data->path,
9351- action_create_folder_cb,
9352- data->impl);
9353- data->impl->pending_handles = g_slist_append (data->impl->pending_handles, handle);
9354- set_busy_cursor (data->impl, TRUE);
9355- }
9356- }
9357- else
9358+ if (have_hidden)
9359+ g_object_set (data->impl, "show-hidden", TRUE, NULL);
9360+
9361+ for (l = data->paths; l; l = l->next)
9362 {
9363- /* This will display an error, which is what we want */
9364- change_folder_and_display_error (data->impl, data->parent_path, FALSE);
9365+ const GtkFilePath *path;
9366+
9367+ path = l->data;
9368+ _gtk_file_system_model_path_do (data->impl->browse_files_model, path,
9369+ select_func, data->impl);
9370 }
9371
9372-out:
9373+ browse_files_center_selected_row (data->impl);
9374+
9375 g_object_unref (data->impl);
9376- gtk_file_path_free (data->path);
9377- gtk_file_path_free (data->parent_path);
9378+ gtk_file_paths_free (data->paths);
9379 g_free (data);
9380-
9381- g_object_unref (handle);
9382 }
9383
9384 static void
9385-file_exists_get_info_cb (GtkFileSystemHandle *handle,
9386- const GtkFileInfo *info,
9387- const GError *error,
9388- gpointer user_data)
9389+show_and_select_paths_get_folder_cb (GtkFileSystemHandle *handle,
9390+ GtkFileFolder *folder,
9391+ const GError *error,
9392+ gpointer user_data)
9393 {
9394- gboolean data_ownership_taken = FALSE;
9395 gboolean cancelled = handle->cancelled;
9396- gboolean file_exists_and_is_not_folder;
9397- struct FileExistsData *data = user_data;
9398+ struct ShowAndSelectPathsData *data = user_data;
9399
9400- if (handle != data->impl->file_exists_get_info_handle)
9401+ if (data->impl->show_and_select_paths_handle != handle)
9402 goto out;
9403
9404- data->impl->file_exists_get_info_handle = NULL;
9405-
9406- set_busy_cursor (data->impl, FALSE);
9407+ data->impl->show_and_select_paths_handle = NULL;
9408
9409- if (cancelled)
9410+ if (cancelled || error)
9411 goto out;
9412
9413- file_exists_and_is_not_folder = info && !gtk_file_info_get_is_folder (info);
9414+ g_object_unref (handle);
9415
9416- if (data->impl->action == GTK_FILE_CHOOSER_ACTION_OPEN)
9417- /* user typed a filename; we are done */
9418- g_signal_emit_by_name (data->impl, "response-requested");
9419- else if (data->impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER
9420- && file_exists_and_is_not_folder)
9421- {
9422- /* Oops, the user typed the name of an existing path which is not
9423- * a folder
9424- */
9425- error_creating_folder_over_existing_file_dialog (data->impl, data->path,
9426- g_error_copy (error));
9427- }
9428+ if (gtk_file_folder_is_finished_loading (folder))
9429+ show_and_select_paths_finished_loading (folder, user_data);
9430 else
9431- {
9432- /* check that everything up to the last component exists */
9433-
9434- data->file_exists_and_is_not_folder = file_exists_and_is_not_folder;
9435- data_ownership_taken = TRUE;
9436-
9437- if (data->impl->should_respond_get_info_handle)
9438- gtk_file_system_cancel_operation (data->impl->should_respond_get_info_handle);
9439+ g_signal_connect (folder, "finished-loading",
9440+ G_CALLBACK (show_and_select_paths_finished_loading),
9441+ user_data);
9442
9443- data->impl->should_respond_get_info_handle =
9444- gtk_file_system_get_info (data->impl->file_system,
9445- data->parent_path,
9446- GTK_FILE_INFO_IS_FOLDER,
9447- save_entry_get_info_cb,
9448- data);
9449- set_busy_cursor (data->impl, TRUE);
9450- }
9451+ return;
9452
9453 out:
9454- if (!data_ownership_taken)
9455- {
9456- g_object_unref (data->impl);
9457- gtk_file_path_free (data->path);
9458- gtk_file_path_free (data->parent_path);
9459- g_free (data);
9460- }
9461+ g_object_unref (data->impl);
9462+ gtk_file_paths_free (data->paths);
9463+ g_free (data);
9464
9465 g_object_unref (handle);
9466 }
9467
9468-static void
9469-paste_text_received (GtkClipboard *clipboard,
9470- const gchar *text,
9471- GtkFileChooserDefault *impl)
9472+static gboolean
9473+show_and_select_paths (GtkFileChooserDefault *impl,
9474+ const GtkFilePath *parent_path,
9475+ GSList *paths,
9476+ GError **error)
9477 {
9478- GtkFilePath *path;
9479+ struct ShowAndSelectPathsData *info;
9480
9481- if (!text)
9482- return;
9483+ profile_start ("start", NULL);
9484
9485- path = gtk_file_system_uri_to_path (impl->file_system, text);
9486- if (!path)
9487+ if (!paths)
9488 {
9489- if (!g_path_is_absolute (text))
9490- {
9491- location_popup_handler (impl, text);
9492- return;
9493- }
9494-
9495- path = gtk_file_system_filename_to_path (impl->file_system, text);
9496- if (!path)
9497- {
9498- location_popup_handler (impl, text);
9499- return;
9500- }
9501+ profile_end ("end", NULL);
9502+ return TRUE;
9503 }
9504
9505- if (!gtk_file_chooser_default_select_path (GTK_FILE_CHOOSER (impl), path, NULL))
9506- location_popup_handler (impl, text);
9507+ info = g_new (struct ShowAndSelectPathsData, 1);
9508+ info->impl = g_object_ref (impl);
9509+ info->paths = gtk_file_paths_copy (paths);
9510
9511- gtk_file_path_free (path);
9512-}
9513+ if (impl->show_and_select_paths_handle)
9514+ gtk_file_system_cancel_operation (impl->show_and_select_paths_handle);
9515
9516-/* Handler for the "location-popup-on-paste" keybinding signal */
9517-static void
9518-location_popup_on_paste_handler (GtkFileChooserDefault *impl)
9519-{
9520- GtkClipboard *clipboard = gtk_widget_get_clipboard (GTK_WIDGET (impl),
9521- GDK_SELECTION_CLIPBOARD);
9522- gtk_clipboard_request_text (clipboard,
9523- (GtkClipboardTextReceivedFunc) paste_text_received,
9524- impl);
9525-}
9526+ impl->show_and_select_paths_handle =
9527+ gtk_file_system_get_folder (impl->file_system, parent_path,
9528+ GTK_FILE_INFO_IS_FOLDER | GTK_FILE_INFO_IS_HIDDEN,
9529+ show_and_select_paths_get_folder_cb, info);
9530
9531+ profile_end ("end", NULL);
9532+ return TRUE;
9533+}
9534
9535-/* Implementation for GtkFileChooserEmbed::should_respond() */
9536-static gboolean
9537-gtk_file_chooser_default_should_respond (GtkFileChooserEmbed *chooser_embed)
9538+/* Processes the pending operation when a folder is finished loading */
9539+static void
9540+pending_select_paths_process (GtkFileChooserDefault *impl)
9541 {
9542- GtkFileChooserDefault *impl;
9543- GtkWidget *toplevel;
9544- GtkWidget *current_focus;
9545+ g_assert (impl->load_state == LOAD_FINISHED);
9546+ g_assert (impl->browse_files_model != NULL);
9547+ g_assert (impl->sort_model != NULL);
9548
9549- impl = GTK_FILE_CHOOSER_DEFAULT (chooser_embed);
9550+ if (impl->pending_select_paths)
9551+ {
9552+ /* NULL GError */
9553+ show_and_select_paths (impl, impl->current_folder, impl->pending_select_paths, NULL);
9554+ pending_select_paths_free (impl);
9555+ browse_files_center_selected_row (impl);
9556+ }
9557+ else
9558+ {
9559+ /* We only select the first row if the chooser is actually mapped ---
9560+ * selecting the first row is to help the user when he is interacting with
9561+ * the chooser, but sometimes a chooser works not on behalf of the user,
9562+ * but rather on behalf of something else like GtkFileChooserButton. In
9563+ * that case, the chooser's selection should be what the caller expects,
9564+ * as the user can't see that something else got selected. See bug #165264.
9565+ *
9566+ * Also, we don't select the first file if we are not in OPEN mode. Doing
9567+ * so would change the contents of the filename entry for SAVE or
9568+ * CREATE_FOLDER, which is undesired; in SELECT_FOLDER, we don't want to
9569+ * select a *different* folder from the one into which the user just
9570+ * navigated.
9571+ */
9572+ if (GTK_WIDGET_MAPPED (impl) && impl->action == GTK_FILE_CHOOSER_ACTION_OPEN)
9573+ browse_files_select_first_row (impl);
9574+ }
9575
9576- toplevel = gtk_widget_get_toplevel (GTK_WIDGET (impl));
9577- g_assert (GTK_IS_WINDOW (toplevel));
9578+ g_assert (impl->pending_select_paths == NULL);
9579+}
9580
9581- current_focus = gtk_window_get_focus (GTK_WINDOW (toplevel));
9582+/* Callback used when the file system model finishes loading */
9583+static void
9584+browse_files_model_finished_loading_cb (GtkFileSystemModel *model,
9585+ GtkFileChooserDefault *impl)
9586+{
9587+ profile_start ("start", NULL);
9588
9589- if (current_focus == impl->browse_files_tree_view)
9590+ if (impl->load_state == LOAD_PRELOAD)
9591 {
9592- /* The following array encodes what we do based on the impl->action and the
9593- * number of files selected.
9594+ load_remove_timer (impl);
9595+ load_set_model (impl);
9596+ }
9597+ else if (impl->load_state == LOAD_LOADING)
9598+ {
9599+ /* Nothing */
9600+ }
9601+ else
9602+ {
9603+ /* We can't g_assert_not_reached(), as something other than us may have
9604+ * initiated a folder reload. See #165556.
9605 */
9606- typedef enum {
9607- NOOP, /* Do nothing (don't respond) */
9608- RESPOND, /* Respond immediately */
9609- RESPOND_OR_SWITCH, /* Respond immediately if the selected item is a file; switch to it if it is a folder */
9610- ALL_FILES, /* Respond only if everything selected is a file */
9611- ALL_FOLDERS, /* Respond only if everything selected is a folder */
9612- SAVE_ENTRY, /* Go to the code for handling the save entry */
9613- NOT_REACHED /* Sanity check */
9614- } ActionToTake;
9615- static const ActionToTake what_to_do[4][3] = {
9616- /* 0 selected 1 selected many selected */
9617- /* ACTION_OPEN */ { NOOP, RESPOND_OR_SWITCH, ALL_FILES },
9618- /* ACTION_SAVE */ { SAVE_ENTRY, RESPOND_OR_SWITCH, NOT_REACHED },
9619- /* ACTION_SELECT_FOLDER */ { RESPOND, ALL_FOLDERS, ALL_FOLDERS },
9620- /* ACTION_CREATE_FOLDER */ { SAVE_ENTRY, ALL_FOLDERS, NOT_REACHED }
9621- };
9622-
9623- int num_selected;
9624- gboolean all_files, all_folders;
9625- int k;
9626- ActionToTake action;
9627+ profile_end ("end", NULL);
9628+ return;
9629+ }
9630
9631- file_list:
9632+ g_assert (impl->load_timeout_id == 0);
9633
9634- g_assert (impl->action >= GTK_FILE_CHOOSER_ACTION_OPEN && impl->action <= GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER);
9635+ impl->load_state = LOAD_FINISHED;
9636
9637- if (impl->operation_mode == OPERATION_MODE_SEARCH)
9638- return search_should_respond (impl);
9639+ pending_select_paths_process (impl);
9640+ set_busy_cursor (impl, FALSE);
9641+#ifdef PROFILE_FILE_CHOOSER
9642+ access ("MARK: *** FINISHED LOADING", F_OK);
9643+#endif
9644
9645- if (impl->operation_mode == OPERATION_MODE_RECENT)
9646- return recent_should_respond (impl);
9647+ profile_end ("end", NULL);
9648+}
9649
9650- selection_check (impl, &num_selected, &all_files, &all_folders);
9651+/* Gets rid of the old list model and creates a new one for the current folder */
9652+static gboolean
9653+set_list_model (GtkFileChooserDefault *impl,
9654+ GError **error)
9655+{
9656+ g_assert (impl->current_folder != NULL);
9657
9658- if (num_selected > 2)
9659- k = 2;
9660- else
9661- k = num_selected;
9662+ profile_start ("start", NULL);
9663
9664- action = what_to_do [impl->action] [k];
9665+ load_remove_timer (impl); /* This changes the state to LOAD_EMPTY */
9666
9667- switch (action)
9668- {
9669- case NOOP:
9670- return FALSE;
9671+ if (impl->browse_files_model)
9672+ {
9673+ g_object_unref (impl->browse_files_model);
9674+ impl->browse_files_model = NULL;
9675+ }
9676
9677- case RESPOND:
9678- return TRUE;
9679+ if (impl->sort_model)
9680+ {
9681+ g_object_unref (impl->sort_model);
9682+ impl->sort_model = NULL;
9683+ }
9684
9685- case RESPOND_OR_SWITCH:
9686- g_assert (num_selected == 1);
9687+ set_busy_cursor (impl, TRUE);
9688+ gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view), NULL);
9689
9690- if (all_folders)
9691- {
9692- switch_to_selected_folder (impl);
9693- return FALSE;
9694- }
9695- else if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
9696- return should_respond_after_confirm_overwrite (impl,
9697- get_display_name_from_file_list (impl),
9698- impl->current_folder);
9699- else
9700- return TRUE;
9701+ impl->browse_files_model = _gtk_file_system_model_new (impl->file_system,
9702+ impl->current_folder, 0,
9703+ GTK_FILE_INFO_ALL,
9704+ error);
9705+ if (!impl->browse_files_model)
9706+ {
9707+ set_busy_cursor (impl, FALSE);
9708+ profile_end ("end", NULL);
9709+ return FALSE;
9710+ }
9711
9712- case ALL_FILES:
9713- return all_files;
9714+ load_setup_timer (impl); /* This changes the state to LOAD_PRELOAD */
9715
9716- case ALL_FOLDERS:
9717- return all_folders;
9718+ g_signal_connect (impl->browse_files_model, "finished-loading",
9719+ G_CALLBACK (browse_files_model_finished_loading_cb), impl);
9720
9721- case SAVE_ENTRY:
9722- goto save_entry;
9723+ _gtk_file_system_model_set_show_hidden (impl->browse_files_model, impl->show_hidden);
9724
9725- default:
9726- g_assert_not_reached ();
9727- }
9728- }
9729- else if ((impl->location_entry != NULL) && (current_focus == impl->location_entry))
9730- {
9731- GtkFilePath *path;
9732- gboolean is_well_formed, is_empty, is_file_part_empty;
9733- gboolean is_folder;
9734- gboolean retval;
9735- GtkFileChooserEntry *entry;
9736- GError *error;
9737+ install_list_model_filter (impl);
9738
9739- save_entry:
9740+ profile_end ("end", NULL);
9741
9742- g_assert (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
9743- || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER
9744- || ((impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
9745- || impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
9746- && impl->location_mode == LOCATION_MODE_FILENAME_ENTRY));
9747+ return TRUE;
9748+}
9749
9750- entry = GTK_FILE_CHOOSER_ENTRY (impl->location_entry);
9751- check_save_entry (impl, &path, &is_well_formed, &is_empty, &is_file_part_empty, &is_folder);
9752+struct update_chooser_entry_selected_foreach_closure {
9753+ int num_selected;
9754+ GtkTreeIter first_selected_iter;
9755+};
9756
9757- if (is_empty || !is_well_formed)
9758- return FALSE;
9759+static gint
9760+compare_utf8_filenames (const gchar *a,
9761+ const gchar *b)
9762+{
9763+ gchar *a_folded, *b_folded;
9764+ gint retval;
9765
9766- g_assert (path != NULL);
9767+ a_folded = g_utf8_strdown (a, -1);
9768+ b_folded = g_utf8_strdown (b, -1);
9769
9770- error = NULL;
9771- if (is_folder)
9772- {
9773- if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
9774- impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
9775- {
9776- change_folder_and_display_error (impl, path, TRUE);
9777- retval = FALSE;
9778- }
9779- else if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
9780- impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
9781- {
9782- /* The folder already exists, so we do not need to create it.
9783- * Just respond to terminate the dialog.
9784- */
9785- retval = TRUE;
9786- }
9787- else
9788- {
9789- g_assert_not_reached ();
9790- retval = FALSE;
9791- }
9792- }
9793- else
9794- {
9795- struct FileExistsData *data;
9796+ retval = strcmp (a_folded, b_folded);
9797
9798- /* We need to check whether path exists and is not a folder */
9799+ g_free (a_folded);
9800+ g_free (b_folded);
9801
9802- data = g_new0 (struct FileExistsData, 1);
9803- data->impl = g_object_ref (impl);
9804- data->path = gtk_file_path_copy (path);
9805- data->parent_path = gtk_file_path_copy (_gtk_file_chooser_entry_get_current_folder (entry));
9806+ return retval;
9807+}
9808
9809- if (impl->file_exists_get_info_handle)
9810- gtk_file_system_cancel_operation (impl->file_exists_get_info_handle);
9811+static void
9812+update_chooser_entry_selected_foreach (GtkTreeModel *model,
9813+ GtkTreePath *path,
9814+ GtkTreeIter *iter,
9815+ gpointer data)
9816+{
9817+ struct update_chooser_entry_selected_foreach_closure *closure;
9818
9819- impl->file_exists_get_info_handle =
9820- gtk_file_system_get_info (impl->file_system, path,
9821- GTK_FILE_INFO_IS_FOLDER,
9822- file_exists_get_info_cb,
9823- data);
9824+ closure = data;
9825+ closure->num_selected++;
9826
9827- set_busy_cursor (impl, TRUE);
9828- retval = FALSE;
9829+ if (closure->num_selected == 1)
9830+ closure->first_selected_iter = *iter;
9831+}
9832
9833- if (error != NULL)
9834- g_error_free (error);
9835- }
9836+static void
9837+update_chooser_entry (GtkFileChooserDefault *impl)
9838+{
9839+ GtkTreeSelection *selection;
9840+ struct update_chooser_entry_selected_foreach_closure closure;
9841+ const char *file_part;
9842
9843- gtk_file_path_free (path);
9844- return retval;
9845- }
9846- else if (impl->toplevel_last_focus_widget == impl->browse_shortcuts_tree_view)
9847- {
9848- /* The focus is on a dialog's action area button, *and* the widget that
9849- * was focused immediately before it is the shortcuts list. Switch to the
9850- * selected shortcut and tell the caller not to respond.
9851- */
9852- GtkTreeIter iter;
9853+ if (!(impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
9854+ || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER
9855+ || impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
9856+ || impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER))
9857+ return;
9858
9859- if (shortcuts_get_selected (impl, &iter))
9860- {
9861- shortcuts_activate_iter (impl, &iter);
9862-
9863- focus_browse_tree_view_if_possible (impl);
9864- }
9865- else
9866- goto file_list;
9867+ g_assert (impl->location_entry != NULL);
9868
9869- return FALSE;
9870- }
9871- else if (impl->toplevel_last_focus_widget == impl->browse_files_tree_view)
9872- {
9873- /* The focus is on a dialog's action area button, *and* the widget that
9874- * was focused immediately before it is the file list.
9875- */
9876- goto file_list;
9877- }
9878- else if (impl->operation_mode == OPERATION_MODE_SEARCH && impl->toplevel_last_focus_widget == impl->search_entry)
9879+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
9880+ closure.num_selected = 0;
9881+ gtk_tree_selection_selected_foreach (selection, update_chooser_entry_selected_foreach, &closure);
9882+
9883+ file_part = NULL;
9884+
9885+ if (closure.num_selected == 0)
9886 {
9887- search_entry_activate_cb (GTK_ENTRY (impl->search_entry), impl);
9888- return FALSE;
9889+ goto maybe_clear_entry;
9890 }
9891- else if (impl->location_entry && impl->toplevel_last_focus_widget == impl->location_entry)
9892+ else if (closure.num_selected == 1)
9893 {
9894- /* The focus is on a dialog's action area button, *and* the widget that
9895- * was focused immediately before it is the location entry.
9896- */
9897- goto save_entry;
9898- }
9899- else
9900- /* The focus is on a dialog's action area button or something else */
9901- if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
9902- || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
9903- goto save_entry;
9904- else
9905- goto file_list;
9906-
9907- g_assert_not_reached ();
9908- return FALSE;
9909-}
9910+ GtkTreeIter child_iter;
9911+ const GtkFileInfo *info;
9912+ gboolean change_entry;
9913
9914-/* Implementation for GtkFileChooserEmbed::initial_focus() */
9915-static void
9916-gtk_file_chooser_default_initial_focus (GtkFileChooserEmbed *chooser_embed)
9917-{
9918- GtkFileChooserDefault *impl;
9919- GtkWidget *widget;
9920+ gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model,
9921+ &child_iter,
9922+ &closure.first_selected_iter);
9923
9924- impl = GTK_FILE_CHOOSER_DEFAULT (chooser_embed);
9925+ info = _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
9926
9927- if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
9928- impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
9929- {
9930- if (impl->location_mode == LOCATION_MODE_PATH_BAR)
9931- widget = impl->browse_files_tree_view;
9932+ /* If the cursor moved to the row of the newly created folder,
9933+ * retrieving info will return NULL.
9934+ */
9935+ if (!info)
9936+ return;
9937+
9938+ g_free (impl->browse_files_last_selected_name);
9939+ impl->browse_files_last_selected_name = g_strdup (gtk_file_info_get_display_name (info));
9940+
9941+ if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
9942+ || impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
9943+ change_entry = !gtk_file_info_get_is_folder (info); /* We don't want the name to change when clicking on a folder... */
9944 else
9945- widget = impl->location_entry;
9946+ change_entry = TRUE; /* ... unless we are in one of the folder modes */
9947+
9948+ if (change_entry)
9949+ _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), impl->browse_files_last_selected_name);
9950+
9951+ return;
9952 }
9953- else if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE ||
9954- impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
9955- widget = impl->location_entry;
9956 else
9957 {
9958- g_assert_not_reached ();
9959- widget = NULL;
9960- }
9961+ g_assert (!(impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
9962+ || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER));
9963
9964- g_assert (widget != NULL);
9965- gtk_widget_grab_focus (widget);
9966-}
9967+ /* Multiple selection, so just clear the entry. */
9968
9969-/* Callback used from gtk_tree_selection_selected_foreach(); gets the selected GtkFilePaths */
9970-static void
9971-search_selected_foreach_get_path_cb (GtkTreeModel *model,
9972- GtkTreePath *path,
9973- GtkTreeIter *iter,
9974- gpointer data)
9975-{
9976- GSList **list;
9977- const GtkFilePath *file_path;
9978- GtkFilePath *file_path_copy;
9979+ g_free (impl->browse_files_last_selected_name);
9980+ impl->browse_files_last_selected_name = NULL;
9981
9982- list = data;
9983+ _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), "");
9984+ return;
9985+ }
9986
9987- gtk_tree_model_get (model, iter, SEARCH_MODEL_COL_PATH, &file_path, -1);
9988- file_path_copy = gtk_file_path_copy (file_path);
9989- *list = g_slist_prepend (*list, file_path_copy);
9990-}
9991+ maybe_clear_entry:
9992
9993-/* Constructs a list of the selected paths in search mode */
9994-static GSList *
9995-search_get_selected_paths (GtkFileChooserDefault *impl)
9996-{
9997- GSList *result;
9998- GtkTreeSelection *selection;
9999+ if (impl->browse_files_last_selected_name)
10000+ {
10001+ const char *entry_text;
10002+ int len;
10003+ gboolean clear_entry;
10004
10005- result = NULL;
10006+ entry_text = gtk_entry_get_text (GTK_ENTRY (impl->location_entry));
10007+ len = strlen (entry_text);
10008+ if (len != 0)
10009+ {
10010+ /* The file chooser entry may have appended a "/" to its text. So
10011+ * take it out, and compare the result to the old selection.
10012+ */
10013+ if (entry_text[len - 1] == G_DIR_SEPARATOR)
10014+ {
10015+ char *tmp;
10016
10017- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
10018- gtk_tree_selection_selected_foreach (selection, search_selected_foreach_get_path_cb, &result);
10019- result = g_slist_reverse (result);
10020+ tmp = g_strndup (entry_text, len - 1);
10021+ clear_entry = (compare_utf8_filenames (impl->browse_files_last_selected_name, tmp) == 0);
10022+ g_free (tmp);
10023+ }
10024+ else
10025+ clear_entry = (compare_utf8_filenames (impl->browse_files_last_selected_name, entry_text) == 0);
10026+ }
10027+ else
10028+ clear_entry = FALSE;
10029
10030- return result;
10031+ if (clear_entry)
10032+ _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), "");
10033+ }
10034 }
10035
10036-/* Called from ::should_respond(). We return whether there are selected files
10037- * in the search list.
10038- */
10039 static gboolean
10040-search_should_respond (GtkFileChooserDefault *impl)
10041+gtk_file_chooser_default_set_current_folder (GtkFileChooser *chooser,
10042+ const GtkFilePath *path,
10043+ GError **error)
10044 {
10045- GtkTreeSelection *selection;
10046-
10047- g_assert (impl->operation_mode == OPERATION_MODE_SEARCH);
10048-
10049- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
10050- return (gtk_tree_selection_count_selected_rows (selection) != 0);
10051+ return gtk_file_chooser_default_update_current_folder (chooser, path, FALSE, FALSE, error);
10052 }
10053
10054-struct SearchHitInsertRequest
10055+
10056+struct UpdateCurrentFolderData
10057 {
10058 GtkFileChooserDefault *impl;
10059 GtkFilePath *path;
10060- GtkTreeRowReference *row_ref;
10061+ gboolean keep_trail;
10062+ gboolean clear_entry;
10063+ GtkFilePath *original_path;
10064+ GError *original_error;
10065 };
10066
10067 static void
10068-search_hit_get_info_cb (GtkFileSystemHandle *handle,
10069- const GtkFileInfo *info,
10070- const GError *error,
10071- gpointer data)
10072+update_current_folder_get_info_cb (GtkFileSystemHandle *handle,
10073+ const GtkFileInfo *info,
10074+ const GError *error,
10075+ gpointer user_data)
10076 {
10077 gboolean cancelled = handle->cancelled;
10078- GdkPixbuf *pixbuf = NULL;
10079- GtkTreePath *path;
10080- GtkTreeIter iter;
10081- GtkFileSystemHandle *model_handle;
10082- gboolean is_folder = FALSE;
10083- char *mime_type;
10084- char *display_name;
10085- struct SearchHitInsertRequest *request = data;
10086-
10087- if (!request->impl->search_model)
10088- goto out;
10089+ struct UpdateCurrentFolderData *data = user_data;
10090+ GtkFileChooserDefault *impl = data->impl;
10091
10092- path = gtk_tree_row_reference_get_path (request->row_ref);
10093- if (!path)
10094+ if (handle != impl->update_current_folder_handle)
10095 goto out;
10096
10097- gtk_tree_model_get_iter (GTK_TREE_MODEL (request->impl->search_model),
10098- &iter, path);
10099- gtk_tree_path_free (path);
10100-
10101- gtk_tree_model_get (GTK_TREE_MODEL (request->impl->search_model), &iter,
10102- SEARCH_MODEL_COL_HANDLE, &model_handle,
10103- -1);
10104- if (handle != model_handle)
10105- goto out;
10106+ impl->update_current_folder_handle = NULL;
10107+ impl->reload_state = RELOAD_EMPTY;
10108
10109- /* set the handle to NULL in the model */
10110- gtk_list_store_set (request->impl->search_model, &iter,
10111- SEARCH_MODEL_COL_HANDLE, NULL,
10112- -1);
10113+ set_busy_cursor (impl, FALSE);
10114
10115 if (cancelled)
10116 goto out;
10117
10118- if (!info)
10119+ if (error)
10120 {
10121- gtk_list_store_remove (request->impl->search_model, &iter);
10122- goto out;
10123- }
10124+ GtkFilePath *parent_path;
10125
10126- display_name = g_strdup (gtk_file_info_get_display_name (info));
10127- mime_type = g_strdup (gtk_file_info_get_mime_type (info));
10128- is_folder = gtk_file_info_get_is_folder (info);
10129- pixbuf = gtk_file_info_render_icon (info, GTK_WIDGET (request->impl),
10130- request->impl->icon_size, NULL);
10131+ if (!data->original_path)
10132+ {
10133+ data->original_path = gtk_file_path_copy (data->path);
10134+ data->original_error = g_error_copy (error);
10135+ }
10136
10137- gtk_list_store_set (request->impl->search_model, &iter,
10138- SEARCH_MODEL_COL_PIXBUF, pixbuf,
10139- SEARCH_MODEL_COL_DISPLAY_NAME, display_name,
10140- SEARCH_MODEL_COL_MIME_TYPE, mime_type,
10141- SEARCH_MODEL_COL_IS_FOLDER, is_folder,
10142- -1);
10143+ /* get parent path and try to change the folder to that */
10144+ if (gtk_file_system_get_parent (impl->file_system, data->path, &parent_path, NULL) &&
10145+ parent_path)
10146+ {
10147+ gtk_file_path_free (data->path);
10148+ data->path = parent_path;
10149
10150- if (pixbuf)
10151- g_object_unref (pixbuf);
10152+ g_object_unref (handle);
10153
10154-out:
10155- g_object_unref (request->impl);
10156- gtk_file_path_free (request->path);
10157- gtk_tree_row_reference_free (request->row_ref);
10158- g_free (request);
10159+ /* restart the update current folder operation */
10160+ impl->reload_state = RELOAD_HAS_FOLDER;
10161
10162- g_object_unref (handle);
10163-}
10164+ impl->update_current_folder_handle =
10165+ gtk_file_system_get_info (impl->file_system, data->path,
10166+ GTK_FILE_INFO_IS_FOLDER,
10167+ update_current_folder_get_info_cb,
10168+ data);
10169
10170-/* Adds one hit from the search engine to the search_model */
10171-static void
10172-search_add_hit (GtkFileChooserDefault *impl,
10173- gchar *uri)
10174-{
10175- GtkFilePath *path;
10176- char *filename;
10177- char *tmp;
10178- char *collation_key;
10179- struct stat statbuf;
10180- struct stat *statbuf_copy;
10181- GtkTreeIter iter;
10182- GtkTreePath *p;
10183- GtkFileSystemHandle *handle;
10184- struct SearchHitInsertRequest *request;
10185+ set_busy_cursor (impl, TRUE);
10186
10187- path = gtk_file_system_uri_to_path (impl->file_system, uri);
10188- if (!path)
10189- return;
10190+ return;
10191+ }
10192+ else
10193+ {
10194+ /* error and bail out */
10195+ error_changing_folder_dialog (impl, data->original_path, data->original_error);
10196
10197- filename = gtk_file_system_path_to_filename (impl->file_system, path);
10198- if (!filename)
10199- {
10200- gtk_file_path_free (path);
10201- return;
10202+ gtk_file_path_free (data->original_path);
10203+
10204+ goto out;
10205+ }
10206 }
10207
10208- if (stat (filename, &statbuf) != 0)
10209+ if (data->original_path)
10210 {
10211- gtk_file_path_free (path);
10212- g_free (filename);
10213- return;
10214+ error_changing_folder_dialog (impl, data->original_path, data->original_error);
10215+
10216+ gtk_file_path_free (data->original_path);
10217 }
10218
10219- statbuf_copy = g_new (struct stat, 1);
10220- *statbuf_copy = statbuf;
10221+ if (!gtk_file_info_get_is_folder (info))
10222+ goto out;
10223+
10224+ if (impl->current_folder != data->path)
10225+ {
10226+ if (impl->current_folder)
10227+ gtk_file_path_free (impl->current_folder);
10228
10229- tmp = g_filename_display_name (filename);
10230- collation_key = g_utf8_collate_key_for_filename (tmp, -1);
10231- g_free (tmp);
10232-
10233- request = g_new0 (struct SearchHitInsertRequest, 1);
10234- request->impl = g_object_ref (impl);
10235- request->path = gtk_file_path_copy (path);
10236+ impl->current_folder = gtk_file_path_copy (data->path);
10237
10238- gtk_list_store_append (impl->search_model, &iter);
10239- p = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->search_model), &iter);
10240-
10241- request->row_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (impl->search_model), p);
10242- gtk_tree_path_free (p);
10243+ impl->reload_state = RELOAD_HAS_FOLDER;
10244+ }
10245
10246- handle = gtk_file_system_get_info (impl->file_system, path,
10247- GTK_FILE_INFO_IS_FOLDER | GTK_FILE_INFO_ICON | GTK_FILE_INFO_MIME_TYPE | GTK_FILE_INFO_DISPLAY_NAME,
10248- search_hit_get_info_cb,
10249- request);
10250-
10251- gtk_list_store_set (impl->search_model, &iter,
10252- SEARCH_MODEL_COL_PATH, path,
10253- SEARCH_MODEL_COL_COLLATION_KEY, collation_key,
10254- SEARCH_MODEL_COL_STAT, statbuf_copy,
10255- SEARCH_MODEL_COL_HANDLE, handle,
10256- -1);
10257-}
10258-
10259-/* Callback used from GtkSearchEngine when we get new hits */
10260-static void
10261-search_engine_hits_added_cb (GtkSearchEngine *engine,
10262- GList *hits,
10263- gpointer data)
10264-{
10265- GtkFileChooserDefault *impl;
10266- GList *l;
10267-
10268- impl = GTK_FILE_CHOOSER_DEFAULT (data);
10269+ /* Set the folder on the save entry */
10270
10271- for (l = hits; l; l = l->next)
10272- search_add_hit (impl, (gchar*)l->data);
10273-}
10274+ if (impl->location_entry)
10275+ {
10276+ _gtk_file_chooser_entry_set_base_folder (GTK_FILE_CHOOSER_ENTRY (impl->location_entry),
10277+ impl->current_folder);
10278
10279-/* Callback used from GtkSearchEngine when the query is done running */
10280-static void
10281-search_engine_finished_cb (GtkSearchEngine *engine,
10282- gpointer data)
10283-{
10284- GtkFileChooserDefault *impl;
10285-
10286- impl = GTK_FILE_CHOOSER_DEFAULT (data);
10287-
10288-#if 0
10289- /* EB: setting the model here will avoid loads of row events,
10290- * but it'll make the search look like blocked.
10291- */
10292- gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view),
10293- GTK_TREE_MODEL (impl->search_model_filter));
10294-#endif
10295+ if (data->clear_entry)
10296+ _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), "");
10297+ }
10298
10299- /* FMQ: if search was empty, say that we got no hits */
10300- set_busy_cursor (impl, FALSE);
10301-}
10302+ /* Create a new list model. This is slightly evil; we store the result value
10303+ * but perform more actions rather than returning immediately even if it
10304+ * generates an error.
10305+ */
10306+ set_list_model (impl, NULL);
10307
10308-/* Displays a generic error when we cannot create a GtkSearchEngine.
10309- * It would be better if _gtk_search_engine_new() gave us a GError
10310- * with a better message, but it doesn't do that right now.
10311- */
10312-static void
10313-search_error_could_not_create_client (GtkFileChooserDefault *impl)
10314-{
10315- error_message (impl,
10316- _("Could not start the search process"),
10317- _("The program was not able to create a connection to the indexer "
10318- "daemon. Please make sure it is running."));
10319-}
10320+ /* Refresh controls */
10321
10322-static void
10323-search_engine_error_cb (GtkSearchEngine *engine,
10324- const gchar *message,
10325- gpointer data)
10326-{
10327- GtkFileChooserDefault *impl;
10328-
10329- impl = GTK_FILE_CHOOSER_DEFAULT (data);
10330+ g_signal_emit_by_name (impl, "current-folder-changed", 0);
10331+ g_signal_emit_by_name (impl, "selection-changed", 0);
10332
10333- search_stop_searching (impl, TRUE);
10334- error_message (impl, _("Could not send the search request"), message);
10335+out:
10336+ gtk_file_path_free (data->path);
10337+ g_free (data);
10338
10339- set_busy_cursor (impl, FALSE);
10340+ g_object_unref (handle);
10341 }
10342
10343-/* Frees the data in the search_model */
10344-static void
10345-search_clear_model (GtkFileChooserDefault *impl,
10346- gboolean remove_from_treeview)
10347+static gboolean
10348+gtk_file_chooser_default_update_current_folder (GtkFileChooser *chooser,
10349+ const GtkFilePath *path,
10350+ gboolean keep_trail,
10351+ gboolean clear_entry,
10352+ GError **error)
10353 {
10354- GtkTreeModel *model;
10355- GtkTreeIter iter;
10356-
10357- if (!impl->search_model)
10358- return;
10359-
10360- model = GTK_TREE_MODEL (impl->search_model);
10361-
10362- if (gtk_tree_model_get_iter_first (model, &iter))
10363- do
10364- {
10365- GtkFilePath *path;
10366- gchar *display_name;
10367- gchar *collation_key;
10368- struct stat *statbuf;
10369- GtkFileSystemHandle *handle;
10370-
10371- gtk_tree_model_get (model, &iter,
10372- SEARCH_MODEL_COL_PATH, &path,
10373- SEARCH_MODEL_COL_DISPLAY_NAME, &display_name,
10374- SEARCH_MODEL_COL_COLLATION_KEY, &collation_key,
10375- SEARCH_MODEL_COL_STAT, &statbuf,
10376- SEARCH_MODEL_COL_HANDLE, &handle,
10377- -1);
10378-
10379- if (handle)
10380- gtk_file_system_cancel_operation (handle);
10381-
10382- gtk_file_path_free (path);
10383- g_free (display_name);
10384- g_free (collation_key);
10385- g_free (statbuf);
10386- }
10387- while (gtk_tree_model_iter_next (model, &iter));
10388+ GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
10389+ struct UpdateCurrentFolderData *data;
10390
10391- g_object_unref (impl->search_model);
10392- impl->search_model = NULL;
10393-
10394- g_object_unref (impl->search_model_filter);
10395- impl->search_model_filter = NULL;
10396-
10397- g_object_unref (impl->search_model_sort);
10398- impl->search_model_sort = NULL;
10399+ profile_start ("start", (char *) path);
10400
10401- if (remove_from_treeview)
10402- gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view), NULL);
10403-}
10404+ g_assert (path != NULL);
10405
10406-/* Stops any ongoing searches; does not touch the search_model */
10407-static void
10408-search_stop_searching (GtkFileChooserDefault *impl,
10409- gboolean remove_query)
10410-{
10411- if (remove_query && impl->search_query)
10412- {
10413- g_object_unref (impl->search_query);
10414- impl->search_query = NULL;
10415- }
10416-
10417- if (impl->search_engine)
10418+ if (impl->local_only &&
10419+ !gtk_file_system_path_is_local (impl->file_system, path))
10420 {
10421- _gtk_search_engine_stop (impl->search_engine);
10422-
10423- g_object_unref (impl->search_engine);
10424- impl->search_engine = NULL;
10425- }
10426-}
10427-
10428-/* Stops any pending searches, clears the file list, and switches back to OPERATION_MODE_BROWSE */
10429-static void
10430-search_switch_to_browse_mode (GtkFileChooserDefault *impl)
10431-{
10432- g_assert (impl->operation_mode != OPERATION_MODE_BROWSE);
10433+ g_set_error (error,
10434+ GTK_FILE_CHOOSER_ERROR,
10435+ GTK_FILE_CHOOSER_ERROR_BAD_FILENAME,
10436+ _("Cannot change to folder because it is not local"));
10437
10438- search_stop_searching (impl, FALSE);
10439- search_clear_model (impl, TRUE);
10440+ profile_end ("end - not local", (char *) path);
10441+ return FALSE;
10442+ }
10443
10444- gtk_widget_destroy (impl->search_hbox);
10445- impl->search_hbox = NULL;
10446- impl->search_entry = NULL;
10447+ if (impl->update_current_folder_handle)
10448+ gtk_file_system_cancel_operation (impl->update_current_folder_handle);
10449
10450- gtk_widget_show (impl->browse_path_bar);
10451- gtk_widget_show (impl->browse_new_folder_button);
10452+ /* Test validity of path here. */
10453+ data = g_new0 (struct UpdateCurrentFolderData, 1);
10454+ data->impl = impl;
10455+ data->path = gtk_file_path_copy (path);
10456+ data->keep_trail = keep_trail;
10457+ data->clear_entry = clear_entry;
10458
10459- if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
10460- impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
10461- {
10462- gtk_widget_show (impl->location_button);
10463+ impl->reload_state = RELOAD_HAS_FOLDER;
10464
10465- if (impl->location_mode == LOCATION_MODE_FILENAME_ENTRY)
10466- gtk_widget_show (impl->location_entry_box);
10467- }
10468+ impl->update_current_folder_handle =
10469+ gtk_file_system_get_info (impl->file_system, path, GTK_FILE_INFO_IS_FOLDER,
10470+ update_current_folder_get_info_cb,
10471+ data);
10472
10473- impl->operation_mode = OPERATION_MODE_BROWSE;
10474+ set_busy_cursor (impl, TRUE);
10475
10476- file_list_set_sort_column_ids (impl);
10477+ profile_end ("end", NULL);
10478+ return TRUE;
10479 }
10480
10481-/* Sort callback from the path column */
10482-static gint
10483-search_column_path_sort_func (GtkTreeModel *model,
10484- GtkTreeIter *a,
10485- GtkTreeIter *b,
10486- gpointer user_data)
10487+static GtkFilePath *
10488+gtk_file_chooser_default_get_current_folder (GtkFileChooser *chooser)
10489 {
10490- GtkFileChooserDefault *impl = user_data;
10491- GtkTreeIter child_a, child_b;
10492- const char *collation_key_a, *collation_key_b;
10493- gboolean is_folder_a, is_folder_b;
10494+ GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
10495
10496- gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), &child_a, a);
10497- gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), &child_b, b);
10498+ if (impl->reload_state == RELOAD_EMPTY)
10499+ {
10500+ char *current_working_dir;
10501+ GtkFilePath *path;
10502
10503- gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &child_a,
10504- SEARCH_MODEL_COL_IS_FOLDER, &is_folder_a,
10505- SEARCH_MODEL_COL_COLLATION_KEY, &collation_key_a,
10506- -1);
10507- gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &child_b,
10508- SEARCH_MODEL_COL_IS_FOLDER, &is_folder_b,
10509- SEARCH_MODEL_COL_COLLATION_KEY, &collation_key_b,
10510- -1);
10511+ /* We are unmapped, or we had an error while loading the last folder. We'll return
10512+ * the $cwd since once we get (re)mapped, we'll load $cwd anyway unless the caller
10513+ * explicitly calls set_current_folder() on us.
10514+ */
10515+ current_working_dir = g_get_current_dir ();
10516+ path = gtk_file_system_filename_to_path (impl->file_system, current_working_dir);
10517+ g_free (current_working_dir);
10518+ return path;
10519+ }
10520
10521- if (!collation_key_a)
10522- return 1;
10523+ return gtk_file_path_copy (impl->current_folder);
10524+}
10525
10526- if (!collation_key_b)
10527- return -1;
10528+static void
10529+gtk_file_chooser_default_set_current_name (GtkFileChooser *chooser,
10530+ const gchar *name)
10531+{
10532+ GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
10533
10534- /* always show folders first */
10535- if (is_folder_a != is_folder_b)
10536- return is_folder_a ? 1 : -1;
10537+ g_return_if_fail (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
10538+ || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER);
10539
10540- return strcmp (collation_key_a, collation_key_b);
10541+ pending_select_paths_free (impl);
10542+ _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), name);
10543 }
10544
10545-/* Sort callback from the modification time column */
10546-static gint
10547-search_column_mtime_sort_func (GtkTreeModel *model,
10548- GtkTreeIter *a,
10549- GtkTreeIter *b,
10550- gpointer user_data)
10551+static void
10552+select_func (GtkFileSystemModel *model,
10553+ GtkTreePath *path,
10554+ GtkTreeIter *iter,
10555+ gpointer user_data)
10556 {
10557 GtkFileChooserDefault *impl = user_data;
10558- GtkTreeIter child_a, child_b;
10559- const struct stat *statbuf_a, *statbuf_b;
10560- gboolean is_folder_a, is_folder_b;
10561-
10562- gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), &child_a, a);
10563- gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), &child_b, b);
10564-
10565- /* Note that although we store a whole struct stat in the model, we only
10566- * compare the mtime here. If we add another column relative to a struct stat
10567- * (e.g. a file size column), we'll want another sort callback similar to this
10568- * one as well.
10569- */
10570- gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &child_a,
10571- SEARCH_MODEL_COL_IS_FOLDER, &is_folder_a,
10572- SEARCH_MODEL_COL_STAT, &statbuf_a,
10573- -1);
10574- gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &child_b,
10575- SEARCH_MODEL_COL_IS_FOLDER, &is_folder_b,
10576- SEARCH_MODEL_COL_STAT, &statbuf_b,
10577- -1);
10578-
10579- if (!statbuf_a)
10580- return 1;
10581-
10582- if (!statbuf_b)
10583- return -1;
10584+ GtkTreeSelection *selection;
10585+ GtkTreeIter sorted_iter;
10586
10587- if (is_folder_a != is_folder_b)
10588- return is_folder_a ? 1 : -1;
10589+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
10590
10591- if (statbuf_a->st_mtime < statbuf_b->st_mtime)
10592- return -1;
10593- else if (statbuf_a->st_mtime > statbuf_b->st_mtime)
10594- return 1;
10595- else
10596- return 0;
10597+ gtk_tree_model_sort_convert_child_iter_to_iter (impl->sort_model, &sorted_iter, iter);
10598+ gtk_tree_selection_select_iter (selection, &sorted_iter);
10599 }
10600
10601 static gboolean
10602-search_get_is_filtered (GtkFileChooserDefault *impl,
10603- const GtkFilePath *path,
10604- const gchar *display_name,
10605- const gchar *mime_type)
10606+gtk_file_chooser_default_select_path (GtkFileChooser *chooser,
10607+ const GtkFilePath *path,
10608+ GError **error)
10609 {
10610- GtkFileFilterInfo filter_info;
10611- GtkFileFilterFlags needed;
10612- gboolean result;
10613+ GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
10614+ GtkFilePath *parent_path;
10615+ gboolean same_path;
10616
10617- if (!impl->current_filter)
10618+ if (!gtk_file_system_get_parent (impl->file_system, path, &parent_path, error))
10619 return FALSE;
10620
10621- filter_info.contains = GTK_FILE_FILTER_DISPLAY_NAME | GTK_FILE_FILTER_MIME_TYPE;
10622- needed = gtk_file_filter_get_needed (impl->current_filter);
10623-
10624- filter_info.display_name = display_name;
10625- filter_info.mime_type = mime_type;
10626+ if (!parent_path)
10627+ return _gtk_file_chooser_set_current_folder_path (chooser, path, error);
10628
10629- if (needed & GTK_FILE_FILTER_FILENAME)
10630+ if (impl->load_state == LOAD_EMPTY)
10631+ same_path = FALSE;
10632+ else
10633 {
10634- filter_info.filename = gtk_file_system_path_to_filename (impl->file_system, path);
10635- if (filter_info.filename)
10636- filter_info.contains |= GTK_FILE_FILTER_FILENAME;
10637+ g_assert (impl->current_folder != NULL);
10638+
10639+ same_path = gtk_file_path_compare (parent_path, impl->current_folder) == 0;
10640 }
10641- else
10642- filter_info.filename = NULL;
10643
10644- if (needed & GTK_FILE_FILTER_URI)
10645+ if (same_path && impl->load_state == LOAD_FINISHED)
10646 {
10647- filter_info.uri = gtk_file_system_path_to_uri (impl->file_system, path);
10648- if (filter_info.uri)
10649- filter_info.contains |= GTK_FILE_FILTER_URI;
10650+ gboolean result;
10651+ GSList paths;
10652+
10653+ paths.data = (gpointer) path;
10654+ paths.next = NULL;
10655+
10656+ result = show_and_select_paths (impl, parent_path, &paths, error);
10657+ gtk_file_path_free (parent_path);
10658+ return result;
10659 }
10660- else
10661- filter_info.uri = NULL;
10662
10663- result = gtk_file_filter_filter (impl->current_filter, &filter_info);
10664+ pending_select_paths_add (impl, path);
10665
10666- if (filter_info.filename)
10667- g_free ((gchar *) filter_info.filename);
10668- if (filter_info.uri)
10669- g_free ((gchar *) filter_info.uri);
10670+ if (!same_path)
10671+ {
10672+ gboolean result;
10673
10674- return !result;
10675+ result = _gtk_file_chooser_set_current_folder_path (chooser, parent_path, error);
10676+ gtk_file_path_free (parent_path);
10677+ return result;
10678+ }
10679
10680+ gtk_file_path_free (parent_path);
10681+ return TRUE;
10682 }
10683
10684-/* Visibility function for the recent filter model */
10685-static gboolean
10686-search_model_visible_func (GtkTreeModel *model,
10687- GtkTreeIter *iter,
10688- gpointer user_data)
10689+static void
10690+unselect_func (GtkFileSystemModel *model,
10691+ GtkTreePath *path,
10692+ GtkTreeIter *iter,
10693+ gpointer user_data)
10694 {
10695 GtkFileChooserDefault *impl = user_data;
10696- GtkFilePath *file_path;
10697- gchar *display_name, *mime_type;
10698- gboolean is_folder;
10699-
10700- if (!impl->current_filter)
10701- return TRUE;
10702+ GtkTreeView *tree_view = GTK_TREE_VIEW (impl->browse_files_tree_view);
10703+ GtkTreePath *sorted_path;
10704
10705- gtk_tree_model_get (model, iter,
10706- SEARCH_MODEL_COL_PATH, &file_path,
10707- SEARCH_MODEL_COL_IS_FOLDER, &is_folder,
10708- SEARCH_MODEL_COL_DISPLAY_NAME, &display_name,
10709- SEARCH_MODEL_COL_MIME_TYPE, &mime_type,
10710- -1);
10711+ sorted_path = gtk_tree_model_sort_convert_child_path_to_path (impl->sort_model,
10712+ path);
10713+ gtk_tree_selection_unselect_path (gtk_tree_view_get_selection (tree_view),
10714+ sorted_path);
10715+ gtk_tree_path_free (sorted_path);
10716+}
10717
10718- if (!display_name)
10719- return TRUE;
10720+static void
10721+gtk_file_chooser_default_unselect_path (GtkFileChooser *chooser,
10722+ const GtkFilePath *path)
10723+{
10724+ GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
10725
10726- if (is_folder)
10727- return TRUE;
10728+ if (!impl->browse_files_model)
10729+ return;
10730
10731- return !search_get_is_filtered (impl, file_path, display_name, mime_type);
10732+ _gtk_file_system_model_path_do (impl->browse_files_model, path,
10733+ unselect_func, impl);
10734 }
10735
10736-/* Creates the search_model and puts it in the tree view */
10737-static void
10738-search_setup_model (GtkFileChooserDefault *impl)
10739+static gboolean
10740+maybe_select (GtkTreeModel *model,
10741+ GtkTreePath *path,
10742+ GtkTreeIter *iter,
10743+ gpointer data)
10744 {
10745- g_assert (impl->search_model == NULL);
10746- g_assert (impl->search_model_filter == NULL);
10747- g_assert (impl->search_model_sort == NULL);
10748-
10749- /* We store these columns in the search model:
10750- *
10751- * SEARCH_MODEL_COL_PATH - a GtkFilePath for the hit's URI, stored as a
10752- * pointer not as a GTK_TYPE_FILE_PATH
10753- * SEARCH_MODEL_COL_DISPLAY_NAME - a string with the display name, stored
10754- * as a pointer not as a G_TYPE_STRING
10755- * SEARCH_MODEL_COL_COLLATION_KEY - collation key for the filename, stored
10756- * as a pointer not as a G_TYPE_STRING
10757- * SEARCH_MODEL_COL_STAT - pointer to a struct stat
10758- * SEARCH_MODEL_COL_HANDLE - handle used when getting the hit's info
10759- * SEARCH_MODEL_COL_PIXBUF - GdkPixbuf for the hit's icon
10760- * SEARCH_MODEL_COL_MIME_TYPE - a string with the hit's MIME type
10761- * SEARCH_MODEL_COL_IS_FOLDER - a boolean flag for folders
10762- *
10763- * Keep this in sync with the enumeration defined near the beginning
10764- * of this file.
10765- */
10766- impl->search_model = gtk_list_store_new (SEARCH_MODEL_COL_NUM_COLUMNS,
10767- G_TYPE_POINTER,
10768- G_TYPE_POINTER,
10769- G_TYPE_POINTER,
10770- G_TYPE_POINTER,
10771- G_TYPE_POINTER,
10772- GDK_TYPE_PIXBUF,
10773- G_TYPE_POINTER,
10774- G_TYPE_BOOLEAN);
10775+ GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (data);
10776+ GtkTreeSelection *selection;
10777+ const GtkFileInfo *info;
10778+ gboolean is_folder;
10779
10780- impl->search_model_filter =
10781- GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (GTK_TREE_MODEL (impl->search_model), NULL));
10782- gtk_tree_model_filter_set_visible_func (impl->search_model_filter,
10783- search_model_visible_func,
10784- impl, NULL);
10785-
10786- impl->search_model_sort =
10787- GTK_TREE_MODEL_SORT (search_model_sort_new (impl, GTK_TREE_MODEL (impl->search_model_filter)));
10788- gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->search_model_sort),
10789- SEARCH_MODEL_COL_PATH,
10790- search_column_path_sort_func,
10791- impl, NULL);
10792- gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->search_model_sort),
10793- SEARCH_MODEL_COL_STAT,
10794- search_column_mtime_sort_func,
10795- impl, NULL);
10796- gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (impl->search_model_sort),
10797- SEARCH_MODEL_COL_STAT,
10798- GTK_SORT_DESCENDING);
10799-
10800- /* EB: setting the model here will make the hits list update feel
10801- * more "alive" than setting the model at the end of the search
10802- * run
10803- */
10804- gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view),
10805- GTK_TREE_MODEL (impl->search_model_sort));
10806+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
10807+
10808+ info = get_list_file_info (impl, iter);
10809+ is_folder = gtk_file_info_get_is_folder (info);
10810+
10811+ if ((is_folder && impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER) ||
10812+ (!is_folder && impl->action == GTK_FILE_CHOOSER_ACTION_OPEN))
10813+ gtk_tree_selection_select_iter (selection, iter);
10814+ else
10815+ gtk_tree_selection_unselect_iter (selection, iter);
10816+
10817+ return FALSE;
10818 }
10819
10820 static void
10821-search_get_valid_child_iter (GtkFileChooserDefault *impl,
10822- GtkTreeIter *child_iter,
10823- GtkTreeIter *iter)
10824+gtk_file_chooser_default_select_all (GtkFileChooser *chooser)
10825 {
10826- GtkTreeIter middle;
10827-
10828- if (!impl->search_model)
10829- return;
10830+ GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
10831+ if (impl->select_multiple)
10832+ gtk_tree_model_foreach (GTK_TREE_MODEL (impl->sort_model),
10833+ maybe_select, impl);
10834+}
10835
10836- if (!impl->search_model_filter || !impl->search_model_sort)
10837- return;
10838+static void
10839+gtk_file_chooser_default_unselect_all (GtkFileChooser *chooser)
10840+{
10841+ GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
10842+ GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
10843
10844- /* pass 1: get the iterator in the filter model */
10845- gtk_tree_model_sort_convert_iter_to_child_iter (impl->search_model_sort,
10846- &middle, iter);
10847-
10848- /* pass 2: get the iterator in the real model */
10849- gtk_tree_model_filter_convert_iter_to_child_iter (impl->search_model_filter,
10850- child_iter, &middle);
10851+ gtk_tree_selection_unselect_all (selection);
10852+ pending_select_paths_free (impl);
10853 }
10854
10855-/* Creates a new query with the specified text and launches it */
10856+/* Checks whether the filename entry for the Save modes contains a well-formed filename.
10857+ *
10858+ * is_well_formed_ret - whether what the user typed passes gkt_file_system_make_path()
10859+ *
10860+ * is_empty_ret - whether the file entry is totally empty
10861+ *
10862+ * is_file_part_empty_ret - whether the file part is empty (will be if user types "foobar/", and
10863+ * the path will be "$cwd/foobar")
10864+ */
10865 static void
10866-search_start_query (GtkFileChooserDefault *impl,
10867- const gchar *query_text)
10868+check_save_entry (GtkFileChooserDefault *impl,
10869+ GtkFilePath **path_ret,
10870+ gboolean *is_well_formed_ret,
10871+ gboolean *is_empty_ret,
10872+ gboolean *is_file_part_empty_ret,
10873+ gboolean *is_folder)
10874 {
10875- search_stop_searching (impl, FALSE);
10876- search_clear_model (impl, TRUE);
10877- search_setup_model (impl);
10878- set_busy_cursor (impl, TRUE);
10879+ GtkFileChooserEntry *chooser_entry;
10880+ const GtkFilePath *current_folder;
10881+ const char *file_part;
10882+ GtkFilePath *path;
10883+ GError *error;
10884
10885- if (impl->search_engine == NULL)
10886- impl->search_engine = _gtk_search_engine_new ();
10887+ g_assert (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
10888+ || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER
10889+ || impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
10890+ || impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
10891+
10892+ chooser_entry = GTK_FILE_CHOOSER_ENTRY (impl->location_entry);
10893
10894- if (!impl->search_engine)
10895+ if (strlen (gtk_entry_get_text (GTK_ENTRY (chooser_entry))) == 0)
10896 {
10897- set_busy_cursor (impl, FALSE);
10898- search_error_could_not_create_client (impl); /* lame; we don't get an error code or anything */
10899+ *path_ret = NULL;
10900+ *is_well_formed_ret = TRUE;
10901+ *is_empty_ret = TRUE;
10902+ *is_file_part_empty_ret = TRUE;
10903+ *is_folder = FALSE;
10904+
10905 return;
10906 }
10907
10908- if (!impl->search_query)
10909+ *is_empty_ret = FALSE;
10910+
10911+ current_folder = _gtk_file_chooser_entry_get_current_folder (chooser_entry);
10912+ if (!current_folder)
10913 {
10914- impl->search_query = _gtk_query_new ();
10915- _gtk_query_set_text (impl->search_query, query_text);
10916+ *path_ret = NULL;
10917+ *is_well_formed_ret = FALSE;
10918+ *is_file_part_empty_ret = FALSE;
10919+ *is_folder = FALSE;
10920+
10921+ return;
10922 }
10923-
10924- _gtk_search_engine_set_query (impl->search_engine, impl->search_query);
10925
10926- g_signal_connect (impl->search_engine, "hits-added",
10927- G_CALLBACK (search_engine_hits_added_cb), impl);
10928- g_signal_connect (impl->search_engine, "finished",
10929- G_CALLBACK (search_engine_finished_cb), impl);
10930- g_signal_connect (impl->search_engine, "error",
10931- G_CALLBACK (search_engine_error_cb), impl);
10932+ file_part = _gtk_file_chooser_entry_get_file_part (chooser_entry);
10933
10934- _gtk_search_engine_start (impl->search_engine);
10935-}
10936+ if (!file_part || file_part[0] == '\0')
10937+ {
10938+ *path_ret = gtk_file_path_copy (current_folder);
10939+ *is_well_formed_ret = TRUE;
10940+ *is_file_part_empty_ret = TRUE;
10941+ *is_folder = TRUE;
10942
10943-/* Callback used when the user presses Enter while typing on the search
10944- * entry; starts the query
10945- */
10946-static void
10947-search_entry_activate_cb (GtkEntry *entry,
10948- gpointer data)
10949-{
10950- GtkFileChooserDefault *impl;
10951- const char *text;
10952+ return;
10953+ }
10954
10955- impl = GTK_FILE_CHOOSER_DEFAULT (data);
10956+ *is_file_part_empty_ret = FALSE;
10957
10958- text = gtk_entry_get_text (GTK_ENTRY (impl->search_entry));
10959- if (strlen (text) == 0)
10960- return;
10961+ error = NULL;
10962+ path = gtk_file_system_make_path (impl->file_system, current_folder, file_part, &error);
10963
10964- /* reset any existing query object */
10965- if (impl->search_query)
10966+ if (!path)
10967 {
10968- g_object_unref (impl->search_query);
10969- impl->search_query = NULL;
10970+ error_building_filename_dialog (impl, current_folder, file_part, error);
10971+ *path_ret = NULL;
10972+ *is_well_formed_ret = FALSE;
10973+ *is_folder = FALSE;
10974+
10975+ return;
10976 }
10977
10978- search_start_query (impl, text);
10979+ *path_ret = path;
10980+ *is_well_formed_ret = TRUE;
10981+ *is_folder = _gtk_file_chooser_entry_get_is_folder (chooser_entry, path);
10982 }
10983
10984-/* Hides the path bar and creates the search entry */
10985+struct get_paths_closure {
10986+ GtkFileChooserDefault *impl;
10987+ GSList *result;
10988+ GtkFilePath *path_from_entry;
10989+};
10990+
10991 static void
10992-search_setup_widgets (GtkFileChooserDefault *impl)
10993+get_paths_foreach (GtkTreeModel *model,
10994+ GtkTreePath *path,
10995+ GtkTreeIter *iter,
10996+ gpointer data)
10997 {
10998- GtkWidget *label;
10999+ struct get_paths_closure *info;
11000+ const GtkFilePath *file_path;
11001+ GtkFileSystemModel *fs_model;
11002+ GtkTreeIter sel_iter;
11003+
11004+ info = data;
11005+ fs_model = info->impl->browse_files_model;
11006+ gtk_tree_model_sort_convert_iter_to_child_iter (info->impl->sort_model, &sel_iter, iter);
11007
11008- impl->search_hbox = gtk_hbox_new (FALSE, 12);
11009+ file_path = _gtk_file_system_model_get_path (fs_model, &sel_iter);
11010+ if (!file_path)
11011+ return; /* We are on the editable row */
11012
11013- /* Label */
11014+ if (!info->path_from_entry
11015+ || gtk_file_path_compare (info->path_from_entry, file_path) != 0)
11016+ info->result = g_slist_prepend (info->result, gtk_file_path_copy (file_path));
11017+}
11018
11019- label = gtk_label_new_with_mnemonic (_("_Search:"));
11020- gtk_box_pack_start (GTK_BOX (impl->search_hbox), label, FALSE, FALSE, 0);
11021+static GSList *
11022+gtk_file_chooser_default_get_paths (GtkFileChooser *chooser)
11023+{
11024+ GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
11025+ struct get_paths_closure info;
11026+ GtkWindow *toplevel;
11027+ GtkWidget *current_focus;
11028
11029- /* Entry */
11030+ info.impl = impl;
11031+ info.result = NULL;
11032+ info.path_from_entry = NULL;
11033
11034- impl->search_entry = gtk_entry_new ();
11035- gtk_label_set_mnemonic_widget (GTK_LABEL (label), impl->search_entry);
11036- g_signal_connect (impl->search_entry, "activate",
11037- G_CALLBACK (search_entry_activate_cb),
11038- impl);
11039- gtk_box_pack_start (GTK_BOX (impl->search_hbox), impl->search_entry, TRUE, TRUE, 0);
11040+ toplevel = get_toplevel (GTK_WIDGET (impl));
11041+ if (toplevel)
11042+ current_focus = gtk_window_get_focus (toplevel);
11043+ else
11044+ current_focus = NULL;
11045
11046- /* if there already is a query, restart it */
11047- if (impl->search_query)
11048+ if (current_focus == impl->browse_files_tree_view)
11049 {
11050- gchar *query = _gtk_query_get_text (impl->search_query);
11051+ GtkTreeSelection *selection;
11052
11053- if (query)
11054- {
11055- gtk_entry_set_text (GTK_ENTRY (impl->search_entry), query);
11056- search_start_query (impl, query);
11057+ file_list:
11058
11059- g_free (query);
11060- }
11061- else
11062- {
11063- g_object_unref (impl->search_query);
11064- impl->search_query = NULL;
11065- }
11066+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
11067+ gtk_tree_selection_selected_foreach (selection, get_paths_foreach, &info);
11068+
11069+ /* If there is no selection in the file list, we probably have this situation:
11070+ *
11071+ * 1. The user typed a filename in the SAVE filename entry ("foo.txt").
11072+ * 2. He then double-clicked on a folder ("bar") in the file list
11073+ *
11074+ * So we want the selection to be "bar/foo.txt". Jump to the case for the
11075+ * filename entry to see if that is the case.
11076+ */
11077+ if (info.result == NULL && impl->location_entry)
11078+ goto file_entry;
11079 }
11080+ else if (impl->location_entry && current_focus == impl->location_entry)
11081+ {
11082+ gboolean is_well_formed, is_empty, is_file_part_empty, is_folder;
11083+
11084+ file_entry:
11085+
11086+ check_save_entry (impl, &info.path_from_entry, &is_well_formed, &is_empty, &is_file_part_empty, &is_folder);
11087+
11088+ if (is_empty)
11089+ goto out;
11090
11091- gtk_widget_hide (impl->browse_path_bar);
11092- gtk_widget_hide (impl->browse_new_folder_button);
11093+ if (!is_well_formed)
11094+ return NULL;
11095+
11096+ if (is_file_part_empty && impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
11097+ {
11098+ gtk_file_path_free (info.path_from_entry);
11099+ return NULL;
11100+ }
11101
11102- /* Box for search widgets */
11103- gtk_box_pack_start (GTK_BOX (impl->browse_path_bar_hbox), impl->search_hbox, TRUE, TRUE, 0);
11104- gtk_widget_show_all (impl->search_hbox);
11105+ g_assert (info.path_from_entry != NULL);
11106+ info.result = g_slist_prepend (info.result, info.path_from_entry);
11107+ }
11108+ else if (impl->toplevel_last_focus_widget == impl->browse_files_tree_view)
11109+ goto file_list;
11110+ else if (impl->location_entry && impl->toplevel_last_focus_widget == impl->location_entry)
11111+ goto file_entry;
11112+ else
11113+ {
11114+ /* The focus is on a dialog's action area button or something else */
11115+ if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
11116+ || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
11117+ goto file_entry;
11118+ else
11119+ goto file_list;
11120+ }
11121
11122- /* Hide the location widgets temporarily */
11123+ out:
11124
11125- if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
11126- impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
11127+ /* If there's no folder selected, and we're in SELECT_FOLDER mode, then we
11128+ * fall back to the current directory */
11129+ if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER &&
11130+ info.result == NULL)
11131 {
11132- gtk_widget_hide (impl->location_button);
11133- gtk_widget_hide (impl->location_entry_box);
11134+ info.result = g_slist_prepend (info.result, _gtk_file_chooser_get_current_folder_path (chooser));
11135 }
11136
11137- gtk_widget_grab_focus (impl->search_entry);
11138+ return g_slist_reverse (info.result);
11139+}
11140+
11141+static GtkFileSystem *
11142+gtk_file_chooser_default_get_file_system (GtkFileChooser *chooser)
11143+{
11144+ GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
11145
11146- /* FMQ: hide the filter combo? */
11147+ return impl->file_system;
11148 }
11149
11150-/* Main entry point to the searching functions; this gets called when the user
11151- * activates the Search shortcut.
11152- */
11153+/* Shows or hides the filter widgets */
11154 static void
11155-search_activate (GtkFileChooserDefault *impl)
11156+show_filters (GtkFileChooserDefault *impl,
11157+ gboolean show)
11158 {
11159- OperationMode previous_mode;
11160-
11161- if (impl->operation_mode == OPERATION_MODE_SEARCH)
11162+ if (show)
11163+ gtk_widget_show (impl->filter_combo);
11164+ else
11165+ gtk_widget_hide (impl->filter_combo);
11166+}
11167+
11168+static void
11169+gtk_file_chooser_default_add_filter (GtkFileChooser *chooser,
11170+ GtkFileFilter *filter)
11171+{
11172+ GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
11173+ const gchar *name;
11174+
11175+ g_debug ("adding filter");
11176+
11177+ if (g_slist_find (impl->filters, filter))
11178 {
11179- gtk_widget_grab_focus (impl->search_entry);
11180+ g_warning ("gtk_file_chooser_add_filter() called on filter already in list\n");
11181 return;
11182 }
11183
11184- previous_mode = impl->operation_mode;
11185- impl->operation_mode = OPERATION_MODE_SEARCH;
11186-
11187- switch (previous_mode)
11188- {
11189- case OPERATION_MODE_RECENT:
11190- recent_stop_loading (impl);
11191- recent_clear_model (impl, TRUE);
11192- break;
11193+ g_object_ref_sink (filter);
11194+ impl->filters = g_slist_append (impl->filters, filter);
11195
11196- case OPERATION_MODE_BROWSE:
11197- stop_loading_and_clear_list_model (impl);
11198- break;
11199+ name = gtk_file_filter_get_name (filter);
11200+ if (!name)
11201+ name = "Untitled filter"; /* Place-holder, doesn't need to be marked for translation */
11202
11203- case OPERATION_MODE_SEARCH:
11204- g_assert_not_reached ();
11205- break;
11206- }
11207+ gtk_combo_box_append_text (GTK_COMBO_BOX (impl->filter_combo), name);
11208
11209- g_assert (impl->search_hbox == NULL);
11210- g_assert (impl->search_entry == NULL);
11211- g_assert (impl->search_model == NULL);
11212- g_assert (impl->search_model_filter == NULL);
11213+ if (!g_slist_find (impl->filters, impl->current_filter))
11214+ set_current_filter (impl, filter);
11215
11216- search_setup_widgets (impl);
11217- file_list_set_sort_column_ids (impl);
11218+ show_filters (impl, g_slist_length (impl->filters) > 1);
11219 }
11220
11221-/*
11222- * Recent files support
11223- */
11224-
11225-/* Frees the data in the recent_model */
11226 static void
11227-recent_clear_model (GtkFileChooserDefault *impl,
11228- gboolean remove_from_treeview)
11229+gtk_file_chooser_default_remove_filter (GtkFileChooser *chooser,
11230+ GtkFileFilter *filter)
11231 {
11232+ GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
11233 GtkTreeModel *model;
11234 GtkTreeIter iter;
11235+ gint filter_index;
11236
11237- if (!impl->recent_model)
11238- return;
11239-
11240- model = GTK_TREE_MODEL (impl->recent_model);
11241-
11242- if (remove_from_treeview)
11243- gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view), NULL);
11244-
11245- if (gtk_tree_model_get_iter_first (model, &iter))
11246- {
11247- do
11248- {
11249- GtkFilePath *file_path;
11250- GtkFileSystemHandle *handle;
11251- GtkRecentInfo *recent_info;
11252- gchar *display_name;
11253-
11254- gtk_tree_model_get (model, &iter,
11255- RECENT_MODEL_COL_DISPLAY_NAME, &display_name,
11256- RECENT_MODEL_COL_PATH, &file_path,
11257- RECENT_MODEL_COL_HANDLE, &handle,
11258- RECENT_MODEL_COL_INFO, &recent_info,
11259- -1);
11260-
11261- if (handle)
11262- gtk_file_system_cancel_operation (handle);
11263-
11264- gtk_file_path_free (file_path);
11265- gtk_recent_info_unref (recent_info);
11266- g_free (display_name);
11267- }
11268- while (gtk_tree_model_iter_next (model, &iter));
11269- }
11270-
11271- g_object_unref (impl->recent_model);
11272- impl->recent_model = NULL;
11273-
11274- g_object_unref (impl->recent_model_filter);
11275- impl->recent_model_filter = NULL;
11276-
11277- g_object_unref (impl->recent_model_sort);
11278- impl->recent_model_sort = NULL;
11279-}
11280+ filter_index = g_slist_index (impl->filters, filter);
11281
11282-/* Stops any ongoing loading of the recent files list; does
11283- * not touch the recent_model
11284- */
11285-static void
11286-recent_stop_loading (GtkFileChooserDefault *impl)
11287-{
11288- if (impl->load_recent_id)
11289+ if (filter_index < 0)
11290 {
11291- g_source_remove (impl->load_recent_id);
11292- impl->load_recent_id = 0;
11293+ g_warning ("gtk_file_chooser_remove_filter() called on filter not in list\n");
11294+ return;
11295 }
11296-}
11297-
11298-/* Stops any pending load, clears the file list, and switches
11299- * back to OPERATION_MODE_BROWSE
11300- */
11301-static void
11302-recent_switch_to_browse_mode (GtkFileChooserDefault *impl)
11303-{
11304- g_assert (impl->operation_mode != OPERATION_MODE_BROWSE);
11305-
11306- recent_stop_loading (impl);
11307- recent_clear_model (impl, TRUE);
11308
11309- gtk_widget_show (impl->browse_path_bar);
11310- gtk_widget_show (impl->browse_new_folder_button);
11311+ impl->filters = g_slist_remove (impl->filters, filter);
11312
11313- if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
11314- impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
11315+ if (filter == impl->current_filter)
11316 {
11317- gtk_widget_show (impl->location_button);
11318-
11319- if (impl->location_mode == LOCATION_MODE_FILENAME_ENTRY)
11320- gtk_widget_show (impl->location_entry_box);
11321+ if (impl->filters)
11322+ set_current_filter (impl, impl->filters->data);
11323+ else
11324+ set_current_filter (impl, NULL);
11325 }
11326
11327- impl->operation_mode = OPERATION_MODE_BROWSE;
11328-
11329- file_list_set_sort_column_ids (impl);
11330-}
11331+ /* Remove row from the combo box */
11332+ model = gtk_combo_box_get_model (GTK_COMBO_BOX (impl->filter_combo));
11333+ if (!gtk_tree_model_iter_nth_child (model, &iter, NULL, filter_index))
11334+ g_assert_not_reached ();
11335
11336-/* Sort callback from the modification time column */
11337-static gint
11338-recent_column_mtime_sort_func (GtkTreeModel *model,
11339- GtkTreeIter *a,
11340- GtkTreeIter *b,
11341- gpointer user_data)
11342-{
11343- GtkFileChooserDefault *impl = user_data;
11344- GtkTreeIter child_a, child_b;
11345- GtkRecentInfo *info_a, *info_b;
11346- gboolean is_folder_a, is_folder_b;
11347-
11348- gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), &child_a, a);
11349- gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), &child_b, b);
11350-
11351- gtk_tree_model_get (GTK_TREE_MODEL (impl->recent_model), &child_a,
11352- RECENT_MODEL_COL_IS_FOLDER, &is_folder_a,
11353- RECENT_MODEL_COL_INFO, &info_a,
11354- -1);
11355- gtk_tree_model_get (GTK_TREE_MODEL (impl->recent_model), &child_b,
11356- RECENT_MODEL_COL_IS_FOLDER, &is_folder_b,
11357- RECENT_MODEL_COL_INFO, &info_b,
11358- -1);
11359-
11360- if (!info_a)
11361- return 1;
11362+ gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
11363
11364- if (!info_b)
11365- return -1;
11366+ g_object_unref (filter);
11367
11368- /* folders always go first */
11369- if (is_folder_a != is_folder_b)
11370- return is_folder_a ? 1 : -1;
11371-
11372- if (gtk_recent_info_get_modified (info_a) < gtk_recent_info_get_modified (info_b))
11373- return -1;
11374- else if (gtk_recent_info_get_modified (info_a) > gtk_recent_info_get_modified (info_b))
11375- return 1;
11376- else
11377- return 0;
11378+ show_filters (impl, g_slist_length (impl->filters) > 1);
11379 }
11380
11381-static gint
11382-recent_column_path_sort_func (GtkTreeModel *model,
11383- GtkTreeIter *a,
11384- GtkTreeIter *b,
11385- gpointer user_data)
11386+static GSList *
11387+gtk_file_chooser_default_list_filters (GtkFileChooser *chooser)
11388 {
11389- GtkFileChooserDefault *impl = user_data;
11390- GtkTreeIter child_a, child_b;
11391- gboolean is_folder_a, is_folder_b;
11392- gchar *name_a, *name_b;
11393-
11394- gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), &child_a, a);
11395- gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), &child_b, b);
11396-
11397- gtk_tree_model_get (GTK_TREE_MODEL (impl->recent_model), &child_a,
11398- RECENT_MODEL_COL_IS_FOLDER, &is_folder_a,
11399- RECENT_MODEL_COL_DISPLAY_NAME, &name_a,
11400- -1);
11401- gtk_tree_model_get (GTK_TREE_MODEL (impl->recent_model), &child_b,
11402- RECENT_MODEL_COL_IS_FOLDER, &is_folder_b,
11403- RECENT_MODEL_COL_DISPLAY_NAME, &name_b,
11404- -1);
11405-
11406- if (!name_a)
11407- return 1;
11408-
11409- if (!name_b)
11410- return -1;
11411-
11412- if (is_folder_a != is_folder_b)
11413- return is_folder_a ? 1 : -1;
11414+ GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
11415
11416- return strcmp (name_a, name_b);
11417+ return g_slist_copy (impl->filters);
11418 }
11419
11420-static gboolean
11421-recent_get_is_filtered (GtkFileChooserDefault *impl,
11422- const GtkFilePath *path,
11423- GtkRecentInfo *recent_info)
11424+/* Guesses a size based upon font sizes */
11425+static void
11426+find_good_size_from_style (GtkWidget *widget,
11427+ gint *width,
11428+ gint *height)
11429 {
11430- GtkFileFilterInfo filter_info;
11431- GtkFileFilterFlags needed;
11432- gboolean result;
11433-
11434- if (!impl->current_filter)
11435- return FALSE;
11436-
11437- filter_info.contains = GTK_FILE_FILTER_DISPLAY_NAME | GTK_FILE_FILTER_MIME_TYPE;
11438- needed = gtk_file_filter_get_needed (impl->current_filter);
11439+ GtkFileChooserDefault *impl;
11440+ int font_size;
11441+ GdkScreen *screen;
11442+ double resolution;
11443
11444- filter_info.display_name = gtk_recent_info_get_display_name (recent_info);
11445- filter_info.mime_type = gtk_recent_info_get_mime_type (recent_info);
11446+ g_assert (widget->style != NULL);
11447+ impl = GTK_FILE_CHOOSER_DEFAULT (widget);
11448
11449- if (needed & GTK_FILE_FILTER_FILENAME)
11450+ if (impl->default_width == 0 &&
11451+ impl->default_height == 0)
11452 {
11453- filter_info.filename = gtk_file_system_path_to_filename (impl->file_system, path);
11454- if (filter_info.filename)
11455- filter_info.contains |= GTK_FILE_FILTER_FILENAME;
11456- }
11457- else
11458- filter_info.filename = NULL;
11459+ screen = gtk_widget_get_screen (widget);
11460+ if (screen)
11461+ {
11462+ resolution = gdk_screen_get_resolution (screen);
11463+ if (resolution < 0.0) /* will be -1 if the resolution is not defined in the GdkScreen */
11464+ resolution = 96.0;
11465+ }
11466+ else
11467+ resolution = 96.0; /* wheeee */
11468
11469- if (needed & GTK_FILE_FILTER_URI)
11470- {
11471- filter_info.uri = gtk_file_system_path_to_uri (impl->file_system, path);
11472- if (filter_info.uri)
11473- filter_info.contains |= GTK_FILE_FILTER_URI;
11474+ font_size = pango_font_description_get_size (widget->style->font_desc);
11475+ font_size = PANGO_PIXELS (font_size) * resolution / 72.0;
11476+
11477+ impl->default_width = font_size * NUM_CHARS;
11478+ impl->default_height = font_size * NUM_LINES;
11479 }
11480- else
11481- filter_info.uri = NULL;
11482
11483- result = gtk_file_filter_filter (impl->current_filter, &filter_info);
11484+ *width = impl->default_width;
11485+ *height = impl->default_height;
11486+}
11487
11488- if (filter_info.filename)
11489- g_free ((gchar *) filter_info.filename);
11490- if (filter_info.uri)
11491- g_free ((gchar *) filter_info.uri);
11492+static void
11493+gtk_file_chooser_default_get_default_size (GtkFileChooserEmbed *chooser_embed,
11494+ gint *default_width,
11495+ gint *default_height)
11496+{
11497+ GtkFileChooserDefault *impl;
11498
11499- return !result;
11500+ impl = GTK_FILE_CHOOSER_DEFAULT (chooser_embed);
11501+ find_good_size_from_style (GTK_WIDGET (chooser_embed), default_width, default_height);
11502 }
11503
11504-/* Visibility function for the recent filter model */
11505 static gboolean
11506-recent_model_visible_func (GtkTreeModel *model,
11507- GtkTreeIter *iter,
11508- gpointer user_data)
11509+gtk_file_chooser_default_get_resizable (GtkFileChooserEmbed *chooser_embed)
11510 {
11511- GtkFileChooserDefault *impl = user_data;
11512- GtkFilePath *file_path;
11513- GtkRecentInfo *recent_info;
11514- gboolean is_folder;
11515-
11516- if (!impl->current_filter)
11517- return TRUE;
11518-
11519- gtk_tree_model_get (model, iter,
11520- RECENT_MODEL_COL_INFO, &recent_info,
11521- RECENT_MODEL_COL_PATH, &file_path,
11522- RECENT_MODEL_COL_IS_FOLDER, &is_folder,
11523- -1);
11524-
11525- if (!recent_info)
11526- return TRUE;
11527-
11528- if (is_folder)
11529- return TRUE;
11530+ GtkFileChooserDefault *impl;
11531
11532- return !recent_get_is_filtered (impl, file_path, recent_info);
11533-}
11534+ impl = GTK_FILE_CHOOSER_DEFAULT (chooser_embed);
11535
11536-static void
11537-recent_setup_model (GtkFileChooserDefault *impl)
11538-{
11539- g_assert (impl->recent_model == NULL);
11540- g_assert (impl->recent_model_filter == NULL);
11541- g_assert (impl->recent_model_sort == NULL);
11542-
11543- /* We store these columns in the search model:
11544- *
11545- * RECENT_MODEL_COL_PATH - a pointer to GtkFilePath for the hit's URI,
11546- * stored as a pointer and not as a GTK_TYPE_FILE_PATH;
11547- * RECENT_MODEL_COL_DISPLAY_NAME - a string with the display name,
11548- * stored as a pointer and not as a G_TYPE_STRING;
11549- * RECENT_MODEL_COL_INFO - GtkRecentInfo, stored as a pointer and not
11550- * as a GTK_TYPE_RECENT_INFO;
11551- * RECENT_MODEL_COL_IS_FOLDER - boolean flag;
11552- * RECENT_MODEL_COL_HANDLE - GtkFileSystemHandle, stored as a pointer
11553- * and not as a GTK_TYPE_FILE_SYSTEM_HANDLE;
11554- *
11555- * Keep this in sync with the enumeration defined near the beginning of
11556- * this file.
11557- */
11558- impl->recent_model = gtk_list_store_new (RECENT_MODEL_COL_NUM_COLUMNS,
11559- G_TYPE_POINTER,
11560- G_TYPE_POINTER,
11561- G_TYPE_POINTER,
11562- G_TYPE_BOOLEAN,
11563- G_TYPE_POINTER);
11564-
11565- impl->recent_model_filter =
11566- GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (GTK_TREE_MODEL (impl->recent_model), NULL));
11567- gtk_tree_model_filter_set_visible_func (impl->recent_model_filter,
11568- recent_model_visible_func,
11569- impl,
11570- NULL);
11571-
11572- /* this is the model that will actually be added to
11573- * the browse_files_tree_view widget; remember: we are
11574- * stuffing the real model into a filter model and then
11575- * into a sort model; this means we'll have to translate
11576- * the child iterator *twice* to get from a path or an
11577- * iterator coming from the tree view widget to the
11578- * real data inside the model.
11579- */
11580- impl->recent_model_sort =
11581- GTK_TREE_MODEL_SORT (recent_model_sort_new (impl, GTK_TREE_MODEL (impl->recent_model_filter)));
11582- gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->recent_model_sort),
11583- RECENT_MODEL_COL_PATH,
11584- recent_column_path_sort_func,
11585- impl, NULL);
11586- gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->recent_model_sort),
11587- RECENT_MODEL_COL_INFO,
11588- recent_column_mtime_sort_func,
11589- impl, NULL);
11590- gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (impl->recent_model_sort),
11591- RECENT_MODEL_COL_INFO,
11592- GTK_SORT_DESCENDING);
11593+ return (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
11594+ impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
11595 }
11596
11597-typedef struct
11598-{
11599+struct switch_folder_closure {
11600 GtkFileChooserDefault *impl;
11601- GList *items;
11602- gint n_items;
11603- gint n_loaded_items;
11604- guint needs_sorting : 1;
11605-} RecentLoadData;
11606+ const GtkFilePath *path;
11607+ int num_selected;
11608+};
11609
11610+/* Used from gtk_tree_selection_selected_foreach() in switch_to_selected_folder() */
11611 static void
11612-recent_idle_cleanup (gpointer data)
11613+switch_folder_foreach_cb (GtkTreeModel *model,
11614+ GtkTreePath *path,
11615+ GtkTreeIter *iter,
11616+ gpointer data)
11617 {
11618- RecentLoadData *load_data = data;
11619- GtkFileChooserDefault *impl = load_data->impl;
11620+ struct switch_folder_closure *closure;
11621+ GtkTreeIter child_iter;
11622
11623- gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view),
11624- GTK_TREE_MODEL (impl->recent_model_sort));
11625+ closure = data;
11626
11627- set_busy_cursor (impl, FALSE);
11628-
11629- impl->load_recent_id = 0;
11630-
11631- if (load_data->items)
11632- {
11633- g_list_foreach (load_data->items, (GFunc) gtk_recent_info_unref, NULL);
11634- g_list_free (load_data->items);
11635- }
11636+ gtk_tree_model_sort_convert_iter_to_child_iter (closure->impl->sort_model, &child_iter, iter);
11637
11638- g_free (load_data);
11639+ closure->path = _gtk_file_system_model_get_path (closure->impl->browse_files_model, &child_iter);
11640+ closure->num_selected++;
11641 }
11642
11643-struct RecentItemInsertRequest
11644-{
11645- GtkFileChooserDefault *impl;
11646- GtkFilePath *path;
11647- GtkTreeRowReference *row_ref;
11648-};
11649-
11650+/* Changes to the selected folder in the list view */
11651 static void
11652-recent_item_get_info_cb (GtkFileSystemHandle *handle,
11653- const GtkFileInfo *info,
11654- const GError *error,
11655- gpointer data)
11656+switch_to_selected_folder (GtkFileChooserDefault *impl)
11657 {
11658- gboolean cancelled = handle->cancelled;
11659- GtkTreePath *path;
11660- GtkTreeIter iter;
11661- GtkFileSystemHandle *model_handle;
11662- gboolean is_folder = FALSE;
11663- struct RecentItemInsertRequest *request = data;
11664+ GtkTreeSelection *selection;
11665+ struct switch_folder_closure closure;
11666
11667- if (!request->impl->recent_model)
11668- goto out;
11669+ /* We do this with foreach() rather than get_selected() as we may be in
11670+ * multiple selection mode
11671+ */
11672
11673- path = gtk_tree_row_reference_get_path (request->row_ref);
11674- if (!path)
11675- goto out;
11676+ closure.impl = impl;
11677+ closure.path = NULL;
11678+ closure.num_selected = 0;
11679
11680- gtk_tree_model_get_iter (GTK_TREE_MODEL (request->impl->recent_model),
11681- &iter, path);
11682- gtk_tree_path_free (path);
11683+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
11684+ gtk_tree_selection_selected_foreach (selection, switch_folder_foreach_cb, &closure);
11685
11686- gtk_tree_model_get (GTK_TREE_MODEL (request->impl->recent_model), &iter,
11687- RECENT_MODEL_COL_HANDLE, &model_handle,
11688- -1);
11689- if (handle != model_handle)
11690- goto out;
11691+ g_assert (closure.path && closure.num_selected == 1);
11692
11693- gtk_list_store_set (request->impl->recent_model, &iter,
11694- RECENT_MODEL_COL_HANDLE, NULL,
11695- -1);
11696+ change_folder_and_display_error (impl, closure.path);
11697+}
11698
11699- if (cancelled)
11700- goto out;
11701+/* Gets the GtkFileInfo for the selected row in the file list; assumes single
11702+ * selection mode.
11703+ */
11704+static const GtkFileInfo *
11705+get_selected_file_info_from_file_list (GtkFileChooserDefault *impl,
11706+ gboolean *had_selection)
11707+{
11708+ GtkTreeSelection *selection;
11709+ GtkTreeIter iter, child_iter;
11710+ const GtkFileInfo *info;
11711
11712- if (!info)
11713+ g_assert (!impl->select_multiple);
11714+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
11715+ if (!gtk_tree_selection_get_selected (selection, NULL, &iter))
11716 {
11717- gtk_list_store_remove (request->impl->recent_model, &iter);
11718- goto out;
11719+ *had_selection = FALSE;
11720+ return NULL;
11721 }
11722
11723- is_folder = gtk_file_info_get_is_folder (info);
11724-
11725- gtk_list_store_set (request->impl->recent_model, &iter,
11726- RECENT_MODEL_COL_IS_FOLDER, is_folder,
11727- -1);
11728+ *had_selection = TRUE;
11729
11730-out:
11731- g_object_unref (request->impl);
11732- gtk_file_path_free (request->path);
11733- gtk_tree_row_reference_free (request->row_ref);
11734- g_free (request);
11735+ gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model,
11736+ &child_iter,
11737+ &iter);
11738
11739- g_object_unref (handle);
11740+ info = _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
11741+ return info;
11742 }
11743
11744-static gint
11745-recent_sort_mru (gconstpointer a,
11746- gconstpointer b)
11747+/* Gets the display name of the selected file in the file list; assumes single
11748+ * selection mode and that something is selected.
11749+ */
11750+static const gchar *
11751+get_display_name_from_file_list (GtkFileChooserDefault *impl)
11752 {
11753- GtkRecentInfo *info_a = (GtkRecentInfo *) a;
11754- GtkRecentInfo *info_b = (GtkRecentInfo *) b;
11755+ const GtkFileInfo *info;
11756+ gboolean had_selection;
11757+
11758+ info = get_selected_file_info_from_file_list (impl, &had_selection);
11759+ g_assert (had_selection);
11760+ g_assert (info != NULL);
11761
11762- return (gtk_recent_info_get_modified (info_a) < gtk_recent_info_get_modified (info_b));
11763+ return gtk_file_info_get_display_name (info);
11764 }
11765
11766-static gint
11767-get_recent_files_limit (GtkWidget *widget)
11768+static void
11769+add_custom_button_to_dialog (GtkDialog *dialog,
11770+ const gchar *mnemonic_label,
11771+ const gchar *stock_id,
11772+ gint response_id)
11773 {
11774- GtkSettings *settings;
11775- gint limit;
11776-
11777- if (gtk_widget_has_screen (widget))
11778- settings = gtk_settings_get_for_screen (gtk_widget_get_screen (widget));
11779- else
11780- settings = gtk_settings_get_default ();
11781+ GtkWidget *button;
11782
11783- g_object_get (G_OBJECT (settings), "gtk-recent-files-limit", &limit, NULL);
11784+ button = gtk_button_new_with_mnemonic (mnemonic_label);
11785+ GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
11786+ gtk_button_set_image (GTK_BUTTON (button),
11787+ gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_BUTTON));
11788+ gtk_widget_show (button);
11789
11790- return limit;
11791+ gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button, response_id);
11792 }
11793
11794+/* Presents an overwrite confirmation dialog; returns whether we should accept
11795+ * the filename.
11796+ */
11797 static gboolean
11798-recent_idle_load (gpointer data)
11799+confirm_dialog_should_accept_filename (GtkFileChooserDefault *impl,
11800+ const gchar *file_part,
11801+ const gchar *folder_display_name)
11802 {
11803- RecentLoadData *load_data = data;
11804- GtkFileChooserDefault *impl = load_data->impl;
11805- GtkTreeIter iter;
11806- GtkTreePath *p;
11807- GtkRecentInfo *info;
11808- const gchar *uri, *display_name;
11809- GtkFilePath *path;
11810- GtkFileSystemHandle *handle;
11811- struct RecentItemInsertRequest *request;
11812-
11813- if (!impl->recent_manager)
11814- return FALSE;
11815+ GtkWindow *toplevel;
11816+ GtkWidget *dialog;
11817+ int response;
11818
11819- /* first iteration: load all the items */
11820- if (!load_data->items)
11821- {
11822- load_data->items = gtk_recent_manager_get_items (impl->recent_manager);
11823- if (!load_data->items)
11824- return FALSE;
11825+ toplevel = get_toplevel (GTK_WIDGET (impl));
11826
11827- load_data->needs_sorting = TRUE;
11828+ dialog = gtk_message_dialog_new (toplevel,
11829+ GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
11830+ GTK_MESSAGE_QUESTION,
11831+ GTK_BUTTONS_NONE,
11832+ _("A file named \"%s\" already exists. Do you want to replace it?"),
11833+ file_part);
11834+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
11835+ _("The file already exists in \"%s\". Replacing it will "
11836+ "overwrite its contents."),
11837+ folder_display_name);
11838
11839- return TRUE;
11840- }
11841+ gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
11842+ add_custom_button_to_dialog (GTK_DIALOG (dialog), _("_Replace"), GTK_STOCK_SAVE_AS, GTK_RESPONSE_ACCEPT);
11843+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
11844
11845- /* second iteration: preliminary MRU sorting and clamping */
11846- if (load_data->needs_sorting)
11847- {
11848- gint limit;
11849-
11850- load_data->items = g_list_sort (load_data->items, recent_sort_mru);
11851- load_data->n_items = g_list_length (load_data->items);
11852-
11853- limit = get_recent_files_limit (GTK_WIDGET (impl));
11854-
11855- if (limit != -1 && (load_data->n_items > limit))
11856- {
11857- GList *clamp, *l;
11858-
11859- clamp = g_list_nth (load_data->items, limit - 1);
11860- if (G_LIKELY (clamp))
11861- {
11862- l = clamp->next;
11863- clamp->next = NULL;
11864-
11865- g_list_foreach (l, (GFunc) gtk_recent_info_unref, NULL);
11866- g_list_free (l);
11867-
11868- load_data->n_items = limit;
11869- }
11870- }
11871-
11872- load_data->n_loaded_items = 0;
11873- load_data->needs_sorting = FALSE;
11874-
11875- return TRUE;
11876- }
11877-
11878- info = g_list_nth_data (load_data->items, load_data->n_loaded_items);
11879- g_assert (info != NULL);
11880-
11881- uri = gtk_recent_info_get_uri (info);
11882- display_name = gtk_recent_info_get_display_name (info);
11883- path = gtk_file_system_uri_to_path (impl->file_system, uri);
11884- if (!path)
11885- goto load_next;
11886-
11887- gtk_list_store_append (impl->recent_model, &iter);
11888- p = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->recent_model), &iter);
11889+ if (toplevel->group)
11890+ gtk_window_group_add_window (toplevel->group, GTK_WINDOW (dialog));
11891
11892- request = g_new0 (struct RecentItemInsertRequest, 1);
11893- request->impl = g_object_ref (impl);
11894- request->path = gtk_file_path_copy (path);
11895- request->row_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (impl->recent_model), p);
11896- gtk_tree_path_free (p);
11897-
11898- handle = gtk_file_system_get_info (impl->file_system, path,
11899- GTK_FILE_INFO_IS_FOLDER,
11900- recent_item_get_info_cb,
11901- request);
11902-
11903- gtk_list_store_set (impl->recent_model, &iter,
11904- RECENT_MODEL_COL_PATH, path,
11905- RECENT_MODEL_COL_DISPLAY_NAME, g_strdup (display_name),
11906- RECENT_MODEL_COL_INFO, gtk_recent_info_ref (info),
11907- RECENT_MODEL_COL_HANDLE, handle,
11908- -1);
11909-
11910-load_next:
11911-
11912- load_data->n_loaded_items += 1;
11913-
11914- /* finished loading items */
11915- if (load_data->n_loaded_items == load_data->n_items)
11916- {
11917- g_list_foreach (load_data->items, (GFunc) gtk_recent_info_unref, NULL);
11918- g_list_free (load_data->items);
11919- load_data->items = NULL;
11920+ response = gtk_dialog_run (GTK_DIALOG (dialog));
11921
11922- return FALSE;
11923- }
11924+ gtk_widget_destroy (dialog);
11925
11926- return TRUE;
11927+ return (response == GTK_RESPONSE_ACCEPT);
11928 }
11929
11930-static void
11931-recent_start_loading (GtkFileChooserDefault *impl)
11932+struct GetDisplayNameData
11933 {
11934- RecentLoadData *load_data;
11935-
11936- recent_stop_loading (impl);
11937- recent_clear_model (impl, TRUE);
11938- recent_setup_model (impl);
11939- set_busy_cursor (impl, TRUE);
11940-
11941- if (!impl->recent_manager)
11942- recent_manager_update (impl);
11943-
11944- g_assert (impl->load_recent_id == 0);
11945-
11946- load_data = g_new (RecentLoadData, 1);
11947- load_data->impl = impl;
11948- load_data->items = NULL;
11949- load_data->n_items = 0;
11950- load_data->n_loaded_items = 0;
11951- load_data->needs_sorting = TRUE;
11952-
11953- /* begin lazy loading the recent files into the model */
11954- impl->load_recent_id = gdk_threads_add_idle_full (G_PRIORITY_HIGH_IDLE + 30,
11955- recent_idle_load,
11956- load_data,
11957- recent_idle_cleanup);
11958-}
11959+ GtkFileChooserDefault *impl;
11960+ gchar *file_part;
11961+};
11962
11963 static void
11964-recent_selected_foreach_get_path_cb (GtkTreeModel *model,
11965- GtkTreePath *path,
11966- GtkTreeIter *iter,
11967- gpointer data)
11968+confirmation_confirm_get_info_cb (GtkFileSystemHandle *handle,
11969+ const GtkFileInfo *info,
11970+ const GError *error,
11971+ gpointer user_data)
11972 {
11973- GSList **list;
11974- const GtkFilePath *file_path;
11975- GtkFilePath *file_path_copy;
11976+ gboolean cancelled = handle->cancelled;
11977+ gboolean should_respond = FALSE;
11978+ struct GetDisplayNameData *data = user_data;
11979
11980- list = data;
11981+ if (handle != data->impl->should_respond_get_info_handle)
11982+ goto out;
11983
11984- gtk_tree_model_get (model, iter, RECENT_MODEL_COL_PATH, &file_path, -1);
11985- file_path_copy = gtk_file_path_copy (file_path);
11986- *list = g_slist_prepend (*list, file_path_copy);
11987-}
11988+ data->impl->should_respond_get_info_handle = NULL;
11989
11990-/* Constructs a list of the selected paths in recent files mode */
11991-static GSList *
11992-recent_get_selected_paths (GtkFileChooserDefault *impl)
11993-{
11994- GSList *result;
11995- GtkTreeSelection *selection;
11996+ if (cancelled)
11997+ goto out;
11998+
11999+ if (error)
12000+ /* Huh? Did the folder disappear? Let the caller deal with it */
12001+ should_respond = TRUE;
12002+ else
12003+ should_respond = confirm_dialog_should_accept_filename (data->impl, data->file_part, gtk_file_info_get_display_name (info));
12004
12005- result = NULL;
12006+ set_busy_cursor (data->impl, FALSE);
12007+ if (should_respond)
12008+ g_signal_emit_by_name (data->impl, "response-requested");
12009
12010- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
12011- gtk_tree_selection_selected_foreach (selection, recent_selected_foreach_get_path_cb, &result);
12012- result = g_slist_reverse (result);
12013+out:
12014+ g_object_unref (data->impl);
12015+ g_free (data->file_part);
12016+ g_free (data);
12017
12018- return result;
12019+ g_object_unref (handle);
12020 }
12021
12022-/* Called from ::should_respond(). We return whether there are selected
12023- * files in the recent files list.
12024+/* Does overwrite confirmation if appropriate, and returns whether the dialog
12025+ * should respond. Can get the file part from the file list or the save entry.
12026 */
12027 static gboolean
12028-recent_should_respond (GtkFileChooserDefault *impl)
12029+should_respond_after_confirm_overwrite (GtkFileChooserDefault *impl,
12030+ const gchar *file_part,
12031+ const GtkFilePath *parent_path)
12032 {
12033- GtkTreeSelection *selection;
12034+ GtkFileChooserConfirmation conf;
12035
12036- g_assert (impl->operation_mode == OPERATION_MODE_RECENT);
12037+ if (!impl->do_overwrite_confirmation)
12038+ return TRUE;
12039
12040- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
12041- return (gtk_tree_selection_count_selected_rows (selection) != 0);
12042-}
12043+ conf = GTK_FILE_CHOOSER_CONFIRMATION_CONFIRM;
12044
12045-/* Hide the location widgets temporarily */
12046-static void
12047-recent_hide_entry (GtkFileChooserDefault *impl)
12048-{
12049- gtk_widget_hide (impl->browse_path_bar);
12050- gtk_widget_hide (impl->browse_new_folder_button);
12051-
12052- if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
12053- impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
12054+ g_signal_emit_by_name (impl, "confirm-overwrite", &conf);
12055+
12056+ switch (conf)
12057 {
12058- gtk_widget_hide (impl->location_button);
12059- gtk_widget_hide (impl->location_entry_box);
12060- }
12061-}
12062+ case GTK_FILE_CHOOSER_CONFIRMATION_CONFIRM:
12063+ {
12064+ struct GetDisplayNameData *data;
12065
12066-/* Main entry point to the recent files functions; this gets called when
12067- * the user activates the Recently Used shortcut.
12068- */
12069-static void
12070-recent_activate (GtkFileChooserDefault *impl)
12071-{
12072- OperationMode previous_mode;
12073+ g_assert (file_part != NULL);
12074
12075- if (impl->operation_mode == OPERATION_MODE_RECENT)
12076- return;
12077+ data = g_new0 (struct GetDisplayNameData, 1);
12078+ data->impl = g_object_ref (impl);
12079+ data->file_part = g_strdup (file_part);
12080+
12081+ if (impl->should_respond_get_info_handle)
12082+ gtk_file_system_cancel_operation (impl->should_respond_get_info_handle);
12083
12084- previous_mode = impl->operation_mode;
12085- impl->operation_mode = OPERATION_MODE_RECENT;
12086+ impl->should_respond_get_info_handle =
12087+ gtk_file_system_get_info (impl->file_system, parent_path,
12088+ GTK_FILE_INFO_DISPLAY_NAME,
12089+ confirmation_confirm_get_info_cb,
12090+ data);
12091+ set_busy_cursor (data->impl, TRUE);
12092+ return FALSE;
12093+ }
12094
12095- switch (previous_mode)
12096- {
12097- case OPERATION_MODE_SEARCH:
12098- search_stop_searching (impl, FALSE);
12099- search_clear_model (impl, TRUE);
12100-
12101- gtk_widget_destroy (impl->search_hbox);
12102- impl->search_hbox = NULL;
12103- impl->search_entry = NULL;
12104- break;
12105+ case GTK_FILE_CHOOSER_CONFIRMATION_ACCEPT_FILENAME:
12106+ return TRUE;
12107
12108- case OPERATION_MODE_BROWSE:
12109- stop_loading_and_clear_list_model (impl);
12110- break;
12111+ case GTK_FILE_CHOOSER_CONFIRMATION_SELECT_AGAIN:
12112+ return FALSE;
12113
12114- case OPERATION_MODE_RECENT:
12115+ default:
12116 g_assert_not_reached ();
12117- break;
12118+ return FALSE;
12119 }
12120-
12121- recent_hide_entry (impl);
12122- file_list_set_sort_column_ids (impl);
12123- recent_start_loading (impl);
12124 }
12125
12126-/* convert an iterator coming from the model bound to
12127- * browse_files_tree_view to an interator inside the
12128- * real recent_model
12129- */
12130 static void
12131-recent_get_valid_child_iter (GtkFileChooserDefault *impl,
12132- GtkTreeIter *child_iter,
12133- GtkTreeIter *iter)
12134+action_create_folder_cb (GtkFileSystemHandle *handle,
12135+ const GtkFilePath *path,
12136+ const GError *error,
12137+ gpointer user_data)
12138 {
12139- GtkTreeIter middle;
12140-
12141- if (!impl->recent_model)
12142- return;
12143+ gboolean cancelled = handle->cancelled;
12144+ GtkFileChooserDefault *impl = user_data;
12145
12146- if (!impl->recent_model_filter || !impl->recent_model_sort)
12147- return;
12148+ if (!g_slist_find (impl->pending_handles, handle))
12149+ goto out;
12150
12151- /* pass 1: get the iterator in the filter model */
12152- gtk_tree_model_sort_convert_iter_to_child_iter (impl->recent_model_sort,
12153- &middle, iter);
12154-
12155- /* pass 2: get the iterator in the real model */
12156- gtk_tree_model_filter_convert_iter_to_child_iter (impl->recent_model_filter,
12157- child_iter,
12158- &middle);
12159-}
12160+ impl->pending_handles = g_slist_remove (impl->pending_handles, handle);
12161
12162+ set_busy_cursor (impl, FALSE);
12163
12164-static void
12165-set_current_filter (GtkFileChooserDefault *impl,
12166- GtkFileFilter *filter)
12167-{
12168- if (impl->current_filter != filter)
12169- {
12170- int filter_index;
12171+ if (cancelled)
12172+ goto out;
12173
12174- /* NULL filters are allowed to reset to non-filtered status
12175- */
12176- filter_index = g_slist_index (impl->filters, filter);
12177- if (impl->filters && filter && filter_index < 0)
12178- return;
12179+ if (error)
12180+ error_creating_folder_dialog (impl, path, g_error_copy (error));
12181+ else
12182+ g_signal_emit_by_name (impl, "response-requested");
12183
12184- if (impl->current_filter)
12185- g_object_unref (impl->current_filter);
12186- impl->current_filter = filter;
12187- if (impl->current_filter)
12188- {
12189- g_object_ref_sink (impl->current_filter);
12190- }
12191+out:
12192+ g_object_unref (impl);
12193+ g_object_unref (handle);
12194+}
12195
12196- if (impl->filters)
12197- gtk_combo_box_set_active (GTK_COMBO_BOX (impl->filter_combo),
12198- filter_index);
12199+struct FileExistsData
12200+{
12201+ GtkFileChooserDefault *impl;
12202+ gboolean file_exists_and_is_not_folder;
12203+ GtkFilePath *parent_path;
12204+ GtkFilePath *path;
12205+};
12206
12207- if (impl->browse_files_model)
12208- install_list_model_filter (impl);
12209+static void
12210+save_entry_get_info_cb (GtkFileSystemHandle *handle,
12211+ const GtkFileInfo *info,
12212+ const GError *error,
12213+ gpointer user_data)
12214+{
12215+ gboolean parent_is_folder;
12216+ gboolean cancelled = handle->cancelled;
12217+ struct FileExistsData *data = user_data;
12218
12219- if (impl->search_model_filter)
12220- gtk_tree_model_filter_refilter (impl->search_model_filter);
12221+ if (handle != data->impl->should_respond_get_info_handle)
12222+ goto out;
12223
12224- if (impl->recent_model_filter)
12225- gtk_tree_model_filter_refilter (impl->recent_model_filter);
12226+ data->impl->should_respond_get_info_handle = NULL;
12227
12228- g_object_notify (G_OBJECT (impl), "filter");
12229- }
12230-}
12231+ set_busy_cursor (data->impl, FALSE);
12232
12233-static void
12234-filter_combo_changed (GtkComboBox *combo_box,
12235- GtkFileChooserDefault *impl)
12236-{
12237- gint new_index = gtk_combo_box_get_active (combo_box);
12238- GtkFileFilter *new_filter = g_slist_nth_data (impl->filters, new_index);
12239+ if (cancelled)
12240+ goto out;
12241
12242- set_current_filter (impl, new_filter);
12243-}
12244+ if (!info)
12245+ parent_is_folder = FALSE;
12246+ else
12247+ parent_is_folder = gtk_file_info_get_is_folder (info);
12248
12249-static void
12250-check_preview_change (GtkFileChooserDefault *impl)
12251-{
12252- GtkTreePath *cursor_path;
12253- const GtkFilePath *new_path;
12254- const char *new_display_name;
12255-
12256- gtk_tree_view_get_cursor (GTK_TREE_VIEW (impl->browse_files_tree_view), &cursor_path, NULL);
12257- new_path = NULL;
12258- new_display_name = NULL;
12259- if (cursor_path)
12260+ if (parent_is_folder)
12261 {
12262- GtkTreeIter child_iter;
12263-
12264- if (impl->operation_mode == OPERATION_MODE_BROWSE)
12265- {
12266- if (impl->sort_model)
12267+ if (data->impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
12268+ {
12269+ if (data->file_exists_and_is_not_folder)
12270 {
12271- GtkTreeIter iter;
12272- const GtkFileInfo *new_info;
12273-
12274- gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->sort_model), &iter, cursor_path);
12275- gtk_tree_path_free (cursor_path);
12276+ gboolean retval;
12277+ const char *file_part;
12278
12279- gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model, &child_iter, &iter);
12280+ file_part = _gtk_file_chooser_entry_get_file_part (GTK_FILE_CHOOSER_ENTRY (data->impl->location_entry));
12281+ retval = should_respond_after_confirm_overwrite (data->impl, file_part, data->parent_path);
12282
12283- new_path = _gtk_file_system_model_get_path (impl->browse_files_model, &child_iter);
12284- new_info = _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
12285- if (new_info)
12286- new_display_name = gtk_file_info_get_display_name (new_info);
12287+ if (retval)
12288+ g_signal_emit_by_name (data->impl, "response-requested");
12289 }
12290+ else
12291+ g_signal_emit_by_name (data->impl, "response-requested");
12292 }
12293- else if (impl->operation_mode == OPERATION_MODE_SEARCH)
12294- {
12295- GtkTreeIter iter;
12296-
12297- gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->search_model_sort),
12298- &iter, cursor_path);
12299- gtk_tree_path_free (cursor_path);
12300-
12301- search_get_valid_child_iter (impl, &child_iter, &iter);
12302- gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &child_iter,
12303- SEARCH_MODEL_COL_PATH, &new_path,
12304- SEARCH_MODEL_COL_DISPLAY_NAME, &new_display_name,
12305- -1);
12306- }
12307- else if (impl->operation_mode == OPERATION_MODE_RECENT)
12308+ else /* GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER */
12309 {
12310- GtkTreeIter iter;
12311+ GtkFileSystemHandle *handle;
12312
12313- gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->recent_model_sort),
12314- &iter, cursor_path);
12315- gtk_tree_path_free (cursor_path);
12316-
12317- recent_get_valid_child_iter (impl, &child_iter, &iter);
12318- gtk_tree_model_get (GTK_TREE_MODEL (impl->recent_model), &child_iter,
12319- RECENT_MODEL_COL_PATH, &new_path,
12320- RECENT_MODEL_COL_DISPLAY_NAME, &new_display_name,
12321- -1);
12322+ g_object_ref (data->impl);
12323+ handle = gtk_file_system_create_folder (data->impl->file_system,
12324+ data->path,
12325+ action_create_folder_cb,
12326+ data->impl);
12327+ data->impl->pending_handles = g_slist_append (data->impl->pending_handles, handle);
12328+ set_busy_cursor (data->impl, TRUE);
12329 }
12330 }
12331-
12332- if (new_path != impl->preview_path &&
12333- !(new_path && impl->preview_path &&
12334- gtk_file_path_compare (new_path, impl->preview_path) == 0))
12335+ else
12336 {
12337- if (impl->preview_path)
12338- {
12339- gtk_file_path_free (impl->preview_path);
12340- g_free (impl->preview_display_name);
12341- }
12342-
12343- if (new_path)
12344- {
12345- impl->preview_path = gtk_file_path_copy (new_path);
12346- impl->preview_display_name = g_strdup (new_display_name);
12347- }
12348- else
12349- {
12350- impl->preview_path = NULL;
12351- impl->preview_display_name = NULL;
12352- }
12353+ /* This will display an error, which is what we want */
12354+ change_folder_and_display_error (data->impl, data->parent_path);
12355+ }
12356
12357- if (impl->use_preview_label && impl->preview_label)
12358- gtk_label_set_text (GTK_LABEL (impl->preview_label), impl->preview_display_name);
12359+out:
12360+ g_object_unref (data->impl);
12361+ gtk_file_path_free (data->path);
12362+ gtk_file_path_free (data->parent_path);
12363+ g_free (data);
12364
12365- g_signal_emit_by_name (impl, "update-preview");
12366- }
12367+ g_object_unref (handle);
12368 }
12369
12370 static void
12371-shortcuts_activate_volume_mount_cb (GtkFileSystemHandle *handle,
12372- GtkFileSystemVolume *volume,
12373- const GError *error,
12374- gpointer data)
12375+file_exists_get_info_cb (GtkFileSystemHandle *handle,
12376+ const GtkFileInfo *info,
12377+ const GError *error,
12378+ gpointer user_data)
12379 {
12380- GtkFilePath *path;
12381+ gboolean data_ownership_taken = FALSE;
12382 gboolean cancelled = handle->cancelled;
12383- GtkFileChooserDefault *impl = data;
12384+ gboolean file_exists_and_is_not_folder;
12385+ struct FileExistsData *data = user_data;
12386
12387- if (handle != impl->shortcuts_activate_iter_handle)
12388+ if (handle != data->impl->file_exists_get_info_handle)
12389 goto out;
12390
12391- impl->shortcuts_activate_iter_handle = NULL;
12392+ data->impl->file_exists_get_info_handle = NULL;
12393
12394- set_busy_cursor (impl, FALSE);
12395+ set_busy_cursor (data->impl, FALSE);
12396
12397 if (cancelled)
12398 goto out;
12399
12400- if (error)
12401+ file_exists_and_is_not_folder = info && !gtk_file_info_get_is_folder (info);
12402+
12403+ if (data->impl->action == GTK_FILE_CHOOSER_ACTION_OPEN)
12404+ /* user typed a filename; we are done */
12405+ g_signal_emit_by_name (data->impl, "response-requested");
12406+ else if (data->impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER
12407+ && file_exists_and_is_not_folder)
12408+ {
12409+ /* Oops, the user typed the name of an existing path which is not
12410+ * a folder
12411+ */
12412+ error_creating_folder_over_existing_file_dialog (data->impl, data->path,
12413+ g_error_copy (error));
12414+ }
12415+ else
12416 {
12417- char *msg;
12418+ /* check that everything up to the last component exists */
12419+
12420+ data->file_exists_and_is_not_folder = file_exists_and_is_not_folder;
12421+ data_ownership_taken = TRUE;
12422
12423- msg = g_strdup_printf (_("Could not mount %s"),
12424- gtk_file_system_volume_get_display_name (impl->file_system, volume));
12425- error_message (impl, msg, error->message);
12426- g_free (msg);
12427+ if (data->impl->should_respond_get_info_handle)
12428+ gtk_file_system_cancel_operation (data->impl->should_respond_get_info_handle);
12429
12430- goto out;
12431+ data->impl->should_respond_get_info_handle =
12432+ gtk_file_system_get_info (data->impl->file_system,
12433+ data->parent_path,
12434+ GTK_FILE_INFO_IS_FOLDER,
12435+ save_entry_get_info_cb,
12436+ data);
12437+ set_busy_cursor (data->impl, TRUE);
12438 }
12439
12440- path = gtk_file_system_volume_get_base_path (impl->file_system, volume);
12441- if (path != NULL)
12442+out:
12443+ if (!data_ownership_taken)
12444 {
12445- change_folder_and_display_error (impl, path, FALSE);
12446- focus_browse_tree_view_if_possible (impl);
12447-
12448- gtk_file_path_free (path);
12449+ g_object_unref (data->impl);
12450+ gtk_file_path_free (data->path);
12451+ gtk_file_path_free (data->parent_path);
12452+ g_free (data);
12453 }
12454
12455-out:
12456- g_object_unref (impl);
12457 g_object_unref (handle);
12458 }
12459
12460
12461-/* Activates a volume by mounting it if necessary and then switching to its
12462- * base path.
12463- */
12464-static void
12465-shortcuts_activate_volume (GtkFileChooserDefault *impl,
12466- GtkFileSystemVolume *volume)
12467+/* Implementation for GtkFileChooserEmbed::should_respond() */
12468+static gboolean
12469+gtk_file_chooser_default_should_respond (GtkFileChooserEmbed *chooser_embed)
12470 {
12471- GtkFilePath *path;
12472+ GtkFileChooserDefault *impl;
12473+ GtkWidget *toplevel;
12474+ GtkWidget *current_focus;
12475
12476- switch (impl->operation_mode)
12477- {
12478- case OPERATION_MODE_BROWSE:
12479- break;
12480- case OPERATION_MODE_SEARCH:
12481- search_switch_to_browse_mode (impl);
12482- break;
12483- case OPERATION_MODE_RECENT:
12484- recent_switch_to_browse_mode (impl);
12485- break;
12486- }
12487+ impl = GTK_FILE_CHOOSER_DEFAULT (chooser_embed);
12488
12489- /* We ref the file chooser since volume_mount() may run a main loop, and the
12490- * user could close the file chooser window in the meantime.
12491- */
12492- g_object_ref (impl);
12493+ toplevel = gtk_widget_get_toplevel (GTK_WIDGET (impl));
12494+ g_assert (GTK_IS_WINDOW (toplevel));
12495+
12496+ current_focus = gtk_window_get_focus (GTK_WINDOW (toplevel));
12497
12498- if (!gtk_file_system_volume_get_is_mounted (impl->file_system, volume))
12499+ if (current_focus == impl->browse_files_tree_view)
12500 {
12501- set_busy_cursor (impl, TRUE);
12502+ /* The following array encodes what we do based on the impl->action and the
12503+ * number of files selected.
12504+ */
12505+ typedef enum {
12506+ NOOP, /* Do nothing (don't respond) */
12507+ RESPOND, /* Respond immediately */
12508+ RESPOND_OR_SWITCH, /* Respond immediately if the selected item is a file; switch to it if it is a folder */
12509+ ALL_FILES, /* Respond only if everything selected is a file */
12510+ ALL_FOLDERS, /* Respond only if everything selected is a folder */
12511+ SAVE_ENTRY, /* Go to the code for handling the save entry */
12512+ NOT_REACHED /* Sanity check */
12513+ } ActionToTake;
12514+ static const ActionToTake what_to_do[4][3] = {
12515+ /* 0 selected 1 selected many selected */
12516+ /* ACTION_OPEN */ { NOOP, RESPOND_OR_SWITCH, ALL_FILES },
12517+ /* ACTION_SAVE */ { SAVE_ENTRY, RESPOND_OR_SWITCH, NOT_REACHED },
12518+ /* ACTION_SELECT_FOLDER */ { RESPOND, ALL_FOLDERS, ALL_FOLDERS },
12519+ /* ACTION_CREATE_FOLDER */ { SAVE_ENTRY, ALL_FOLDERS, NOT_REACHED }
12520+ };
12521+
12522+ int num_selected;
12523+ gboolean all_files, all_folders;
12524+ int k;
12525+ ActionToTake action;
12526+
12527+ file_list:
12528+
12529+ g_assert (impl->action >= GTK_FILE_CHOOSER_ACTION_OPEN && impl->action <= GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER);
12530+
12531+ selection_check (impl, &num_selected, &all_files, &all_folders);
12532+
12533+ if (num_selected > 2)
12534+ k = 2;
12535+ else
12536+ k = num_selected;
12537+
12538+ action = what_to_do [impl->action] [k];
12539+
12540+ switch (action)
12541+ {
12542+ case NOOP:
12543+ return FALSE;
12544+
12545+ case RESPOND:
12546+ return TRUE;
12547+
12548+ case RESPOND_OR_SWITCH:
12549+ g_assert (num_selected == 1);
12550+
12551+ if (all_folders)
12552+ {
12553+ switch_to_selected_folder (impl);
12554+ return FALSE;
12555+ }
12556+ else if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
12557+ return should_respond_after_confirm_overwrite (impl,
12558+ get_display_name_from_file_list (impl),
12559+ impl->current_folder);
12560+ else
12561+ return TRUE;
12562+
12563+ case ALL_FILES:
12564+ return all_files;
12565+
12566+ case ALL_FOLDERS:
12567+ return all_folders;
12568+
12569+ case SAVE_ENTRY:
12570+ goto save_entry;
12571
12572- impl->shortcuts_activate_iter_handle =
12573- gtk_file_system_volume_mount (impl->file_system, volume,
12574- shortcuts_activate_volume_mount_cb,
12575- g_object_ref (impl));
12576+ default:
12577+ g_assert_not_reached ();
12578+ }
12579 }
12580- else
12581+ else if ((impl->location_entry != NULL) && (current_focus == impl->location_entry))
12582 {
12583- path = gtk_file_system_volume_get_base_path (impl->file_system, volume);
12584- if (path != NULL)
12585- {
12586- change_folder_and_display_error (impl, path, FALSE);
12587- gtk_file_path_free (path);
12588- }
12589- }
12590+ GtkFilePath *path;
12591+ gboolean is_well_formed, is_empty, is_file_part_empty;
12592+ gboolean is_folder;
12593+ gboolean retval;
12594+ GtkFileChooserEntry *entry;
12595+ GError *error;
12596+
12597+ save_entry:
12598+
12599+ g_assert (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
12600+ || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER
12601+ || impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
12602+ || impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
12603+
12604+ entry = GTK_FILE_CHOOSER_ENTRY (impl->location_entry);
12605+ check_save_entry (impl, &path, &is_well_formed, &is_empty, &is_file_part_empty, &is_folder);
12606+
12607+ if (is_empty || !is_well_formed)
12608+ return FALSE;
12609+
12610+ g_assert (path != NULL);
12611+
12612+ error = NULL;
12613+ if (is_folder)
12614+ {
12615+ if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
12616+ || impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
12617+ {
12618+ change_folder_and_display_error (impl, path);
12619+ retval = FALSE;
12620+ }
12621+ else if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER
12622+ || GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
12623+ {
12624+ /* The folder already exists, so we do not need to create it.
12625+ * Just respond to terminate the dialog.
12626+ */
12627+ retval = TRUE;
12628+ }
12629+ else
12630+ {
12631+ g_assert_not_reached ();
12632+ retval = FALSE;
12633+ }
12634+ }
12635+ else
12636+ {
12637+ struct FileExistsData *data;
12638
12639- g_object_unref (impl);
12640-}
12641+ /* We need to check whether path exists and is not a folder */
12642
12643-/* Opens the folder or volume at the specified iter in the shortcuts model */
12644-struct ShortcutsActivateData
12645-{
12646- GtkFileChooserDefault *impl;
12647- GtkFilePath *path;
12648-};
12649+ data = g_new0 (struct FileExistsData, 1);
12650+ data->impl = g_object_ref (impl);
12651+ data->path = gtk_file_path_copy (path);
12652+ data->parent_path = gtk_file_path_copy (_gtk_file_chooser_entry_get_current_folder (entry));
12653
12654-static void
12655-shortcuts_activate_get_info_cb (GtkFileSystemHandle *handle,
12656- const GtkFileInfo *info,
12657- const GError *error,
12658- gpointer user_data)
12659-{
12660- gboolean cancelled = handle->cancelled;
12661- struct ShortcutsActivateData *data = user_data;
12662+ if (impl->file_exists_get_info_handle)
12663+ gtk_file_system_cancel_operation (impl->file_exists_get_info_handle);
12664
12665- if (handle != data->impl->shortcuts_activate_iter_handle)
12666- goto out;
12667+ impl->file_exists_get_info_handle =
12668+ gtk_file_system_get_info (impl->file_system, path,
12669+ GTK_FILE_INFO_IS_FOLDER,
12670+ file_exists_get_info_cb,
12671+ data);
12672
12673- data->impl->shortcuts_activate_iter_handle = NULL;
12674+ set_busy_cursor (impl, TRUE);
12675+ retval = FALSE;
12676
12677- if (cancelled)
12678- goto out;
12679+ if (error != NULL)
12680+ g_error_free (error);
12681+ }
12682
12683- if (!error && gtk_file_info_get_is_folder (info))
12684+ gtk_file_path_free (path);
12685+ return retval;
12686+ }
12687+ else if (impl->toplevel_last_focus_widget == impl->browse_files_tree_view)
12688+ {
12689+ /* The focus is on a dialog's action area button, *and* the widget that
12690+ * was focused immediately before it is the file list.
12691+ */
12692+ goto file_list;
12693+ }
12694+ else if (impl->location_entry && impl->toplevel_last_focus_widget == impl->location_entry)
12695 {
12696- change_folder_and_display_error (data->impl, data->path, FALSE);
12697- focus_browse_tree_view_if_possible (data->impl);
12698+ /* The focus is on a dialog's action area button, *and* the widget that
12699+ * was focused immediately before it is the location entry.
12700+ */
12701+ goto save_entry;
12702 }
12703 else
12704- gtk_file_chooser_default_select_path (GTK_FILE_CHOOSER (data->impl),
12705- data->path,
12706- NULL);
12707-
12708-out:
12709- g_object_unref (data->impl);
12710- gtk_file_path_free (data->path);
12711- g_free (data);
12712+ /* The focus is on a dialog's action area button or something else */
12713+ if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
12714+ || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
12715+ goto save_entry;
12716+ else
12717+ goto file_list;
12718
12719- g_object_unref (handle);
12720+ g_assert_not_reached ();
12721+ return FALSE;
12722 }
12723
12724+/* Implementation for GtkFileChooserEmbed::initial_focus() */
12725 static void
12726-shortcuts_activate_iter (GtkFileChooserDefault *impl,
12727- GtkTreeIter *iter)
12728+gtk_file_chooser_default_initial_focus (GtkFileChooserEmbed *chooser_embed)
12729 {
12730- gpointer col_data;
12731- ShortcutType shortcut_type;
12732-
12733- if (impl->location_mode == LOCATION_MODE_FILENAME_ENTRY && impl->action != GTK_FILE_CHOOSER_ACTION_SAVE)
12734- _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), "");
12735-
12736- gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), iter,
12737- SHORTCUTS_COL_DATA, &col_data,
12738- SHORTCUTS_COL_TYPE, &shortcut_type,
12739- -1);
12740-
12741- if (impl->shortcuts_activate_iter_handle)
12742- {
12743- gtk_file_system_cancel_operation (impl->shortcuts_activate_iter_handle);
12744- impl->shortcuts_activate_iter_handle = NULL;
12745- }
12746-
12747- if (shortcut_type == SHORTCUT_TYPE_SEPARATOR)
12748- return;
12749- else if (shortcut_type == SHORTCUT_TYPE_VOLUME)
12750- {
12751- GtkFileSystemVolume *volume;
12752+ GtkFileChooserDefault *impl;
12753+ GtkWidget *widget;
12754
12755- volume = col_data;
12756+ impl = GTK_FILE_CHOOSER_DEFAULT (chooser_embed);
12757
12758- shortcuts_activate_volume (impl, volume);
12759- }
12760- else if (shortcut_type == SHORTCUT_TYPE_PATH)
12761+ if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
12762+ || impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
12763 {
12764- struct ShortcutsActivateData *data;
12765-
12766- data = g_new0 (struct ShortcutsActivateData, 1);
12767- data->impl = g_object_ref (impl);
12768- data->path = gtk_file_path_copy (col_data);
12769-
12770- impl->shortcuts_activate_iter_handle =
12771- gtk_file_system_get_info (impl->file_system, data->path,
12772- GTK_FILE_INFO_IS_FOLDER,
12773- shortcuts_activate_get_info_cb, data);
12774+ widget = impl->browse_files_tree_view;
12775 }
12776- else if (shortcut_type == SHORTCUT_TYPE_SEARCH)
12777+ else if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
12778+ || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
12779 {
12780- search_activate (impl);
12781+ widget = impl->location_entry;
12782 }
12783- else if (shortcut_type == SHORTCUT_TYPE_RECENT)
12784+ else
12785 {
12786- recent_activate (impl);
12787+ g_assert_not_reached ();
12788+ widget = NULL;
12789 }
12790+
12791+ g_assert (widget != NULL);
12792+ gtk_widget_grab_focus (widget);
12793 }
12794
12795-/* Callback used when a row in the shortcuts list is activated */
12796 static void
12797-shortcuts_row_activated_cb (GtkTreeView *tree_view,
12798- GtkTreePath *path,
12799- GtkTreeViewColumn *column,
12800- GtkFileChooserDefault *impl)
12801+set_current_filter (GtkFileChooserDefault *impl,
12802+ GtkFileFilter *filter)
12803 {
12804- GtkTreeIter iter;
12805- GtkTreeIter child_iter;
12806-
12807- if (!gtk_tree_model_get_iter (impl->shortcuts_pane_filter_model, &iter, path))
12808- return;
12809+ if (impl->current_filter != filter)
12810+ {
12811+ int filter_index;
12812
12813- gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (impl->shortcuts_pane_filter_model),
12814- &child_iter,
12815- &iter);
12816- shortcuts_activate_iter (impl, &child_iter);
12817-}
12818+ /* NULL filters are allowed to reset to non-filtered status
12819+ */
12820+ filter_index = g_slist_index (impl->filters, filter);
12821+ if (impl->filters && filter && filter_index < 0)
12822+ return;
12823
12824-/* Handler for GtkWidget::key-press-event on the shortcuts list */
12825-static gboolean
12826-shortcuts_key_press_event_cb (GtkWidget *widget,
12827- GdkEventKey *event,
12828- GtkFileChooserDefault *impl)
12829-{
12830- guint modifiers;
12831+ if (impl->current_filter)
12832+ g_object_unref (impl->current_filter);
12833+ impl->current_filter = filter;
12834+ if (impl->current_filter)
12835+ {
12836+ g_object_ref_sink (impl->current_filter);
12837+ }
12838
12839- modifiers = gtk_accelerator_get_default_mod_mask ();
12840+ if (impl->filters)
12841+ gtk_combo_box_set_active (GTK_COMBO_BOX (impl->filter_combo),
12842+ filter_index);
12843
12844- if ((event->keyval == GDK_BackSpace
12845- || event->keyval == GDK_Delete
12846- || event->keyval == GDK_KP_Delete)
12847- && (event->state & modifiers) == 0)
12848- {
12849- remove_selected_bookmarks (impl);
12850- return TRUE;
12851- }
12852+ if (impl->browse_files_model)
12853+ install_list_model_filter (impl);
12854
12855- if ((event->keyval == GDK_F2)
12856- && (event->state & modifiers) == 0)
12857- {
12858- rename_selected_bookmark (impl);
12859- return TRUE;
12860+ g_object_notify (G_OBJECT (impl), "filter");
12861 }
12862-
12863- return FALSE;
12864 }
12865
12866-static gboolean
12867-shortcuts_select_func (GtkTreeSelection *selection,
12868- GtkTreeModel *model,
12869- GtkTreePath *path,
12870- gboolean path_currently_selected,
12871- gpointer data)
12872+static void
12873+filter_combo_changed (GtkComboBox *combo_box,
12874+ GtkFileChooserDefault *impl)
12875 {
12876- GtkFileChooserDefault *impl = data;
12877- GtkTreeIter filter_iter;
12878- ShortcutType shortcut_type;
12879-
12880- if (!gtk_tree_model_get_iter (impl->shortcuts_pane_filter_model, &filter_iter, path))
12881- g_assert_not_reached ();
12882-
12883- gtk_tree_model_get (impl->shortcuts_pane_filter_model, &filter_iter, SHORTCUTS_COL_TYPE, &shortcut_type, -1);
12884+ gint new_index = gtk_combo_box_get_active (combo_box);
12885+ GtkFileFilter *new_filter = g_slist_nth_data (impl->filters, new_index);
12886
12887- return shortcut_type != SHORTCUT_TYPE_SEPARATOR;
12888+ set_current_filter (impl, new_filter);
12889 }
12890
12891 static gboolean
12892@@ -10562,55 +4490,17 @@
12893 impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
12894 {
12895 GtkTreeIter iter, child_iter;
12896+ const GtkFileInfo *info;
12897
12898- switch (impl->operation_mode)
12899- {
12900- case OPERATION_MODE_SEARCH:
12901- {
12902- gboolean is_folder;
12903-
12904- if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->search_model_sort), &iter, path))
12905- return FALSE;
12906-
12907- search_get_valid_child_iter (impl, &child_iter, &iter);
12908- gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &child_iter,
12909- SEARCH_MODEL_COL_IS_FOLDER, &is_folder,
12910- -1);
12911- if (!is_folder)
12912- return FALSE;
12913- }
12914- break;
12915-
12916- case OPERATION_MODE_RECENT:
12917- {
12918- gboolean is_folder;
12919-
12920- if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->recent_model_sort), &iter, path))
12921- return FALSE;
12922-
12923- recent_get_valid_child_iter (impl, &child_iter, &iter);
12924- gtk_tree_model_get (GTK_TREE_MODEL (impl->recent_model), &child_iter,
12925- RECENT_MODEL_COL_IS_FOLDER, &is_folder,
12926- -1);
12927- if (!is_folder)
12928- return FALSE;
12929- }
12930- break;
12931-
12932- case OPERATION_MODE_BROWSE:
12933- {
12934- const GtkFileInfo *info;
12935-
12936- if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->sort_model), &iter, path))
12937- return FALSE;
12938-
12939- gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model, &child_iter, &iter);
12940- info = _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
12941- if (info && !gtk_file_info_get_is_folder (info))
12942- return FALSE;
12943- }
12944- break;
12945- }
12946+ if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->sort_model), &iter, path))
12947+ return FALSE;
12948+
12949+ gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model, &child_iter, &iter);
12950+
12951+ info = _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
12952+
12953+ if (info && !gtk_file_info_get_is_folder (info))
12954+ return FALSE;
12955 }
12956
12957 return TRUE;
12958@@ -10621,8 +4511,7 @@
12959 GtkFileChooserDefault *impl)
12960 {
12961 /* See if we are in the new folder editable row for Save mode */
12962- if (impl->operation_mode == OPERATION_MODE_BROWSE &&
12963- impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
12964+ if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
12965 {
12966 const GtkFileInfo *info;
12967 gboolean had_selection;
12968@@ -10640,9 +4529,6 @@
12969 if (impl->location_entry)
12970 update_chooser_entry (impl);
12971
12972- check_preview_change (impl);
12973- bookmarks_check_add_sensitivity (impl);
12974-
12975 g_signal_emit_by_name (impl, "selection-changed", 0);
12976 }
12977
12978@@ -10653,107 +4539,30 @@
12979 GtkTreeViewColumn *column,
12980 GtkFileChooserDefault *impl)
12981 {
12982- GtkTreeIter iter;
12983- GtkTreeIter child_iter;
12984+ GtkTreeIter iter, child_iter;
12985+ const GtkFileInfo *info;
12986
12987- switch (impl->operation_mode)
12988- {
12989- case OPERATION_MODE_SEARCH:
12990- {
12991- GtkFilePath *file_path;
12992- gboolean is_folder;
12993+ if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->sort_model), &iter, path))
12994+ return;
12995
12996- if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->search_model_sort), &iter, path))
12997- return;
12998+ gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model, &child_iter, &iter);
12999
13000- search_get_valid_child_iter (impl, &child_iter, &iter);
13001- gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &child_iter,
13002- SEARCH_MODEL_COL_PATH, &file_path,
13003- SEARCH_MODEL_COL_IS_FOLDER, &is_folder,
13004- -1);
13005-
13006- if (is_folder)
13007- {
13008- change_folder_and_display_error (impl, file_path, FALSE);
13009- return;
13010- }
13011+ info = _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
13012
13013- g_signal_emit_by_name (impl, "file-activated");
13014- }
13015- break;
13016+ if (gtk_file_info_get_is_folder (info))
13017+ {
13018+ const GtkFilePath *file_path;
13019
13020- case OPERATION_MODE_RECENT:
13021- {
13022- GtkFilePath *file_path;
13023- gboolean is_folder;
13024+ file_path = _gtk_file_system_model_get_path (impl->browse_files_model, &child_iter);
13025
13026- if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->recent_model_sort), &iter, path))
13027- return;
13028-
13029- recent_get_valid_child_iter (impl, &child_iter, &iter);
13030- gtk_tree_model_get (GTK_TREE_MODEL (impl->recent_model), &child_iter,
13031- RECENT_MODEL_COL_PATH, &file_path,
13032- RECENT_MODEL_COL_IS_FOLDER, &is_folder,
13033- -1);
13034-
13035- if (is_folder)
13036- {
13037- change_folder_and_display_error (impl, file_path, FALSE);
13038- return;
13039- }
13040-
13041- g_signal_emit_by_name (impl, "file-activated");
13042- }
13043- break;
13044-
13045- case OPERATION_MODE_BROWSE:
13046- {
13047- const GtkFileInfo *info;
13048+ change_folder_and_display_error (impl, file_path);
13049
13050- if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->sort_model), &iter, path))
13051- return;
13052-
13053- gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model,
13054- &child_iter, &iter);
13055- info = _gtk_file_system_model_get_info (impl->browse_files_model,
13056- &child_iter);
13057-
13058- if (gtk_file_info_get_is_folder (info))
13059- {
13060- const GtkFilePath *file_path;
13061-
13062- file_path = _gtk_file_system_model_get_path (impl->browse_files_model, &child_iter);
13063- change_folder_and_display_error (impl, file_path, FALSE);
13064- return;
13065- }
13066-
13067- if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
13068- impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
13069- g_signal_emit_by_name (impl, "file-activated");
13070- }
13071- break;
13072+ return;
13073 }
13074-}
13075-
13076-static void
13077-path_bar_clicked (GtkPathBar *path_bar,
13078- GtkFilePath *file_path,
13079- GtkFilePath *child_path,
13080- gboolean child_is_hidden,
13081- GtkFileChooserDefault *impl)
13082-{
13083- if (child_path)
13084- pending_select_paths_add (impl, child_path);
13085
13086- if (!change_folder_and_display_error (impl, file_path, FALSE))
13087- return;
13088-
13089- /* Say we have "/foo/bar/[.baz]" and the user clicks on "bar". We should then
13090- * show hidden files so that ".baz" appears in the file list, as it will still
13091- * be shown in the path bar: "/foo/[bar]/.baz"
13092- */
13093- if (child_is_hidden)
13094- g_object_set (impl, "show-hidden", TRUE, NULL);
13095+ if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
13096+ impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
13097+ g_signal_emit_by_name (impl, "file-activated");
13098 }
13099
13100 static const GtkFileInfo *
13101@@ -10778,83 +4587,40 @@
13102 {
13103 GtkFileChooserDefault *impl = data;
13104 GtkTreeIter child_iter;
13105- GdkPixbuf *pixbuf = NULL;
13106+ const GtkFilePath *path;
13107+ GdkPixbuf *pixbuf;
13108+ const GtkFileInfo *info;
13109 gboolean sensitive = TRUE;
13110
13111 profile_start ("start", NULL);
13112
13113- switch (impl->operation_mode)
13114- {
13115- case OPERATION_MODE_SEARCH:
13116- {
13117- GtkTreeIter child_iter;
13118- gboolean is_folder;
13119-
13120- search_get_valid_child_iter (impl, &child_iter, iter);
13121- gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &child_iter,
13122- SEARCH_MODEL_COL_PIXBUF, &pixbuf,
13123- SEARCH_MODEL_COL_IS_FOLDER, &is_folder,
13124- -1);
13125-
13126- if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
13127- impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
13128- sensitive = is_folder;
13129- }
13130- break;
13131+ info = get_list_file_info (impl, iter);
13132
13133- case OPERATION_MODE_RECENT:
13134- {
13135- GtkTreeIter child_iter;
13136- GtkRecentInfo *info;
13137- gboolean is_folder;
13138-
13139- recent_get_valid_child_iter (impl, &child_iter, iter);
13140- gtk_tree_model_get (GTK_TREE_MODEL (impl->recent_model), &child_iter,
13141- RECENT_MODEL_COL_INFO, &info,
13142- RECENT_MODEL_COL_IS_FOLDER, &is_folder,
13143- -1);
13144-
13145- pixbuf = gtk_recent_info_get_icon (info, impl->icon_size);
13146-
13147- if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
13148- impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
13149- sensitive = is_folder;
13150- }
13151- break;
13152-
13153- case OPERATION_MODE_BROWSE:
13154- {
13155- const GtkFileInfo *info;
13156- const GtkFilePath *path;
13157+ gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model,
13158+ &child_iter,
13159+ iter);
13160+ path = _gtk_file_system_model_get_path (impl->browse_files_model, &child_iter);
13161
13162- info = get_list_file_info (impl, iter);
13163+ if (path)
13164+ {
13165+ pixbuf = NULL;
13166
13167- gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model,
13168- &child_iter,
13169- iter);
13170- path = _gtk_file_system_model_get_path (impl->browse_files_model, &child_iter);
13171- if (path)
13172- {
13173- if (info)
13174- {
13175- /* FIXME: NULL GError */
13176- pixbuf = gtk_file_info_render_icon (info, GTK_WIDGET (impl),
13177- impl->icon_size, NULL);
13178- }
13179- }
13180- else
13181- {
13182- /* We are on the editable row */
13183- pixbuf = NULL;
13184- }
13185-
13186- if (info &&
13187- (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
13188- impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER))
13189- sensitive = gtk_file_info_get_is_folder (info);
13190- }
13191- break;
13192+ if (info)
13193+ {
13194+ /* FIXME: NULL GError */
13195+ pixbuf = gtk_file_info_render_icon (info, GTK_WIDGET (impl),
13196+ impl->icon_size, NULL);
13197+ }
13198+ }
13199+ else
13200+ {
13201+ /* We are on the editable row */
13202+ pixbuf = NULL;
13203 }
13204+
13205+ if (info && (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
13206+ impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER))
13207+ sensitive = gtk_file_info_get_is_folder (info);
13208
13209 g_object_set (cell,
13210 "pixbuf", pixbuf,
13211@@ -10864,96 +4630,32 @@
13212 if (pixbuf)
13213 g_object_unref (pixbuf);
13214
13215- profile_end ("end", NULL);
13216-}
13217-
13218-static void
13219-list_name_data_func (GtkTreeViewColumn *tree_column,
13220- GtkCellRenderer *cell,
13221- GtkTreeModel *tree_model,
13222- GtkTreeIter *iter,
13223- gpointer data)
13224-{
13225- GtkFileChooserDefault *impl = data;
13226- const GtkFileInfo *info;
13227- gboolean sensitive = TRUE;
13228-
13229- if (impl->operation_mode == OPERATION_MODE_SEARCH)
13230- {
13231- GtkTreeIter child_iter;
13232- gchar *display_name;
13233- gboolean is_folder;
13234-
13235- search_get_valid_child_iter (impl, &child_iter, iter);
13236- gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &child_iter,
13237- SEARCH_MODEL_COL_DISPLAY_NAME, &display_name,
13238- SEARCH_MODEL_COL_IS_FOLDER, &is_folder,
13239- -1);
13240-
13241- if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
13242- impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
13243- {
13244- sensitive = is_folder;
13245- }
13246-
13247- g_object_set (cell,
13248- "text", display_name,
13249- "sensitive", sensitive,
13250- "ellipsize", PANGO_ELLIPSIZE_END,
13251- NULL);
13252-
13253- return;
13254- }
13255-
13256- if (impl->operation_mode == OPERATION_MODE_RECENT)
13257- {
13258- GtkTreeIter child_iter;
13259- GtkRecentInfo *recent_info;
13260- gchar *display_name;
13261- gboolean is_folder;
13262-
13263- recent_get_valid_child_iter (impl, &child_iter, iter);
13264- gtk_tree_model_get (GTK_TREE_MODEL (impl->recent_model), &child_iter,
13265- RECENT_MODEL_COL_INFO, &recent_info,
13266- RECENT_MODEL_COL_IS_FOLDER, &is_folder,
13267- -1);
13268-
13269- display_name = gtk_recent_info_get_short_name (recent_info);
13270-
13271- if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
13272- impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
13273- {
13274- sensitive = is_folder;
13275- }
13276-
13277- g_object_set (cell,
13278- "text", display_name,
13279- "sensitive", sensitive,
13280- "ellipsize", PANGO_ELLIPSIZE_END,
13281- NULL);
13282-
13283- g_free (display_name);
13284-
13285- return;
13286- }
13287-
13288- info = get_list_file_info (impl, iter);
13289- sensitive = TRUE;
13290+ profile_end ("end", NULL);
13291+}
13292+
13293+static void
13294+list_name_data_func (GtkTreeViewColumn *tree_column,
13295+ GtkCellRenderer *cell,
13296+ GtkTreeModel *tree_model,
13297+ GtkTreeIter *iter,
13298+ gpointer data)
13299+{
13300+ GtkFileChooserDefault *impl = data;
13301+ const GtkFileInfo *info = get_list_file_info (impl, iter);
13302+ gboolean sensitive = TRUE;
13303
13304 if (!info)
13305 {
13306 g_object_set (cell,
13307 "text", _("Type name of new folder"),
13308- "sensitive", TRUE,
13309- "ellipsize", PANGO_ELLIPSIZE_NONE,
13310 NULL);
13311
13312 return;
13313 }
13314
13315
13316- if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
13317- impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
13318+ if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER
13319+ || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
13320 {
13321 sensitive = gtk_file_info_get_is_folder (info);
13322 }
13323@@ -10961,7 +4663,6 @@
13324 g_object_set (cell,
13325 "text", gtk_file_info_get_display_name (info),
13326 "sensitive", sensitive,
13327- "ellipsize", PANGO_ELLIPSIZE_END,
13328 NULL);
13329 }
13330
13331@@ -11023,142 +4724,64 @@
13332 gpointer data)
13333 {
13334 GtkFileChooserDefault *impl;
13335- time_t time_mtime;
13336- gchar *date_str = NULL;
13337+ const GtkFileInfo *info;
13338+ GtkFileTime time_mtime;
13339+ GDate mtime, now;
13340+ int days_diff;
13341+ char buf[256];
13342 gboolean sensitive = TRUE;
13343
13344 impl = data;
13345
13346- if (impl->operation_mode == OPERATION_MODE_SEARCH)
13347- {
13348- GtkTreeIter child_iter;
13349- struct stat *statbuf;
13350- gboolean is_folder;
13351-
13352- search_get_valid_child_iter (impl, &child_iter, iter);
13353- gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &child_iter,
13354- SEARCH_MODEL_COL_STAT, &statbuf,
13355- SEARCH_MODEL_COL_IS_FOLDER, &is_folder,
13356- -1);
13357- if (statbuf)
13358- time_mtime = statbuf->st_mtime;
13359- else
13360- time_mtime = 0;
13361-
13362-
13363- if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
13364- impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
13365- sensitive = is_folder;
13366- }
13367- else if (impl->operation_mode == OPERATION_MODE_RECENT)
13368+ info = get_list_file_info (impl, iter);
13369+ if (!info)
13370 {
13371- GtkTreeIter child_iter;
13372- GtkRecentInfo *info;
13373- gboolean is_folder;
13374-
13375- recent_get_valid_child_iter (impl, &child_iter, iter);
13376- gtk_tree_model_get (GTK_TREE_MODEL (impl->recent_model), &child_iter,
13377- RECENT_MODEL_COL_INFO, &info,
13378- RECENT_MODEL_COL_IS_FOLDER, &is_folder,
13379- -1);
13380-
13381- if (info)
13382- time_mtime = gtk_recent_info_get_modified (info);
13383- else
13384- time_mtime = 0;
13385-
13386- if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
13387- impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
13388- sensitive = is_folder;
13389+ g_object_set (cell,
13390+ "text", "",
13391+ "sensitive", TRUE,
13392+ NULL);
13393+ return;
13394 }
13395- else
13396- {
13397- const GtkFileInfo *info;
13398-
13399- info = get_list_file_info (impl, iter);
13400- if (!info)
13401- {
13402- g_object_set (cell,
13403- "text", "",
13404- "sensitive", TRUE,
13405- NULL);
13406- return;
13407- }
13408-
13409- time_mtime = (time_t) gtk_file_info_get_modification_time (info);
13410
13411- if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
13412- impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
13413- sensitive = gtk_file_info_get_is_folder (info);
13414- }
13415+ time_mtime = gtk_file_info_get_modification_time (info);
13416
13417- if (G_UNLIKELY (time_mtime == 0))
13418- date_str = g_strdup (_("Unknown"));
13419+ if (time_mtime == 0)
13420+ strcpy (buf, _("Unknown"));
13421 else
13422 {
13423- GDate mtime, now;
13424- gint days_diff;
13425- struct tm tm_mtime;
13426 time_t time_now;
13427- const gchar *format;
13428- gchar *locale_format = NULL;
13429- gchar buf[256];
13430-
13431-#ifdef HAVE_LOCALTIME_R
13432- localtime_r ((time_t *) &time_mtime, &tm_mtime);
13433-#else
13434- {
13435- struct tm *ptm = localtime ((time_t *) &time_mtime);
13436-
13437- if (!ptm)
13438- {
13439- g_warning ("ptm != NULL failed");
13440-
13441- g_object_set (cell,
13442- "text", _("Unknown"),
13443- "sensitive", sensitive,
13444- NULL);
13445- return;
13446- }
13447- else
13448- memcpy ((void *) &tm_mtime, (void *) ptm, sizeof (struct tm));
13449- }
13450-#endif /* HAVE_LOCALTIME_R */
13451-
13452 g_date_set_time_t (&mtime, time_mtime);
13453 time_now = time (NULL);
13454 g_date_set_time_t (&now, time_now);
13455
13456 days_diff = g_date_get_julian (&now) - g_date_get_julian (&mtime);
13457
13458- /* Translators: %H means "hours" and %M means "minutes" */
13459 if (days_diff == 0)
13460- format = _("Today at %H:%M");
13461+ strcpy (buf, _("Today"));
13462 else if (days_diff == 1)
13463- format = _("Yesterday at %H:%M");
13464+ strcpy (buf, _("Yesterday"));
13465 else
13466 {
13467+ char *format;
13468+
13469 if (days_diff > 1 && days_diff < 7)
13470 format = "%A"; /* Days from last week */
13471 else
13472 format = "%x"; /* Any other date */
13473- }
13474-
13475- locale_format = g_locale_from_utf8 (format, -1, NULL, NULL, NULL);
13476
13477- if (strftime (buf, sizeof (buf), locale_format, &tm_mtime) != 0)
13478- date_str = g_locale_to_utf8 (buf, -1, NULL, NULL, NULL);
13479- else
13480- date_str = g_strdup (_("Unknown"));
13481-
13482- g_free (locale_format);
13483+ if (g_date_strftime (buf, sizeof (buf), format, &mtime) == 0)
13484+ strcpy (buf, _("Unknown"));
13485+ }
13486 }
13487
13488+ if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
13489+ impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
13490+ sensitive = gtk_file_info_get_is_folder (info);
13491+
13492 g_object_set (cell,
13493- "text", date_str,
13494+ "text", buf,
13495 "sensitive", sensitive,
13496 NULL);
13497- g_free (date_str);
13498 }
13499
13500 GtkWidget *
13501@@ -11169,437 +4792,73 @@
13502 NULL);
13503 }
13504
13505-static void
13506-location_set_user_text (GtkFileChooserDefault *impl,
13507- const gchar *path)
13508-{
13509- _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), path);
13510- gtk_editable_set_position (GTK_EDITABLE (impl->location_entry), -1);
13511-}
13512-
13513-static void
13514-location_popup_handler (GtkFileChooserDefault *impl,
13515- const gchar *path)
13516-{
13517- if (impl->operation_mode != OPERATION_MODE_BROWSE)
13518- {
13519- GtkWidget *widget_to_focus;
13520-
13521- /* This will give us the location widgets back */
13522- switch (impl->operation_mode)
13523- {
13524- case OPERATION_MODE_SEARCH:
13525- search_switch_to_browse_mode (impl);
13526- break;
13527- case OPERATION_MODE_RECENT:
13528- recent_switch_to_browse_mode (impl);
13529- break;
13530- case OPERATION_MODE_BROWSE:
13531- g_assert_not_reached ();
13532- break;
13533- }
13534-
13535- if (impl->current_folder)
13536- change_folder_and_display_error (impl, impl->current_folder, FALSE);
13537-
13538- if (impl->location_mode == LOCATION_MODE_PATH_BAR)
13539- widget_to_focus = impl->browse_files_tree_view;
13540- else
13541- widget_to_focus = impl->location_entry;
13542-
13543- gtk_widget_grab_focus (widget_to_focus);
13544- return;
13545- }
13546-
13547- if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
13548- impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
13549- {
13550- LocationMode new_mode;
13551-
13552- if (path != NULL)
13553- {
13554- /* since the user typed something, we unconditionally want to turn on the entry */
13555- new_mode = LOCATION_MODE_FILENAME_ENTRY;
13556- }
13557- else if (impl->location_mode == LOCATION_MODE_PATH_BAR)
13558- new_mode = LOCATION_MODE_FILENAME_ENTRY;
13559- else if (impl->location_mode == LOCATION_MODE_FILENAME_ENTRY)
13560- new_mode = LOCATION_MODE_PATH_BAR;
13561- else
13562- {
13563- g_assert_not_reached ();
13564- return;
13565- }
13566-
13567- location_mode_set (impl, new_mode, TRUE);
13568- if (new_mode == LOCATION_MODE_FILENAME_ENTRY)
13569- {
13570- if (path != NULL)
13571- location_set_user_text (impl, path);
13572- else
13573- {
13574- location_entry_set_initial_text (impl);
13575- gtk_editable_select_region (GTK_EDITABLE (impl->location_entry), 0, -1);
13576- }
13577- }
13578- }
13579- else if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE ||
13580- impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
13581- {
13582- gtk_widget_grab_focus (impl->location_entry);
13583- if (path != NULL)
13584- location_set_user_text (impl, path);
13585- }
13586- else
13587- g_assert_not_reached ();
13588-}
13589-
13590 /* Handler for the "up-folder" keybinding signal */
13591 static void
13592 up_folder_handler (GtkFileChooserDefault *impl)
13593 {
13594- _gtk_path_bar_up (GTK_PATH_BAR (impl->browse_path_bar));
13595+ GtkFilePath * parent;
13596+ pending_select_paths_add (impl, impl->current_folder);
13597+
13598+ if (gtk_file_system_get_parent (impl->file_system, impl->current_folder,
13599+ &parent, NULL) && parent)
13600+ {
13601+ impl->path_history = g_slist_prepend (impl->path_history,
13602+ gtk_file_path_copy (impl->current_folder));
13603+
13604+ change_folder_and_display_error (impl, parent);
13605+ gtk_file_path_free (parent);
13606+ }
13607 }
13608
13609 /* Handler for the "down-folder" keybinding signal */
13610 static void
13611 down_folder_handler (GtkFileChooserDefault *impl)
13612 {
13613- _gtk_path_bar_down (GTK_PATH_BAR (impl->browse_path_bar));
13614-}
13615-
13616-/* Switches to the shortcut in the specified index */
13617-static void
13618-switch_to_shortcut (GtkFileChooserDefault *impl,
13619- int pos)
13620-{
13621- GtkTreeIter iter;
13622-
13623- if (!gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (impl->shortcuts_model), &iter, NULL, pos))
13624- g_assert_not_reached ();
13625-
13626- shortcuts_activate_iter (impl, &iter);
13627- focus_browse_tree_view_if_possible (impl);
13628+ if (impl->path_history)
13629+ {
13630+ GtkFilePath * path = impl->path_history->data;
13631+
13632+ change_folder_and_display_error (impl, path);
13633+ impl->path_history = g_slist_remove (impl->path_history, path);
13634+ gtk_file_path_free (path);
13635+ }
13636 }
13637
13638 /* Handler for the "home-folder" keybinding signal */
13639 static void
13640 home_folder_handler (GtkFileChooserDefault *impl)
13641 {
13642- if (impl->has_home)
13643- switch_to_shortcut (impl, shortcuts_get_index (impl, SHORTCUTS_HOME));
13644-}
13645-
13646-/* Handler for the "desktop-folder" keybinding signal */
13647-static void
13648-desktop_folder_handler (GtkFileChooserDefault *impl)
13649-{
13650- if (impl->has_desktop)
13651- switch_to_shortcut (impl, shortcuts_get_index (impl, SHORTCUTS_DESKTOP));
13652-}
13653-
13654-/* Handler for the "search-shortcut" keybinding signal */
13655-static void
13656-search_shortcut_handler (GtkFileChooserDefault *impl)
13657-{
13658- if (impl->has_search)
13659- {
13660- switch_to_shortcut (impl, shortcuts_get_index (impl, SHORTCUTS_SEARCH));
13661-
13662- /* we want the entry widget to grab the focus the first
13663- * time, not the browse_files_tree_view widget.
13664- */
13665- if (impl->search_entry)
13666- gtk_widget_grab_focus (impl->search_entry);
13667- }
13668-}
13669-
13670-/* Handler for the "recent-shortcut" keybinding signal */
13671-static void
13672-recent_shortcut_handler (GtkFileChooserDefault *impl)
13673-{
13674- if (impl->has_recent)
13675- switch_to_shortcut (impl, shortcuts_get_index (impl, SHORTCUTS_RECENT));
13676-}
13677-
13678-static void
13679-quick_bookmark_handler (GtkFileChooserDefault *impl,
13680- gint bookmark_index)
13681-{
13682- int bookmark_pos;
13683- GtkTreePath *path;
13684-
13685- if (bookmark_index < 0 || bookmark_index >= impl->num_bookmarks)
13686- return;
13687-
13688- bookmark_pos = shortcuts_get_index (impl, SHORTCUTS_BOOKMARKS) + bookmark_index;
13689-
13690- path = gtk_tree_path_new_from_indices (bookmark_pos, -1);
13691- gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view),
13692- path, NULL,
13693- FALSE, 0.0, 0.0);
13694- gtk_tree_path_free (path);
13695-
13696- switch_to_shortcut (impl, bookmark_pos);
13697 }
13698
13699 static void
13700 show_hidden_handler (GtkFileChooserDefault *impl)
13701 {
13702- g_object_set (impl,
13703- "show-hidden", !impl->show_hidden,
13704- NULL);
13705-}
13706-
13707-
13708-/* Drag and drop interfaces */
13709-
13710-static void
13711-_shortcuts_pane_model_filter_class_init (ShortcutsPaneModelFilterClass *class)
13712-{
13713-}
13714-
13715-static void
13716-_shortcuts_pane_model_filter_init (ShortcutsPaneModelFilter *model)
13717-{
13718- model->impl = NULL;
13719-}
13720-
13721-/* GtkTreeDragSource::row_draggable implementation for the shortcuts filter model */
13722-static gboolean
13723-shortcuts_pane_model_filter_row_draggable (GtkTreeDragSource *drag_source,
13724- GtkTreePath *path)
13725-{
13726- ShortcutsPaneModelFilter *model;
13727- int pos;
13728- int bookmarks_pos;
13729-
13730- model = SHORTCUTS_PANE_MODEL_FILTER (drag_source);
13731-
13732- pos = *gtk_tree_path_get_indices (path);
13733- bookmarks_pos = shortcuts_get_index (model->impl, SHORTCUTS_BOOKMARKS);
13734-
13735- return (pos >= bookmarks_pos && pos < bookmarks_pos + model->impl->num_bookmarks);
13736-}
13737-
13738-/* GtkTreeDragSource::drag_data_get implementation for the shortcuts filter model */
13739-static gboolean
13740-shortcuts_pane_model_filter_drag_data_get (GtkTreeDragSource *drag_source,
13741- GtkTreePath *path,
13742- GtkSelectionData *selection_data)
13743-{
13744- ShortcutsPaneModelFilter *model;
13745-
13746- model = SHORTCUTS_PANE_MODEL_FILTER (drag_source);
13747-
13748- /* FIXME */
13749-
13750- return FALSE;
13751-}
13752-
13753-/* Fill the GtkTreeDragSourceIface vtable */
13754-static void
13755-shortcuts_pane_model_filter_drag_source_iface_init (GtkTreeDragSourceIface *iface)
13756-{
13757- iface->row_draggable = shortcuts_pane_model_filter_row_draggable;
13758- iface->drag_data_get = shortcuts_pane_model_filter_drag_data_get;
13759-}
13760-
13761-#if 0
13762-/* Fill the GtkTreeDragDestIface vtable */
13763-static void
13764-shortcuts_pane_model_filter_drag_dest_iface_init (GtkTreeDragDestIface *iface)
13765-{
13766- iface->drag_data_received = shortcuts_pane_model_filter_drag_data_received;
13767- iface->row_drop_possible = shortcuts_pane_model_filter_row_drop_possible;
13768-}
13769-#endif
13770-
13771-static GtkTreeModel *
13772-shortcuts_pane_model_filter_new (GtkFileChooserDefault *impl,
13773- GtkTreeModel *child_model,
13774- GtkTreePath *root)
13775-{
13776- ShortcutsPaneModelFilter *model;
13777-
13778- model = g_object_new (SHORTCUTS_PANE_MODEL_FILTER_TYPE,
13779- "child-model", child_model,
13780- "virtual-root", root,
13781- NULL);
13782-
13783- model->impl = impl;
13784-
13785- return GTK_TREE_MODEL (model);
13786-}
13787-
13788-
13789-
13790-static gboolean
13791-recent_model_sort_row_draggable (GtkTreeDragSource *drag_source,
13792- GtkTreePath *path)
13793-{
13794- RecentModelSort *model;
13795- GtkTreeIter iter, child_iter;
13796- gboolean is_folder;
13797-
13798- model = RECENT_MODEL_SORT (drag_source);
13799- if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path))
13800- return FALSE;
13801-
13802- recent_get_valid_child_iter (model->impl, &child_iter, &iter);
13803- gtk_tree_model_get (GTK_TREE_MODEL (model->impl->recent_model), &child_iter,
13804- RECENT_MODEL_COL_IS_FOLDER, &is_folder,
13805- -1);
13806-
13807- return is_folder;
13808-}
13809-
13810-static gboolean
13811-recent_model_sort_drag_data_get (GtkTreeDragSource *drag_source,
13812- GtkTreePath *path,
13813- GtkSelectionData *selection_data)
13814-{
13815- RecentModelSort *model;
13816- GtkTreeIter iter, child_iter;
13817- GtkFilePath *file_path;
13818- gchar **uris;
13819-
13820- model = RECENT_MODEL_SORT (drag_source);
13821- if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path))
13822- return FALSE;
13823-
13824- recent_get_valid_child_iter (model->impl, &child_iter, &iter);
13825- gtk_tree_model_get (GTK_TREE_MODEL (model->impl->recent_model), &child_iter,
13826- RECENT_MODEL_COL_PATH, &file_path,
13827- -1);
13828- g_assert (file_path != NULL);
13829-
13830- uris = g_new (gchar *, 2);
13831- uris[0] = gtk_file_system_path_to_uri (model->impl->file_system, file_path);
13832- uris[1] = NULL;
13833-
13834- gtk_selection_data_set_uris (selection_data, uris);
13835-
13836- g_strfreev (uris);
13837-
13838- return TRUE;
13839-}
13840-
13841-static void
13842-recent_model_sort_drag_source_iface_init (GtkTreeDragSourceIface *iface)
13843-{
13844- iface->row_draggable = recent_model_sort_row_draggable;
13845- iface->drag_data_get = recent_model_sort_drag_data_get;
13846-}
13847-
13848-static void
13849-_recent_model_sort_class_init (RecentModelSortClass *klass)
13850-{
13851-
13852-}
13853-
13854-static void
13855-_recent_model_sort_init (RecentModelSort *model)
13856-{
13857- model->impl = NULL;
13858 }
13859
13860-static GtkTreeModel *
13861-recent_model_sort_new (GtkFileChooserDefault *impl,
13862- GtkTreeModel *child_model)
13863+static GtkFilePath *
13864+gtk_file_chooser_default_get_preview_path (GtkFileChooser *chooser)
13865 {
13866- RecentModelSort *model;
13867-
13868- model = g_object_new (RECENT_MODEL_SORT_TYPE,
13869- "model", child_model,
13870- NULL);
13871- model->impl = impl;
13872-
13873- return GTK_TREE_MODEL (model);
13874+ return NULL;
13875 }
13876
13877-
13878-
13879 static gboolean
13880-search_model_sort_row_draggable (GtkTreeDragSource *drag_source,
13881- GtkTreePath *path)
13882+gtk_file_chooser_default_add_shortcut_folder (GtkFileChooser *chooser,
13883+ const GtkFilePath *path,
13884+ GError **error)
13885 {
13886- SearchModelSort *model;
13887- GtkTreeIter iter, child_iter;
13888- gboolean is_folder;
13889-
13890- model = SEARCH_MODEL_SORT (drag_source);
13891- if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path))
13892 return FALSE;
13893-
13894- search_get_valid_child_iter (model->impl, &child_iter, &iter);
13895- gtk_tree_model_get (GTK_TREE_MODEL (model->impl->search_model), &child_iter,
13896- SEARCH_MODEL_COL_IS_FOLDER, &is_folder,
13897- -1);
13898-
13899- return is_folder;
13900 }
13901
13902 static gboolean
13903-search_model_sort_drag_data_get (GtkTreeDragSource *drag_source,
13904- GtkTreePath *path,
13905- GtkSelectionData *selection_data)
13906-{
13907- SearchModelSort *model;
13908- GtkTreeIter iter, child_iter;
13909- GtkFilePath *file_path;
13910- gchar **uris;
13911-
13912- model = SEARCH_MODEL_SORT (drag_source);
13913- if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path))
13914- return FALSE;
13915-
13916- search_get_valid_child_iter (model->impl, &child_iter, &iter);
13917- gtk_tree_model_get (GTK_TREE_MODEL (model->impl->search_model), &child_iter,
13918- RECENT_MODEL_COL_PATH, &file_path,
13919- -1);
13920- g_assert (file_path != NULL);
13921-
13922- uris = g_new (gchar *, 2);
13923- uris[0] = gtk_file_system_path_to_uri (model->impl->file_system, file_path);
13924- uris[1] = NULL;
13925-
13926- gtk_selection_data_set_uris (selection_data, uris);
13927-
13928- g_strfreev (uris);
13929-
13930- return TRUE;
13931-}
13932-
13933-static void
13934-search_model_sort_drag_source_iface_init (GtkTreeDragSourceIface *iface)
13935-{
13936- iface->row_draggable = search_model_sort_row_draggable;
13937- iface->drag_data_get = search_model_sort_drag_data_get;
13938-}
13939-
13940-static void
13941-_search_model_sort_class_init (SearchModelSortClass *klass)
13942-{
13943-
13944-}
13945-
13946-static void
13947-_search_model_sort_init (SearchModelSort *model)
13948+gtk_file_chooser_default_remove_shortcut_folder (GtkFileChooser *chooser,
13949+ const GtkFilePath *path,
13950+ GError **error)
13951 {
13952- model->impl = NULL;
13953+ return TRUE;
13954 }
13955
13956-static GtkTreeModel *
13957-search_model_sort_new (GtkFileChooserDefault *impl,
13958- GtkTreeModel *child_model)
13959+static GSList *
13960+gtk_file_chooser_default_list_shortcut_folders (GtkFileChooser *chooser)
13961 {
13962- SearchModelSort *model;
13963-
13964- model = g_object_new (SEARCH_MODEL_SORT_TYPE,
13965- "model", child_model,
13966- NULL);
13967- model->impl = impl;
13968-
13969- return GTK_TREE_MODEL (model);
13970+ return NULL;
13971 }
13972Index: gtk+-2.12.3/gtk/gtkfilechooserprivate.h
13973===================================================================
13974--- gtk+-2.12.3.orig/gtk/gtkfilechooserprivate.h 2007-12-04 16:52:08.000000000 +0000
13975+++ gtk+-2.12.3/gtk/gtkfilechooserprivate.h 2008-01-04 10:11:20.000000000 +0000
13976@@ -25,9 +25,6 @@
13977 #include "gtkfilesystem.h"
13978 #include "gtkfilesystemmodel.h"
13979 #include "gtkliststore.h"
13980-#include "gtkrecentmanager.h"
13981-#include "gtksearchengine.h"
13982-#include "gtkquery.h"
13983 #include "gtktooltips.h"
13984 #include "gtktreemodelsort.h"
13985 #include "gtktreestore.h"
13986@@ -146,12 +143,6 @@
13987 LOCATION_MODE_FILENAME_ENTRY
13988 } LocationMode;
13989
13990-typedef enum {
13991- OPERATION_MODE_BROWSE,
13992- OPERATION_MODE_SEARCH,
13993- OPERATION_MODE_RECENT
13994-} OperationMode;
13995-
13996 struct _GtkFileChooserDefault
13997 {
13998 GtkVBox parent_instance;
13999@@ -162,53 +153,19 @@
14000
14001 /* Save mode widgets */
14002 GtkWidget *save_widgets;
14003-
14004- GtkWidget *save_folder_label;
14005- GtkWidget *save_folder_combo;
14006- GtkWidget *save_expander;
14007+ GtkWidget *save_file_name_entry;
14008
14009 /* The file browsing widgets */
14010 GtkWidget *browse_widgets;
14011- GtkWidget *browse_shortcuts_tree_view;
14012- GtkWidget *browse_shortcuts_add_button;
14013- GtkWidget *browse_shortcuts_remove_button;
14014- GtkWidget *browse_shortcuts_popup_menu;
14015- GtkWidget *browse_shortcuts_popup_menu_remove_item;
14016- GtkWidget *browse_shortcuts_popup_menu_rename_item;
14017 GtkWidget *browse_files_tree_view;
14018- GtkWidget *browse_files_popup_menu;
14019- GtkWidget *browse_files_popup_menu_add_shortcut_item;
14020- GtkWidget *browse_files_popup_menu_hidden_files_item;
14021 GtkWidget *browse_new_folder_button;
14022- GtkWidget *browse_path_bar_hbox;
14023- GtkWidget *browse_path_bar;
14024+ GtkWidget *bar;
14025+ GtkWidget *up_button;
14026
14027 GtkFileSystemModel *browse_files_model;
14028- char *browse_files_last_selected_name;
14029+ char *browse_files_last_selected_name; /* ??? */
14030
14031- /* OPERATION_MODE_SEARCH */
14032- GtkWidget *search_hbox;
14033- GtkWidget *search_entry;
14034- GtkSearchEngine *search_engine;
14035- GtkQuery *search_query;
14036- GtkListStore *search_model;
14037- GtkTreeModelFilter *search_model_filter;
14038- GtkTreeModelSort *search_model_sort;
14039-
14040- /* OPERATION_MODE_RECENT */
14041- GtkRecentManager *recent_manager;
14042- GtkListStore *recent_model;
14043- guint load_recent_id;
14044- GtkTreeModelFilter *recent_model_filter;
14045- GtkTreeModelSort *recent_model_sort;
14046-
14047- GtkWidget *filter_combo_hbox;
14048 GtkWidget *filter_combo;
14049- GtkWidget *preview_box;
14050- GtkWidget *preview_label;
14051- GtkWidget *preview_widget;
14052- GtkWidget *extra_align;
14053- GtkWidget *extra_widget;
14054
14055 GtkWidget *location_button;
14056 GtkWidget *location_entry_box;
14057@@ -217,23 +174,13 @@
14058 LocationMode location_mode;
14059
14060 GtkListStore *shortcuts_model;
14061-
14062- /* Filter for the shortcuts pane. We filter out the "current folder" row and
14063- * the separator that we use for the "Save in folder" combo.
14064- */
14065- GtkTreeModel *shortcuts_pane_filter_model;
14066-
14067- /* Filter for the "Save in folder" combo. We filter out the Search row and
14068- * its separator.
14069- */
14070- GtkTreeModel *shortcuts_combo_filter_model;
14071+ GtkTreeModel *shortcuts_filter_model;
14072
14073 GtkTreeModelSort *sort_model;
14074
14075 /* Handles */
14076 GSList *loading_shortcuts;
14077 GSList *reload_icon_handles;
14078- GtkFileSystemHandle *file_list_drag_data_received_handle;
14079 GtkFileSystemHandle *update_current_folder_handle;
14080 GtkFileSystemHandle *show_and_select_paths_handle;
14081 GtkFileSystemHandle *should_respond_get_info_handle;
14082@@ -246,9 +193,8 @@
14083 ReloadState reload_state;
14084 guint load_timeout_id;
14085
14086- OperationMode operation_mode;
14087-
14088 GSList *pending_select_paths;
14089+ GSList *path_history;
14090
14091 GtkFileFilter *current_filter;
14092 GSList *filters;
14093@@ -256,20 +202,16 @@
14094 GtkTooltips *tooltips;
14095
14096 int num_volumes;
14097- int num_shortcuts;
14098- int num_bookmarks;
14099
14100 gulong volumes_changed_id;
14101- gulong bookmarks_changed_id;
14102
14103 GtkFilePath *current_volume_path;
14104 GtkFilePath *current_folder;
14105- GtkFilePath *preview_path;
14106- char *preview_display_name;
14107
14108 GtkTreeViewColumn *list_name_column;
14109 GtkCellRenderer *list_name_renderer;
14110- GtkTreeViewColumn *list_mtime_column;
14111+ guint32 list_press_time;
14112+ GtkTreePath *list_press_path;
14113
14114 GSource *edited_idle;
14115 char *edited_new_text;
14116@@ -280,10 +222,7 @@
14117 gulong toplevel_set_focus_id;
14118 GtkWidget *toplevel_last_focus_widget;
14119
14120-#if 0
14121- GdkDragContext *shortcuts_drag_context;
14122- GSource *shortcuts_drag_outside_idle;
14123-#endif
14124+ gchar * root_folder;
14125
14126 gint default_width;
14127 gint default_height;
14128@@ -291,23 +230,13 @@
14129 /* Flags */
14130
14131 guint local_only : 1;
14132- guint preview_widget_active : 1;
14133- guint use_preview_label : 1;
14134 guint select_multiple : 1;
14135 guint show_hidden : 1;
14136+ guint show_create_folder : 1;
14137 guint do_overwrite_confirmation : 1;
14138 guint list_sort_ascending : 1;
14139 guint changing_folder : 1;
14140- guint shortcuts_current_folder_active : 1;
14141 guint expand_folders : 1;
14142- guint has_home : 1;
14143- guint has_desktop : 1;
14144- guint has_search : 1;
14145- guint has_recent : 1;
14146-
14147-#if 0
14148- guint shortcuts_drag_outside : 1;
14149-#endif
14150 };
14151
14152
14153Index: gtk+-2.12.3/tests/autotestfilechooser.c
14154===================================================================
14155--- gtk+-2.12.3.orig/tests/autotestfilechooser.c 2007-12-04 16:52:18.000000000 +0000
14156+++ gtk+-2.12.3/tests/autotestfilechooser.c 2008-01-02 13:26:09.000000000 +0000
14157@@ -510,9 +510,6 @@
14158 && (impl->location_mode == LOCATION_MODE_PATH_BAR
14159 ? impl->location_entry == NULL
14160 : impl->location_entry != NULL)
14161- && impl->save_folder_label == NULL
14162- && impl->save_folder_combo == NULL
14163- && impl->save_expander == NULL
14164 && GTK_IS_CONTAINER (impl->browse_widgets) && GTK_WIDGET_DRAWABLE (impl->browse_widgets));
14165 }
14166 else if (has_action (save_actions, G_N_ELEMENTS (save_actions), impl->action))
14167@@ -523,9 +520,6 @@
14168 */
14169 passed = passed && (GTK_IS_CONTAINER (impl->save_widgets) && GTK_WIDGET_DRAWABLE (impl->save_widgets)
14170 && impl->location_entry != NULL && GTK_WIDGET_DRAWABLE (impl->location_entry)
14171- && GTK_IS_LABEL (impl->save_folder_label) && GTK_WIDGET_DRAWABLE (impl->save_folder_label)
14172- && GTK_IS_COMBO_BOX (impl->save_folder_combo) && GTK_WIDGET_DRAWABLE (impl->save_folder_combo)
14173- && GTK_IS_EXPANDER (impl->save_expander) && GTK_WIDGET_DRAWABLE (impl->save_expander)
14174 && GTK_IS_CONTAINER (impl->browse_widgets));
14175
14176 /* FIXME: we are in a SAVE mode; test the visibility and sensitivity of
14177@@ -1026,11 +1020,6 @@
14178 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), base_dir);
14179 sleep_in_main_loop (500);
14180
14181- g_signal_emit_by_name (impl->browse_path_bar, "path-clicked",
14182- (GtkFilePath *) cwd_path,
14183- (GtkFilePath *) base_dir_path,
14184- FALSE);
14185- sleep_in_main_loop (500);
14186 passed = passed && (gtk_file_chooser_get_filter (GTK_FILE_CHOOSER (dialog)) == txt_filter);
14187
14188 log_test (passed, "test_folder_switch_and_filters(): filter after changing folder");
diff --git a/meta/packages/gtk+/gtk+-2.12.3/filechooser-utils.patch b/meta/packages/gtk+/gtk+-2.12.3/filechooser-utils.patch
new file mode 100644
index 0000000000..45cfd4fd60
--- /dev/null
+++ b/meta/packages/gtk+/gtk+-2.12.3/filechooser-utils.patch
@@ -0,0 +1,32 @@
1Index: gtk+-2.12.3/gtk/gtkfilechooserutils.h
2===================================================================
3--- gtk+-2.12.3.orig/gtk/gtkfilechooserutils.h 2007-12-04 16:52:08.000000000 +0000
4+++ gtk+-2.12.3/gtk/gtkfilechooserutils.h 2008-01-02 13:15:17.000000000 +0000
5@@ -41,7 +41,9 @@
6 GTK_FILE_CHOOSER_PROP_SELECT_MULTIPLE,
7 GTK_FILE_CHOOSER_PROP_SHOW_HIDDEN,
8 GTK_FILE_CHOOSER_PROP_DO_OVERWRITE_CONFIRMATION,
9- GTK_FILE_CHOOSER_PROP_LAST = GTK_FILE_CHOOSER_PROP_DO_OVERWRITE_CONFIRMATION
10+ GTK_FILE_CHOOSER_PROP_ROOT_FOLDER,
11+ GTK_FILE_CHOOSER_PROP_SHOW_CREATE_FOLDER,
12+ GTK_FILE_CHOOSER_PROP_LAST = GTK_FILE_CHOOSER_PROP_SHOW_CREATE_FOLDER
13 } GtkFileChooserProp;
14
15 void _gtk_file_chooser_install_properties (GObjectClass *klass);
16Index: gtk+-2.12.3/gtk/gtkfilechooserutils.c
17===================================================================
18--- gtk+-2.12.3.orig/gtk/gtkfilechooserutils.c 2007-12-04 16:52:08.000000000 +0000
19+++ gtk+-2.12.3/gtk/gtkfilechooserutils.c 2008-01-02 13:15:17.000000000 +0000
20@@ -117,6 +117,12 @@
21 g_object_class_override_property (klass,
22 GTK_FILE_CHOOSER_PROP_DO_OVERWRITE_CONFIRMATION,
23 "do-overwrite-confirmation");
24+ g_object_class_override_property (klass,
25+ GTK_FILE_CHOOSER_PROP_ROOT_FOLDER,
26+ "root-folder");
27+ g_object_class_override_property (klass,
28+ GTK_FILE_CHOOSER_PROP_SHOW_CREATE_FOLDER,
29+ "show-create-folder");
30 }
31
32 /**
diff --git a/meta/packages/gtk+/gtk+-2.12.3/filechooser.patch b/meta/packages/gtk+/gtk+-2.12.3/filechooser.patch
new file mode 100644
index 0000000000..c422f60d49
--- /dev/null
+++ b/meta/packages/gtk+/gtk+-2.12.3/filechooser.patch
@@ -0,0 +1,25 @@
1Index: gtk+-2.12.3/gtk/gtkfilechooser.c
2===================================================================
3--- gtk+-2.12.3.orig/gtk/gtkfilechooser.c 2007-12-04 16:52:08.000000000 +0000
4+++ gtk+-2.12.3/gtk/gtkfilechooser.c 2008-01-02 13:15:38.000000000 +0000
5@@ -272,6 +272,20 @@
6 "if necessary."),
7 FALSE,
8 GTK_PARAM_READWRITE));
9+
10+ g_object_interface_install_property (g_iface,
11+ g_param_spec_string ("root-folder",
12+ P_("File System Root"),
13+ P_("Root folder for the file system below which the user should not be able to switch"),
14+ NULL,
15+ G_PARAM_WRITABLE));
16+
17+ g_object_interface_install_property (g_iface,
18+ g_param_spec_boolean ("show-create-folder",
19+ P_("Show Create Folder button"),
20+ P_("Whether the Create Folder button should be visible on the bar"),
21+ TRUE,
22+ G_PARAM_READWRITE));
23 }
24
25 /**
diff --git a/meta/packages/gtk+/gtk+-2.12.3/filesystem-volumes.patch b/meta/packages/gtk+/gtk+-2.12.3/filesystem-volumes.patch
new file mode 100644
index 0000000000..826fd6bee0
--- /dev/null
+++ b/meta/packages/gtk+/gtk+-2.12.3/filesystem-volumes.patch
@@ -0,0 +1,198 @@
1Index: gtk+-2.12.3/gtk/gtkfilesystemunix.c
2===================================================================
3--- gtk+-2.12.3.orig/gtk/gtkfilesystemunix.c 2007-12-04 16:52:08.000000000 +0000
4+++ gtk+-2.12.3/gtk/gtkfilesystemunix.c 2008-01-02 13:15:02.000000000 +0000
5@@ -38,6 +38,7 @@
6 #include <errno.h>
7 #include <string.h>
8 #include <sys/stat.h>
9+#include <sys/statvfs.h>
10 #include <sys/types.h>
11 #include <pwd.h>
12 #ifdef HAVE_UNISTD_H
13@@ -474,7 +475,55 @@
14 static GSList *
15 gtk_file_system_unix_list_volumes (GtkFileSystem *file_system)
16 {
17- return g_slist_append (NULL, get_root_volume ());
18+ struct statvfs stv;
19+ struct stat st;
20+ GSList * l = g_slist_append (NULL, get_root_volume ());
21+
22+ if (!statvfs ("/.", &stv))
23+ {
24+ fsblkcnt_t root_blocks = stv.f_blocks;
25+ fsfilcnt_t root_files = stv.f_files;
26+
27+ GDir * dir;
28+ if ((dir = g_dir_open ("/media", 0, NULL)) != NULL)
29+ {
30+ const gchar * name;
31+ while ((name = g_dir_read_name (dir)) != NULL)
32+ {
33+ gchar * abs_name;
34+
35+ /* Skip ram disks */
36+ if (!strcmp (name, "ram"))
37+ continue;
38+
39+ abs_name = g_strconcat ("/media/", name, NULL);
40+
41+ if (!stat (abs_name, &st) && S_ISDIR (st.st_mode))
42+ {
43+ gchar * dot = g_strconcat (abs_name, "/.", NULL);
44+ if (!statvfs (dot, &stv) &&
45+ (stv.f_blocks != root_blocks ||
46+ stv.f_files != root_files))
47+ {
48+ GtkFilePath * path =
49+ gtk_file_system_filename_to_path (file_system,
50+ abs_name);
51+
52+ if (path)
53+ l = g_slist_append (l, path);
54+ }
55+
56+ g_free (dot);
57+ }
58+
59+ g_free (abs_name);
60+ }
61+
62+ g_dir_close (dir);
63+ }
64+ }
65+
66+ return l;
67 }
68
69 static GtkFileSystemVolume *
70@@ -488,13 +537,18 @@
71 remove_trailing_slash (const char *filename)
72 {
73 int len;
74-
75+
76 len = strlen (filename);
77
78- if (len > 1 && filename[len - 1] == '/')
79- return g_strndup (filename, len - 1);
80- else
81- return g_memdup (filename, len + 1);
82+ if (len > 1)
83+ {
84+ gchar *c = g_utf8_prev_char (filename + len);
85+
86+ if (c && *c == '/')
87+ return g_strndup (filename, len - 1);
88+ }
89+
90+ return g_memdup (filename, len + 1);
91 }
92
93 /* Delay callback dispatching
94@@ -1128,7 +1182,7 @@
95 gtk_file_system_unix_volume_get_base_path (GtkFileSystem *file_system,
96 GtkFileSystemVolume *volume)
97 {
98- return gtk_file_path_new_dup ("/");
99+ return gtk_file_path_copy ((GtkFilePath*)volume);
100 }
101
102 static gboolean
103@@ -1162,7 +1216,32 @@
104 gtk_file_system_unix_volume_get_display_name (GtkFileSystem *file_system,
105 GtkFileSystemVolume *volume)
106 {
107- return g_strdup (_("File System")); /* Same as Nautilus */
108+ gchar * slash;
109+ gchar * path;
110+ gchar * c;
111+
112+ g_return_val_if_fail (file_system && volume, NULL);
113+
114+ path = gtk_file_system_path_to_filename (file_system, (GtkFilePath*) volume);
115+
116+ g_return_val_if_fail (path && *path, NULL);
117+
118+ if (path[0] == '/' && !path[1])
119+ return g_strdup (_("Filesystem")); /* Same as Nautilus */
120+
121+ /* Now the media volumes */
122+ /* strip trailing / if any */
123+ c = g_utf8_prev_char (path + strlen(path));
124+
125+ if (*c == '/')
126+ *c = 0;
127+
128+ slash = g_utf8_strrchr (path, -1, '/');
129+
130+ if (!slash)
131+ return g_strdup (path);
132+
133+ return g_strdup (slash + 1);
134 }
135
136 static IconType
137@@ -1250,10 +1329,57 @@
138 GtkFileSystemVolume *volume,
139 GError **error)
140 {
141- /* FIXME: maybe we just always want to return GTK_STOCK_HARDDISK here?
142- * or the new tango icon name?
143- */
144- return g_strdup ("gnome-dev-harddisk");
145+ gchar * c;
146+ gchar * slash;
147+ gchar * path = NULL;
148+ GtkFilePath * fpath;
149+ const gchar * id = NULL;
150+
151+ g_return_val_if_fail (file_system && volume, NULL);
152+
153+ fpath = gtk_file_system_volume_get_base_path (file_system, volume);
154+
155+ if (!fpath)
156+ goto out;
157+
158+ path = gtk_file_system_path_to_filename (file_system, fpath);
159+ gtk_file_path_free (fpath);
160+
161+ if (!path || !*path || (*path == '/' && !path[1]))
162+ goto out;
163+
164+ /* Now the media volumes */
165+ /* strip trailing / if any */
166+ c = g_utf8_prev_char (path + strlen(path));
167+
168+ if (*c == '/')
169+ *c = 0;
170+
171+ slash = g_utf8_strrchr (path, -1, '/');
172+
173+ if (slash)
174+ {
175+ slash++;
176+
177+ if (!strcmp (slash, "card"))
178+ id = "gnome-dev-media-sdmmc";
179+ else if (!strcmp (slash, "cf"))
180+ id = "gnome-dev-media-cf";
181+ else if (!strncmp (slash, "mmc", 3))
182+ id = "gnome-dev-media-sdmmc";
183+ else if (!strcmp (slash, "usbhdd"))
184+ id = "gnome-dev-removable-usb";
185+ else
186+ id = "gnome-dev-removable";
187+ }
188+
189+ out:
190+ g_free (path);
191+
192+ if (!id)
193+ id = "gnome-fs-blockdev";
194+
195+ return g_strdup (id);
196 }
197
198 static char *
diff --git a/meta/packages/gtk+/gtk+_2.12.3.bb b/meta/packages/gtk+/gtk+_2.12.3.bb
index 2060dc2bc2..398f01ba0e 100644
--- a/meta/packages/gtk+/gtk+_2.12.3.bb
+++ b/meta/packages/gtk+/gtk+_2.12.3.bb
@@ -1,10 +1,10 @@
1require gtk+.inc 1require gtk+.inc
2 2
3DEPENDS += "cairo" 3DEPENDS += "cairo"
4PR = "r2" 4PR = "r3"
5 5
6# disable per default - untested and not all patches included. 6# disable per default - untested and not all patches included.
7DEFAULT_PREFERENCE = "-1" 7DEFAULT_PREFERENCE = "-1"
8 8
9SRC_URI = "http://download.gnome.org/sources/gtk+/2.12/gtk+-${PV}.tar.bz2 \ 9SRC_URI = "http://download.gnome.org/sources/gtk+/2.12/gtk+-${PV}.tar.bz2 \
10 file://xsettings.patch;patch=1 \ 10 file://xsettings.patch;patch=1 \
@@ -12,16 +12,21 @@ SRC_URI = "http://download.gnome.org/sources/gtk+/2.12/gtk+-${PV}.tar.bz2 \
12 file://disable-print.patch;patch=1 \ 12 file://disable-print.patch;patch=1 \
13 file://hardcoded_libtool.patch;patch=1 \ 13 file://hardcoded_libtool.patch;patch=1 \
14 file://no-demos.patch;patch=1 \ 14 file://no-demos.patch;patch=1 \
15 file://cellrenderer-cairo.patch;patch=1;pnum=0 \ 15 file://cellrenderer-cairo.patch;patch=1;pnum=0 \
16 file://entry-cairo.patch;patch=1;pnum=0 \ 16 file://entry-cairo.patch;patch=1;pnum=0 \
17 file://toggle-font.diff;patch=1;pnum=0 \ 17 file://toggle-font.diff;patch=1;pnum=0 \
18 file://scrolled-placement.patch;patch=1;pnum=0" 18 file://scrolled-placement.patch;patch=1;pnum=0 \
19 file://filesystem-volumes.patch;patch=1 \
20 file://filechooser-utils.patch;patch=1 \
21 file://filechooser.patch;patch=1 \
22 file://filechooser-default.patch;patch=1 \
19# temporary 23# temporary
20# file://gtklabel-resize-patch;patch=1 \ 24# file://gtklabel-resize-patch;patch=1 \
21# file://menu-deactivate.patch;patch=1 \ 25# file://menu-deactivate.patch;patch=1 \
22# file://combo-arrow-size.patch;patch=1;pnum=0 \ 26# file://combo-arrow-size.patch;patch=1;pnum=0 \
23# die die die 27# die die die
24# file://pangoxft2.10.6.diff;patch=1" 28# file://pangoxft2.10.6.diff;patch=1 \
29 "
25 30
26EXTRA_OECONF = "--without-libtiff --disable-xkb --disable-glibtest --enable-display-migration" 31EXTRA_OECONF = "--without-libtiff --disable-xkb --disable-glibtest --enable-display-migration"
27 32