1 /* GTK - The GIMP Toolkit
2 * gtkfilechooserimpldefault.c: Default implementation of GtkFileChooser
3 * Copyright (C) 2003, Red Hat, Inc.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
21 #include "gtkfilechooserimpldefault.h"
22 #include "gtkfilechooserentry.h"
23 #include "gtkfilechooserenums.h"
24 #include "gtkfilechooserutils.h"
25 #include "gtkfilechooser.h"
26 #include "gtkfilesystemmodel.h"
28 #include <gtk/gtkalignment.h>
29 #include <gtk/gtkcellrendererpixbuf.h>
30 #include <gtk/gtkcellrenderertext.h>
31 #include <gtk/gtkentry.h>
32 #include <gtk/gtkframe.h>
33 #include <gtk/gtkhbox.h>
34 #include <gtk/gtkhpaned.h>
35 #include <gtk/gtkicontheme.h>
36 #include <gtk/gtklabel.h>
37 #include <gtk/gtkmenuitem.h>
38 #include <gtk/gtkoptionmenu.h>
39 #include <gtk/gtkscrolledwindow.h>
40 #include <gtk/gtktable.h>
41 #include <gtk/gtktreeview.h>
42 #include <gtk/gtktreemodelsort.h>
43 #include <gtk/gtktreeselection.h>
44 #include <gtk/gtkvbox.h>
49 typedef struct _GtkFileChooserImplDefaultClass GtkFileChooserImplDefaultClass;
51 #define GTK_FILE_CHOOSER_IMPL_DEFAULT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_FILE_CHOOSER_IMPL_DEFAULT, GtkFileChooserImplDefaultClass))
52 #define GTK_IS_FILE_CHOOSER_IMPL_DEFAULT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_FILE_CHOOSER_IMPL_DEFAULT))
53 #define GTK_FILE_CHOOSER_IMPL_DEFAULT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_FILE_CHOOSER_IMPL_DEFAULT, GtkFileChooserImplDefaultClass))
55 struct _GtkFileChooserImplDefaultClass
57 GtkVBoxClass parent_class;
60 struct _GtkFileChooserImplDefault
62 GtkVBox parent_instance;
64 GtkFileSystem *file_system;
65 GtkFileSystemModel *tree_model;
66 GtkFileSystemModel *list_model;
67 GtkTreeModelSort *sort_model;
69 GtkFileChooserAction action;
71 GtkFileFilter *current_filter;
74 GtkFilePath *current_folder;
75 GtkFilePath *preview_path;
77 GtkWidget *preview_frame;
79 guint folder_mode : 1;
81 guint preview_widget_active : 1;
82 guint select_multiple : 1;
83 guint show_hidden : 1;
85 GtkWidget *filter_alignment;
86 GtkWidget *filter_option_menu;
87 GtkWidget *tree_scrollwin;
89 GtkWidget *list_scrollwin;
92 GtkWidget *preview_widget;
93 GtkWidget *extra_widget;
96 static void gtk_file_chooser_impl_default_class_init (GtkFileChooserImplDefaultClass *class);
97 static void gtk_file_chooser_impl_default_iface_init (GtkFileChooserIface *iface);
98 static void gtk_file_chooser_impl_default_init (GtkFileChooserImplDefault *impl);
100 static GObject* gtk_file_chooser_impl_default_constructor (GType type,
101 guint n_construct_properties,
102 GObjectConstructParam *construct_params);
103 static void gtk_file_chooser_impl_default_finalize (GObject *object);
104 static void gtk_file_chooser_impl_default_set_property (GObject *object,
108 static void gtk_file_chooser_impl_default_get_property (GObject *object,
112 static void gtk_file_chooser_impl_default_show_all (GtkWidget *widget);
114 static void gtk_file_chooser_impl_default_set_current_folder (GtkFileChooser *chooser,
115 const GtkFilePath *path);
116 static GtkFilePath * gtk_file_chooser_impl_default_get_current_folder (GtkFileChooser *chooser);
117 static void gtk_file_chooser_impl_default_set_current_name (GtkFileChooser *chooser,
119 static void gtk_file_chooser_impl_default_select_path (GtkFileChooser *chooser,
120 const GtkFilePath *path);
121 static void gtk_file_chooser_impl_default_unselect_path (GtkFileChooser *chooser,
122 const GtkFilePath *path);
123 static void gtk_file_chooser_impl_default_select_all (GtkFileChooser *chooser);
124 static void gtk_file_chooser_impl_default_unselect_all (GtkFileChooser *chooser);
125 static GSList * gtk_file_chooser_impl_default_get_paths (GtkFileChooser *chooser);
126 static GtkFilePath * gtk_file_chooser_impl_default_get_preview_path (GtkFileChooser *chooser);
127 static GtkFileSystem *gtk_file_chooser_impl_default_get_file_system (GtkFileChooser *chooser);
128 static void gtk_file_chooser_impl_default_add_filter (GtkFileChooser *chooser,
129 GtkFileFilter *filter);
130 static void gtk_file_chooser_impl_default_remove_filter (GtkFileChooser *chooser,
131 GtkFileFilter *filter);
132 static GSList * gtk_file_chooser_impl_default_list_filters (GtkFileChooser *chooser);
134 static void set_current_filter (GtkFileChooserImplDefault *impl,
135 GtkFileFilter *filter);
136 static void check_preview_change (GtkFileChooserImplDefault *impl);
138 static void filter_option_menu_changed (GtkOptionMenu *option_menu,
139 GtkFileChooserImplDefault *impl);
140 static void tree_selection_changed (GtkTreeSelection *tree_selection,
141 GtkFileChooserImplDefault *impl);
142 static void list_selection_changed (GtkTreeSelection *tree_selection,
143 GtkFileChooserImplDefault *impl);
144 static void list_row_activated (GtkTreeView *tree_view,
146 GtkTreeViewColumn *column,
147 GtkFileChooserImplDefault *impl);
148 static void entry_activate (GtkEntry *entry,
149 GtkFileChooserImplDefault *impl);
151 static void tree_name_data_func (GtkTreeViewColumn *tree_column,
152 GtkCellRenderer *cell,
153 GtkTreeModel *tree_model,
156 static void list_icon_data_func (GtkTreeViewColumn *tree_column,
157 GtkCellRenderer *cell,
158 GtkTreeModel *tree_model,
161 static void list_name_data_func (GtkTreeViewColumn *tree_column,
162 GtkCellRenderer *cell,
163 GtkTreeModel *tree_model,
167 static void list_size_data_func (GtkTreeViewColumn *tree_column,
168 GtkCellRenderer *cell,
169 GtkTreeModel *tree_model,
173 static void list_mtime_data_func (GtkTreeViewColumn *tree_column,
174 GtkCellRenderer *cell,
175 GtkTreeModel *tree_model,
179 static GObjectClass *parent_class;
182 _gtk_file_chooser_impl_default_get_type (void)
184 static GType file_chooser_impl_default_type = 0;
186 if (!file_chooser_impl_default_type)
188 static const GTypeInfo file_chooser_impl_default_info =
190 sizeof (GtkFileChooserImplDefaultClass),
191 NULL, /* base_init */
192 NULL, /* base_finalize */
193 (GClassInitFunc) gtk_file_chooser_impl_default_class_init,
194 NULL, /* class_finalize */
195 NULL, /* class_data */
196 sizeof (GtkFileChooserImplDefault),
198 (GInstanceInitFunc) gtk_file_chooser_impl_default_init,
201 static const GInterfaceInfo file_chooser_info =
203 (GInterfaceInitFunc) gtk_file_chooser_impl_default_iface_init, /* interface_init */
204 NULL, /* interface_finalize */
205 NULL /* interface_data */
208 file_chooser_impl_default_type = g_type_register_static (GTK_TYPE_VBOX, "GtkFileChooserImplDefault",
209 &file_chooser_impl_default_info, 0);
210 g_type_add_interface_static (file_chooser_impl_default_type,
211 GTK_TYPE_FILE_CHOOSER,
215 return file_chooser_impl_default_type;
219 gtk_file_chooser_impl_default_class_init (GtkFileChooserImplDefaultClass *class)
221 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
222 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
224 parent_class = g_type_class_peek_parent (class);
226 gobject_class->finalize = gtk_file_chooser_impl_default_finalize;
227 gobject_class->constructor = gtk_file_chooser_impl_default_constructor;
228 gobject_class->set_property = gtk_file_chooser_impl_default_set_property;
229 gobject_class->get_property = gtk_file_chooser_impl_default_get_property;
231 widget_class->show_all = gtk_file_chooser_impl_default_show_all;
233 _gtk_file_chooser_install_properties (gobject_class);
237 gtk_file_chooser_impl_default_iface_init (GtkFileChooserIface *iface)
239 iface->select_path = gtk_file_chooser_impl_default_select_path;
240 iface->unselect_path = gtk_file_chooser_impl_default_unselect_path;
241 iface->select_all = gtk_file_chooser_impl_default_select_all;
242 iface->unselect_all = gtk_file_chooser_impl_default_unselect_all;
243 iface->get_paths = gtk_file_chooser_impl_default_get_paths;
244 iface->get_preview_path = gtk_file_chooser_impl_default_get_preview_path;
245 iface->get_file_system = gtk_file_chooser_impl_default_get_file_system;
246 iface->set_current_folder = gtk_file_chooser_impl_default_set_current_folder;
247 iface->get_current_folder = gtk_file_chooser_impl_default_get_current_folder;
248 iface->set_current_name = gtk_file_chooser_impl_default_set_current_name;
249 iface->add_filter = gtk_file_chooser_impl_default_add_filter;
250 iface->remove_filter = gtk_file_chooser_impl_default_remove_filter;
251 iface->list_filters = gtk_file_chooser_impl_default_list_filters;
255 gtk_file_chooser_impl_default_init (GtkFileChooserImplDefault *impl)
257 impl->folder_mode = FALSE;
258 impl->local_only = TRUE;
259 impl->preview_widget_active = TRUE;
260 impl->select_multiple = FALSE;
261 impl->show_hidden = FALSE;
263 gtk_container_set_border_width (GTK_CONTAINER (impl), 5);
267 gtk_file_chooser_impl_default_finalize (GObject *object)
269 GtkFileChooserImplDefault *impl = GTK_FILE_CHOOSER_IMPL_DEFAULT (object);
271 g_object_unref (impl->file_system);
273 G_OBJECT_CLASS (parent_class)->finalize (object);
277 update_preview_widget_visibility (GtkFileChooserImplDefault *impl)
279 if (impl->preview_widget_active && impl->preview_widget)
280 gtk_widget_show (impl->preview_frame);
282 gtk_widget_hide (impl->preview_frame);
286 set_preview_widget (GtkFileChooserImplDefault *impl,
287 GtkWidget *preview_widget)
289 if (preview_widget == impl->preview_widget)
292 if (impl->preview_widget)
293 gtk_container_remove (GTK_CONTAINER (impl->preview_frame),
294 impl->preview_widget);
296 impl->preview_widget = preview_widget;
297 if (impl->preview_widget)
299 gtk_widget_show (impl->preview_widget);
300 gtk_container_add (GTK_CONTAINER (impl->preview_frame),
301 impl->preview_widget);
304 update_preview_widget_visibility (impl);
307 /* Creates the widgets for the filter option menu */
309 create_filter (GtkFileChooserImplDefault *impl)
314 impl->filter_alignment = gtk_alignment_new (0.0, 0.5, 0.0, 1.0);
315 gtk_alignment_set_padding (GTK_ALIGNMENT (impl->filter_alignment), 0, 6, 0, 0);
316 /* Don't show filter initially -- don't gtk_widget_show() the filter_alignment here */
318 hbox = gtk_hbox_new (FALSE, 6);
319 gtk_container_add (GTK_CONTAINER (impl->filter_alignment), hbox);
320 gtk_widget_show (hbox);
322 label = gtk_label_new_with_mnemonic ("Files of _type:");
323 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
324 gtk_widget_show (label);
326 impl->filter_option_menu = gtk_option_menu_new ();
327 gtk_option_menu_set_menu (GTK_OPTION_MENU (impl->filter_option_menu),
329 gtk_box_pack_start (GTK_BOX (hbox), impl->filter_option_menu, FALSE, FALSE, 0);
330 gtk_widget_show (impl->filter_option_menu);
332 gtk_label_set_mnemonic_widget (GTK_LABEL (label), impl->filter_option_menu);
334 g_signal_connect (impl->filter_option_menu, "changed",
335 G_CALLBACK (filter_option_menu_changed), impl);
337 return impl->filter_alignment;
340 /* Creates the widgets for the folder tree */
342 create_folder_tree (GtkFileChooserImplDefault *impl)
344 GtkTreeSelection *selection;
346 /* Scrolled window */
348 impl->tree_scrollwin = gtk_scrolled_window_new (NULL, NULL);
349 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (impl->tree_scrollwin),
350 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
351 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (impl->tree_scrollwin),
353 gtk_widget_show (impl->tree_scrollwin);
357 impl->tree = gtk_tree_view_new ();
358 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (impl->tree), FALSE);
360 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->tree));
361 g_signal_connect (selection, "changed",
362 G_CALLBACK (tree_selection_changed), impl);
364 gtk_container_add (GTK_CONTAINER (impl->tree_scrollwin), impl->tree);
365 gtk_widget_show (impl->tree);
369 impl->tree_model = _gtk_file_system_model_new (impl->file_system, NULL, -1,
370 GTK_FILE_INFO_DISPLAY_NAME);
371 _gtk_file_system_model_set_show_files (impl->tree_model, FALSE);
373 gtk_tree_view_set_model (GTK_TREE_VIEW (impl->tree),
374 GTK_TREE_MODEL (impl->tree_model));
378 gtk_tree_view_insert_column_with_data_func (GTK_TREE_VIEW (impl->tree), 0,
380 gtk_cell_renderer_text_new (),
381 tree_name_data_func, impl, NULL);
382 gtk_tree_view_set_search_column (GTK_TREE_VIEW (impl->tree),
383 GTK_FILE_SYSTEM_MODEL_DISPLAY_NAME);
385 return impl->tree_scrollwin;
388 /* Creates the widgets for the folder tree */
390 create_file_list (GtkFileChooserImplDefault *impl)
392 GtkTreeSelection *selection;
393 GtkTreeViewColumn *column;
394 GtkCellRenderer *renderer;
396 /* Scrolled window */
398 impl->list_scrollwin = gtk_scrolled_window_new (NULL, NULL);
399 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (impl->list_scrollwin),
400 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
401 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (impl->list_scrollwin),
403 gtk_widget_show (impl->list_scrollwin);
407 impl->list = gtk_tree_view_new ();
408 gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (impl->list), TRUE);
409 gtk_container_add (GTK_CONTAINER (impl->list_scrollwin), impl->list);
410 g_signal_connect (impl->list, "row_activated",
411 G_CALLBACK (list_row_activated), impl);
412 gtk_widget_show (impl->list);
414 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->list));
415 g_signal_connect (selection, "changed",
416 G_CALLBACK (list_selection_changed), impl);
418 /* Filename column */
420 column = gtk_tree_view_column_new ();
421 gtk_tree_view_column_set_title (column, "File name");
423 renderer = gtk_cell_renderer_pixbuf_new ();
424 gtk_tree_view_column_pack_start (column, renderer, TRUE);
425 gtk_tree_view_column_set_cell_data_func (column, renderer,
426 list_icon_data_func, impl, NULL);
427 gtk_tree_view_column_set_sort_column_id (column, 0);
429 renderer = gtk_cell_renderer_text_new ();
430 gtk_tree_view_column_pack_start (column, renderer, TRUE);
431 gtk_tree_view_column_set_cell_data_func (column, renderer,
432 list_name_data_func, impl, NULL);
433 gtk_tree_view_column_set_sort_column_id (column, 0);
435 gtk_tree_view_append_column (GTK_TREE_VIEW (impl->list), column);
439 column = gtk_tree_view_column_new ();
440 gtk_tree_view_column_set_title (column, "Size");
442 renderer = gtk_cell_renderer_text_new ();
443 gtk_tree_view_column_pack_start (column, renderer, TRUE);
444 gtk_tree_view_column_set_cell_data_func (column, renderer,
445 list_size_data_func, impl, NULL);
446 gtk_tree_view_column_set_sort_column_id (column, 1);
447 gtk_tree_view_append_column (GTK_TREE_VIEW (impl->list), column);
449 /* Modification time column */
451 column = gtk_tree_view_column_new ();
452 gtk_tree_view_column_set_title (column, "Modified");
454 renderer = gtk_cell_renderer_text_new ();
455 gtk_tree_view_column_pack_start (column, renderer, TRUE);
456 gtk_tree_view_column_set_cell_data_func (column, renderer,
457 list_mtime_data_func, impl, NULL);
458 gtk_tree_view_column_set_sort_column_id (column, 2);
459 gtk_tree_view_append_column (GTK_TREE_VIEW (impl->list), column);
461 return impl->list_scrollwin;
465 create_filename_entry (GtkFileChooserImplDefault *impl)
470 hbox = gtk_hbox_new (FALSE, 6);
471 gtk_widget_show (hbox);
473 label = gtk_label_new_with_mnemonic ("_Location:");
474 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
475 gtk_widget_show (label);
477 impl->entry = _gtk_file_chooser_entry_new ();
478 gtk_entry_set_activates_default (GTK_ENTRY (impl->entry), TRUE);
479 g_signal_connect (impl->entry, "activate",
480 G_CALLBACK (entry_activate), impl);
481 _gtk_file_chooser_entry_set_file_system (GTK_FILE_CHOOSER_ENTRY (impl->entry),
484 gtk_box_pack_start (GTK_BOX (hbox), impl->entry, TRUE, TRUE, 0);
485 gtk_widget_show (impl->entry);
487 gtk_label_set_mnemonic_widget (GTK_LABEL (label), impl->entry);
493 gtk_file_chooser_impl_default_constructor (GType type,
494 guint n_construct_properties,
495 GObjectConstructParam *construct_params)
497 GtkFileChooserImplDefault *impl;
506 object = parent_class->constructor (type,
507 n_construct_properties,
509 impl = GTK_FILE_CHOOSER_IMPL_DEFAULT (object);
511 g_assert (impl->file_system);
513 gtk_widget_push_composite_child ();
517 table = gtk_table_new (3, 2, FALSE);
518 gtk_table_set_col_spacings (GTK_TABLE (table), 6);
519 gtk_box_pack_start (GTK_BOX (impl), table, TRUE, TRUE, 0);
520 gtk_widget_show (table);
524 widget = create_filter (impl);
525 gtk_table_attach (GTK_TABLE (table), widget,
527 GTK_EXPAND | GTK_FILL, 0,
532 hpaned = gtk_hpaned_new ();
533 gtk_table_attach (GTK_TABLE (table), hpaned,
535 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
537 gtk_paned_set_position (GTK_PANED (hpaned), 200); /* FIXME: this sucks */
538 gtk_widget_show (hpaned);
542 widget = create_folder_tree (impl);
543 gtk_paned_add1 (GTK_PANED (hpaned), widget);
547 widget = create_file_list (impl);
548 gtk_paned_add2 (GTK_PANED (hpaned), widget);
550 /* Location/filename entry */
552 widget = create_filename_entry (impl);
553 gtk_table_attach (GTK_TABLE (table), widget,
555 GTK_EXPAND | GTK_FILL, 0,
560 impl->preview_frame = gtk_frame_new ("Preview");
561 gtk_table_attach (GTK_TABLE (table), impl->preview_frame,
563 0, GTK_EXPAND | GTK_FILL,
565 /* Don't show preview frame initially */
568 focus_chain = g_list_append (NULL, impl->entry);
569 focus_chain = g_list_append (focus_chain, impl->tree);
570 focus_chain = g_list_append (focus_chain, impl->list);
571 gtk_container_set_focus_chain (GTK_CONTAINER (impl), focus_chain);
572 g_list_free (focus_chain);
575 gtk_widget_pop_composite_child ();
580 /* Sets the extra_widget by packing it in the appropriate place */
582 set_extra_widget (GtkFileChooserImplDefault *impl,
583 GtkWidget *extra_widget)
585 if (extra_widget == impl->extra_widget)
588 if (impl->extra_widget)
589 gtk_container_remove (GTK_CONTAINER (impl), impl->extra_widget);
591 impl->extra_widget = extra_widget;
592 if (impl->extra_widget)
594 gtk_widget_show (impl->extra_widget);
595 gtk_box_pack_end (GTK_BOX (impl), impl->extra_widget, FALSE, FALSE, 0);
600 gtk_file_chooser_impl_default_set_property (GObject *object,
606 GtkFileChooserImplDefault *impl = GTK_FILE_CHOOSER_IMPL_DEFAULT (object);
610 case GTK_FILE_CHOOSER_PROP_ACTION:
611 impl->action = g_value_get_enum (value);
613 case GTK_FILE_CHOOSER_PROP_FILE_SYSTEM:
615 GtkFileSystem *file_system = g_value_get_object (value);
616 if (impl->file_system != file_system)
618 if (impl->file_system)
619 g_object_unref (impl->file_system);
620 impl->file_system = file_system;
621 if (impl->file_system)
622 g_object_ref (impl->file_system);
626 case GTK_FILE_CHOOSER_PROP_FILTER:
627 set_current_filter (impl, g_value_get_object (value));
629 case GTK_FILE_CHOOSER_PROP_FOLDER_MODE:
631 gboolean folder_mode = g_value_get_boolean (value);
632 if (folder_mode != impl->folder_mode)
634 impl->folder_mode = folder_mode;
635 if (impl->folder_mode)
636 gtk_widget_hide (impl->list_scrollwin);
638 gtk_widget_show (impl->list_scrollwin);
642 case GTK_FILE_CHOOSER_PROP_LOCAL_ONLY:
643 impl->local_only = g_value_get_boolean (value);
645 case GTK_FILE_CHOOSER_PROP_PREVIEW_WIDGET:
646 set_preview_widget (impl, g_value_get_object (value));
648 case GTK_FILE_CHOOSER_PROP_PREVIEW_WIDGET_ACTIVE:
649 impl->preview_widget_active = g_value_get_boolean (value);
650 update_preview_widget_visibility (impl);
652 case GTK_FILE_CHOOSER_PROP_EXTRA_WIDGET:
653 set_extra_widget (impl, g_value_get_object (value));
655 case GTK_FILE_CHOOSER_PROP_SELECT_MULTIPLE:
657 gboolean select_multiple = g_value_get_boolean (value);
658 if (select_multiple != impl->select_multiple)
660 GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->list));
662 impl->select_multiple = select_multiple;
663 gtk_tree_selection_set_mode (selection,
665 GTK_SELECTION_MULTIPLE : GTK_SELECTION_BROWSE));
666 /* FIXME: See note in check_preview_change() */
667 check_preview_change (impl);
671 case GTK_FILE_CHOOSER_PROP_SHOW_HIDDEN:
673 gboolean show_hidden = g_value_get_boolean (value);
674 if (show_hidden != impl->show_hidden)
676 impl->show_hidden = show_hidden;
677 _gtk_file_system_model_set_show_hidden (impl->tree_model, show_hidden);
678 _gtk_file_system_model_set_show_hidden (impl->list_model, show_hidden);
683 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
689 gtk_file_chooser_impl_default_get_property (GObject *object,
694 GtkFileChooserImplDefault *impl = GTK_FILE_CHOOSER_IMPL_DEFAULT (object);
698 case GTK_FILE_CHOOSER_PROP_ACTION:
699 g_value_set_enum (value, impl->action);
701 case GTK_FILE_CHOOSER_PROP_FILTER:
702 g_value_set_object (value, impl->current_filter);
704 case GTK_FILE_CHOOSER_PROP_FOLDER_MODE:
705 g_value_set_boolean (value, impl->folder_mode);
707 case GTK_FILE_CHOOSER_PROP_LOCAL_ONLY:
708 g_value_set_boolean (value, impl->local_only);
710 case GTK_FILE_CHOOSER_PROP_PREVIEW_WIDGET:
711 g_value_set_object (value, impl->preview_widget);
713 case GTK_FILE_CHOOSER_PROP_PREVIEW_WIDGET_ACTIVE:
714 g_value_set_boolean (value, impl->preview_widget_active);
716 case GTK_FILE_CHOOSER_PROP_EXTRA_WIDGET:
717 g_value_set_object (value, impl->extra_widget);
719 case GTK_FILE_CHOOSER_PROP_SELECT_MULTIPLE:
720 g_value_set_boolean (value, impl->select_multiple);
722 case GTK_FILE_CHOOSER_PROP_SHOW_HIDDEN:
723 g_value_set_boolean (value, impl->show_hidden);
726 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
731 /* We override show-all since we have internal widgets that
732 * shouldn't be shown when you call show_all(), like the filter
736 gtk_file_chooser_impl_default_show_all (GtkWidget *widget)
738 gtk_widget_show (widget);
742 expand_and_select_func (GtkFileSystemModel *model,
747 GtkFileChooserImplDefault *impl = user_data;
748 GtkTreeView *tree_view;
750 if (model == impl->tree_model)
751 tree_view = GTK_TREE_VIEW (impl->tree);
753 tree_view = GTK_TREE_VIEW (impl->list);
755 gtk_tree_view_expand_to_path (tree_view, path);
756 gtk_tree_view_expand_row (tree_view, path, FALSE);
757 gtk_tree_view_set_cursor (tree_view, path, NULL, FALSE);
758 gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (impl->tree), path, NULL, TRUE, 0.3, 0.5);
762 gtk_file_chooser_impl_default_set_current_folder (GtkFileChooser *chooser,
763 const GtkFilePath *path)
765 GtkFileChooserImplDefault *impl = GTK_FILE_CHOOSER_IMPL_DEFAULT (chooser);
767 _gtk_file_system_model_path_do (impl->tree_model, path,
768 expand_and_select_func, impl);
772 gtk_file_chooser_impl_default_get_current_folder (GtkFileChooser *chooser)
774 GtkFileChooserImplDefault *impl = GTK_FILE_CHOOSER_IMPL_DEFAULT (chooser);
776 return gtk_file_path_copy (impl->current_folder);
780 gtk_file_chooser_impl_default_set_current_name (GtkFileChooser *chooser,
783 GtkFileChooserImplDefault *impl = GTK_FILE_CHOOSER_IMPL_DEFAULT (chooser);
785 _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->entry), name);
789 select_func (GtkFileSystemModel *model,
794 GtkFileChooserImplDefault *impl = user_data;
795 GtkTreeView *tree_view = GTK_TREE_VIEW (impl->list);
796 GtkTreePath *sorted_path;
798 sorted_path = gtk_tree_model_sort_convert_child_path_to_path (impl->sort_model, path);
799 gtk_tree_view_set_cursor (tree_view, sorted_path, NULL, FALSE);
800 gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (impl->tree), sorted_path, NULL, TRUE, 0.3, 0.0);
801 gtk_tree_path_free (sorted_path);
805 gtk_file_chooser_impl_default_select_path (GtkFileChooser *chooser,
806 const GtkFilePath *path)
808 GtkFileChooserImplDefault *impl = GTK_FILE_CHOOSER_IMPL_DEFAULT (chooser);
809 GtkFilePath *parent_path;
811 if (!gtk_file_system_get_parent (impl->file_system, path, &parent_path, NULL)) /* NULL-GError */
816 _gtk_file_chooser_set_current_folder_path (chooser, path);
820 _gtk_file_chooser_set_current_folder_path (chooser, parent_path);
821 gtk_file_path_free (parent_path);
822 _gtk_file_system_model_path_do (impl->list_model, path,
828 unselect_func (GtkFileSystemModel *model,
833 GtkFileChooserImplDefault *impl = user_data;
834 GtkTreeView *tree_view = GTK_TREE_VIEW (impl->list);
835 GtkTreePath *sorted_path;
837 sorted_path = gtk_tree_model_sort_convert_child_path_to_path (impl->sort_model,
839 gtk_tree_selection_unselect_path (gtk_tree_view_get_selection (tree_view),
841 gtk_tree_path_free (sorted_path);
845 gtk_file_chooser_impl_default_unselect_path (GtkFileChooser *chooser,
846 const GtkFilePath *path)
848 GtkFileChooserImplDefault *impl = GTK_FILE_CHOOSER_IMPL_DEFAULT (chooser);
850 _gtk_file_system_model_path_do (impl->list_model, path,
851 unselect_func, impl);
855 gtk_file_chooser_impl_default_select_all (GtkFileChooser *chooser)
857 GtkFileChooserImplDefault *impl = GTK_FILE_CHOOSER_IMPL_DEFAULT (chooser);
858 if (impl->select_multiple)
860 GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->list));
861 gtk_tree_selection_select_all (selection);
866 gtk_file_chooser_impl_default_unselect_all (GtkFileChooser *chooser)
868 GtkFileChooserImplDefault *impl = GTK_FILE_CHOOSER_IMPL_DEFAULT (chooser);
869 GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->list));
871 gtk_tree_selection_unselect_all (selection);
875 get_paths_foreach (GtkTreeModel *model,
880 GtkTreePath *child_path;
881 GtkTreeIter child_iter;
882 const GtkFilePath *file_path;
886 GtkFileChooserImplDefault *impl;
889 child_path = gtk_tree_model_sort_convert_path_to_child_path (info->impl->sort_model, path);
890 gtk_tree_model_get_iter (GTK_TREE_MODEL (info->impl->list_model), &child_iter, child_path);
891 gtk_tree_path_free (child_path);
893 file_path = _gtk_file_system_model_get_path (info->impl->list_model, &child_iter);
894 info->result = g_slist_prepend (info->result, gtk_file_path_copy (file_path));
898 gtk_file_chooser_impl_default_get_paths (GtkFileChooser *chooser)
900 GtkFileChooserImplDefault *impl = GTK_FILE_CHOOSER_IMPL_DEFAULT (chooser);
901 GtkTreeSelection *selection;
905 GtkFileChooserImplDefault *impl;
908 if (!impl->sort_model)
911 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->list));
914 gtk_tree_selection_selected_foreach (selection,
915 get_paths_foreach, &info);
916 return g_slist_reverse (info.result);
920 gtk_file_chooser_impl_default_get_preview_path (GtkFileChooser *chooser)
922 GtkFileChooserImplDefault *impl = GTK_FILE_CHOOSER_IMPL_DEFAULT (chooser);
924 if (impl->preview_path)
925 return gtk_file_path_copy (impl->preview_path);
930 static GtkFileSystem *
931 gtk_file_chooser_impl_default_get_file_system (GtkFileChooser *chooser)
933 GtkFileChooserImplDefault *impl = GTK_FILE_CHOOSER_IMPL_DEFAULT (chooser);
935 return impl->file_system;
939 find_filter_menu_item (GtkFileChooserImplDefault *impl,
940 GtkFileFilter *filter,
943 GtkWidget *menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (impl->filter_option_menu));
944 GList *children = gtk_container_get_children (GTK_CONTAINER (menu));
951 for (tmp_list = children; tmp_list; tmp_list = tmp_list->next)
953 if (g_object_get_data (tmp_list->data, "gtk-file-filter") == filter)
956 *index_return = index;
957 return tmp_list->data;
962 g_list_free (children);
968 gtk_file_chooser_impl_default_add_filter (GtkFileChooser *chooser,
969 GtkFileFilter *filter)
971 GtkFileChooserImplDefault *impl = GTK_FILE_CHOOSER_IMPL_DEFAULT (chooser);
973 GtkWidget *menu_item;
976 if (g_slist_find (impl->filters, filter))
978 g_warning ("gtk_file_chooser_add_filter() called on filter already in list\n");
982 g_object_ref (filter);
983 gtk_object_sink (GTK_OBJECT (filter));
984 impl->filters = g_slist_append (impl->filters, filter);
986 name = gtk_file_filter_get_name (filter);
988 name = "Untitled filter"; /* Place-holder, doesn't need to be marked for translation */
990 menu_item = gtk_menu_item_new_with_label (name);
991 g_object_set_data (G_OBJECT (menu_item), "gtk-file-filter", filter);
992 gtk_widget_show (menu_item);
994 menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (impl->filter_option_menu));
995 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
996 /* Option menus don't react to menu size changes properly */
997 gtk_widget_size_request (menu, NULL);
999 if (!g_slist_find (impl->filters, impl->current_filter))
1000 set_current_filter (impl, filter);
1002 gtk_widget_show (impl->filter_alignment);
1006 gtk_file_chooser_impl_default_remove_filter (GtkFileChooser *chooser,
1007 GtkFileFilter *filter)
1009 GtkFileChooserImplDefault *impl = GTK_FILE_CHOOSER_IMPL_DEFAULT (chooser);
1011 GtkWidget *menu_item;
1013 if (!g_slist_find (impl->filters, filter))
1015 g_warning ("gtk_file_chooser_remove_filter() called on filter not in list\n");
1019 impl->filters = g_slist_remove (impl->filters, filter);
1021 if (filter == impl->current_filter)
1024 set_current_filter (impl, impl->filters->data);
1026 set_current_filter (impl, NULL);
1029 menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (impl->filter_option_menu));
1030 menu_item = find_filter_menu_item (impl, filter, NULL);
1031 g_assert (menu_item);
1032 gtk_widget_destroy (menu_item);
1033 /* Option menus don't react to menu size changes properly */
1034 gtk_widget_size_request (menu, NULL);
1036 g_object_unref (filter);
1039 gtk_widget_hide (impl->filter_alignment);
1043 gtk_file_chooser_impl_default_list_filters (GtkFileChooser *chooser)
1045 GtkFileChooserImplDefault *impl = GTK_FILE_CHOOSER_IMPL_DEFAULT (chooser);
1047 return g_slist_copy (impl->filters);
1051 list_model_filter_func (GtkFileSystemModel *model,
1053 const GtkFileInfo *file_info,
1056 GtkFileChooserImplDefault *impl = user_data;
1057 GtkFileFilterInfo filter_info;
1058 GtkFileFilterFlags needed;
1061 if (!impl->current_filter)
1064 filter_info.contains = GTK_FILE_FILTER_DISPLAY_NAME | GTK_FILE_FILTER_MIME_TYPE;
1066 needed = gtk_file_filter_get_needed (impl->current_filter);
1068 filter_info.display_name = gtk_file_info_get_display_name (file_info);
1069 filter_info.mime_type = gtk_file_info_get_mime_type (file_info);
1071 if (needed & GTK_FILE_FILTER_FILENAME)
1073 filter_info.filename = gtk_file_system_path_to_filename (impl->file_system, path);
1074 if (filter_info.filename)
1075 filter_info.contains |= GTK_FILE_FILTER_FILENAME;
1078 filter_info.filename = NULL;
1080 if (needed & GTK_FILE_FILTER_URI)
1082 filter_info.uri = gtk_file_system_path_to_uri (impl->file_system, path);
1083 if (filter_info.filename)
1084 filter_info.contains |= GTK_FILE_FILTER_URI;
1087 filter_info.uri = NULL;
1089 result = gtk_file_filter_filter (impl->current_filter, &filter_info);
1091 if (filter_info.filename)
1092 g_free ((gchar *)filter_info.filename);
1093 if (filter_info.uri)
1094 g_free ((gchar *)filter_info.uri);
1100 install_list_model_filter (GtkFileChooserImplDefault *impl)
1102 if (impl->current_filter)
1103 _gtk_file_system_model_set_filter (impl->list_model,
1104 list_model_filter_func,
1109 set_current_filter (GtkFileChooserImplDefault *impl,
1110 GtkFileFilter *filter)
1112 if (impl->current_filter != filter)
1114 int menu_item_index;
1116 /* If we have filters, new filter must be one of them
1118 find_filter_menu_item (impl, filter, &menu_item_index);
1119 if (impl->filters && menu_item_index < 0)
1122 if (impl->current_filter)
1123 g_object_unref (impl->current_filter);
1124 impl->current_filter = filter;
1125 if (impl->current_filter)
1127 g_object_ref (impl->current_filter);
1128 gtk_object_sink (GTK_OBJECT (filter));
1132 gtk_option_menu_set_history (GTK_OPTION_MENU (impl->filter_option_menu),
1135 install_list_model_filter (impl);
1137 g_object_notify (G_OBJECT (impl), "filter");
1142 name_sort_func (GtkTreeModel *model,
1147 GtkFileChooserImplDefault *impl = user_data;
1148 const GtkFileInfo *info_a = _gtk_file_system_model_get_info (impl->tree_model, a);
1149 const GtkFileInfo *info_b = _gtk_file_system_model_get_info (impl->tree_model, b);
1151 return strcmp (gtk_file_info_get_display_key (info_a), gtk_file_info_get_display_key (info_b));
1155 size_sort_func (GtkTreeModel *model,
1160 GtkFileChooserImplDefault *impl = user_data;
1161 const GtkFileInfo *info_a = _gtk_file_system_model_get_info (impl->tree_model, a);
1162 const GtkFileInfo *info_b = _gtk_file_system_model_get_info (impl->tree_model, b);
1163 gint64 size_a = gtk_file_info_get_size (info_a);
1164 gint64 size_b = gtk_file_info_get_size (info_b);
1166 return size_a > size_b ? -1 : (size_a == size_b ? 0 : 1);
1169 /* Sort callback for the mtime column */
1171 mtime_sort_func (GtkTreeModel *model,
1176 GtkFileChooserImplDefault *impl = user_data;
1177 const GtkFileInfo *info_a = _gtk_file_system_model_get_info (impl->tree_model, a);
1178 const GtkFileInfo *info_b = _gtk_file_system_model_get_info (impl->tree_model, b);
1179 GtkFileTime ta = gtk_file_info_get_modification_time (info_a);
1180 GtkFileTime tb = gtk_file_info_get_modification_time (info_b);
1182 return ta > tb ? -1 : (ta == tb ? 0 : 1);
1186 open_and_close (GtkTreeView *tree_view,
1187 GtkTreePath *target_path)
1189 GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
1193 path = gtk_tree_path_new ();
1194 gtk_tree_path_append_index (path, 0);
1196 gtk_tree_model_get_iter (model, &iter, path);
1200 if (gtk_tree_path_is_ancestor (path, target_path) ||
1201 gtk_tree_path_compare (path, target_path) == 0)
1203 GtkTreeIter child_iter;
1204 gtk_tree_view_expand_row (tree_view, path, FALSE);
1205 if (gtk_tree_model_iter_children (model, &child_iter, &iter))
1208 gtk_tree_path_down (path);
1213 gtk_tree_view_collapse_row (tree_view, path);
1217 GtkTreeIter parent_iter;
1218 GtkTreeIter next_iter;
1221 if (gtk_tree_model_iter_next (model, &next_iter))
1224 gtk_tree_path_next (path);
1228 if (!gtk_tree_model_iter_parent (model, &parent_iter, &iter))
1232 gtk_tree_path_up (path);
1239 gtk_tree_path_free (path);
1243 update_chooser_entry (GtkFileChooserImplDefault *impl)
1245 GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->list));
1246 const GtkFileInfo *info;
1248 GtkTreeIter child_iter;
1250 /* Fixing this for multiple selection involves getting the full
1251 * selection and diffing to find out what the most recently selected
1252 * file is; there is logic in GtkFileSelection that probably can
1253 * be copied; check_preview_change() is similar.
1255 if (impl->select_multiple ||
1256 !gtk_tree_selection_get_selected (selection, NULL, &iter))
1259 gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model,
1263 info = _gtk_file_system_model_get_info (impl->list_model, &child_iter);
1265 _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->entry),
1266 gtk_file_info_get_display_name (info));
1270 filter_option_menu_changed (GtkOptionMenu *option_menu,
1271 GtkFileChooserImplDefault *impl)
1273 gint new_index = gtk_option_menu_get_history (GTK_OPTION_MENU (option_menu));
1274 GtkFileFilter *new_filter = g_slist_nth_data (impl->filters, new_index);
1276 set_current_filter (impl, new_filter);
1280 check_preview_change (GtkFileChooserImplDefault *impl)
1282 const GtkFilePath *new_path = NULL;
1284 /* Fixing preview for multiple selection involves getting the full
1285 * selection and diffing to find out what the most recently selected
1286 * file is; there is logic in GtkFileSelection that probably can
1287 * be copied. update_chooser_entry() is similar.
1289 if (impl->sort_model && !impl->select_multiple)
1291 GtkTreeSelection *selection;
1294 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->list));
1295 if (gtk_tree_selection_get_selected (selection, NULL, &iter))
1297 GtkTreeIter child_iter;
1299 gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model,
1300 &child_iter, &iter);
1302 new_path = _gtk_file_system_model_get_path (impl->list_model, &child_iter);
1306 if (new_path != impl->preview_path &&
1307 !(new_path && impl->preview_path &&
1308 gtk_file_path_compare (new_path, impl->preview_path) == 0))
1310 if (impl->preview_path)
1311 gtk_file_path_free (impl->preview_path);
1314 impl->preview_path = gtk_file_path_copy (new_path);
1316 impl->preview_path = NULL;
1318 g_signal_emit_by_name (impl, "update-preview");
1323 tree_selection_changed (GtkTreeSelection *selection,
1324 GtkFileChooserImplDefault *impl)
1327 const GtkFilePath *file_path;
1330 if (!gtk_tree_selection_get_selected (selection, NULL, &iter))
1333 file_path = _gtk_file_system_model_get_path (impl->tree_model, &iter);
1334 if (impl->current_folder && gtk_file_path_compare (file_path, impl->current_folder) == 0)
1337 if (impl->current_folder)
1338 gtk_file_path_free (impl->current_folder);
1339 impl->current_folder = gtk_file_path_copy (file_path);
1340 _gtk_file_chooser_entry_set_base_folder (GTK_FILE_CHOOSER_ENTRY (impl->entry), file_path);
1342 if (impl->list_model)
1344 g_object_unref (impl->list_model);
1345 impl->list_model = NULL;
1347 g_object_unref (impl->sort_model);
1348 impl->sort_model = NULL;
1351 /* Close the tree up to only the parents of the newly selected
1352 * node and it's immediate children are visible.
1354 path = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->tree_model), &iter);
1355 open_and_close (GTK_TREE_VIEW (impl->tree), path);
1356 gtk_tree_path_free (path);
1358 /* Now update the list view to show the new row.
1360 file_path = _gtk_file_system_model_get_path (impl->tree_model, &iter);
1362 impl->list_model = _gtk_file_system_model_new (impl->file_system,
1364 GTK_FILE_INFO_ICON |
1365 GTK_FILE_INFO_DISPLAY_NAME |
1366 GTK_FILE_INFO_IS_FOLDER |
1367 GTK_FILE_INFO_SIZE |
1368 GTK_FILE_INFO_MODIFICATION_TIME);
1370 _gtk_file_system_model_set_show_folders (impl->list_model, TRUE);
1372 install_list_model_filter (impl);
1374 impl->sort_model = (GtkTreeModelSort *)gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (impl->list_model));
1375 gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->sort_model), 0, name_sort_func, impl, NULL);
1376 gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->sort_model), 1, size_sort_func, impl, NULL);
1377 gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->sort_model), 2, mtime_sort_func, impl, NULL);
1378 gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (impl->sort_model),
1379 name_sort_func, impl, NULL);
1381 gtk_tree_view_set_model (GTK_TREE_VIEW (impl->list),
1382 GTK_TREE_MODEL (impl->sort_model));
1383 gtk_tree_view_set_search_column (GTK_TREE_VIEW (impl->list),
1384 GTK_FILE_SYSTEM_MODEL_DISPLAY_NAME);
1386 g_signal_emit_by_name (impl, "current-folder-changed", 0);
1388 update_chooser_entry (impl);
1389 check_preview_change (impl);
1391 g_signal_emit_by_name (impl, "selection-changed", 0);
1395 list_selection_changed (GtkTreeSelection *selection,
1396 GtkFileChooserImplDefault *impl)
1398 update_chooser_entry (impl);
1399 check_preview_change (impl);
1401 g_signal_emit_by_name (impl, "selection-changed", 0);
1404 /* Callback used when a row in the file list is activated */
1406 list_row_activated (GtkTreeView *tree_view,
1408 GtkTreeViewColumn *column,
1409 GtkFileChooserImplDefault *impl)
1411 GtkTreeIter iter, child_iter;
1412 const GtkFileInfo *info;
1414 if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->sort_model), &iter, path))
1417 gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model, &child_iter, &iter);
1419 info = _gtk_file_system_model_get_info (impl->list_model, &child_iter);
1421 if (gtk_file_info_get_is_folder (info))
1423 const GtkFilePath *file_path;
1426 file_path = _gtk_file_system_model_get_path (impl->list_model, &child_iter);
1427 uri = gtk_file_system_path_to_uri (impl->file_system, file_path);
1429 gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (impl), uri);
1436 g_signal_emit_by_name (impl, "file-activated");
1440 entry_activate (GtkEntry *entry,
1441 GtkFileChooserImplDefault *impl)
1443 GtkFileChooserEntry *chooser_entry = GTK_FILE_CHOOSER_ENTRY (entry);
1444 const GtkFilePath *folder_path = _gtk_file_chooser_entry_get_current_folder (chooser_entry);
1445 const gchar *file_part = _gtk_file_chooser_entry_get_file_part (chooser_entry);
1446 GtkFilePath *new_folder = NULL;
1448 /* If the file part is non-empty, we need to figure out if it
1449 * refers to a folder within folder. We could optimize the case
1450 * here where the folder is already loaded for one of our tree models.
1452 if (file_part[0] == '\0' && gtk_file_path_compare (impl->current_folder, folder_path) != 0)
1453 new_folder = gtk_file_path_copy (folder_path);
1456 GtkFileFolder *folder = NULL;
1457 GtkFilePath *subfolder_path = NULL;
1458 GtkFileInfo *info = NULL;
1460 folder = gtk_file_system_get_folder (impl->file_system,
1462 GTK_FILE_INFO_IS_FOLDER,
1463 NULL); /* NULL-GError */
1466 subfolder_path = gtk_file_system_make_path (impl->file_system,
1469 NULL); /* NULL-GError */
1472 info = gtk_file_folder_get_info (folder,
1474 NULL); /* NULL-GError */
1476 if (info && gtk_file_info_get_is_folder (info))
1477 new_folder = gtk_file_path_copy (subfolder_path);
1480 g_object_unref (folder);
1483 gtk_file_path_free (subfolder_path);
1486 gtk_file_info_free (info);
1491 g_signal_stop_emission_by_name (entry, "activate");
1493 _gtk_file_chooser_set_current_folder_path (GTK_FILE_CHOOSER (impl), new_folder);
1494 _gtk_file_chooser_entry_set_file_part (chooser_entry, "");
1496 gtk_file_path_free (new_folder);
1500 static const GtkFileInfo *
1501 get_list_file_info (GtkFileChooserImplDefault *impl,
1504 GtkTreeIter child_iter;
1506 gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model,
1510 return _gtk_file_system_model_get_info (impl->tree_model, &child_iter);
1514 tree_name_data_func (GtkTreeViewColumn *tree_column,
1515 GtkCellRenderer *cell,
1516 GtkTreeModel *tree_model,
1520 GtkFileChooserImplDefault *impl = data;
1521 const GtkFileInfo *info = _gtk_file_system_model_get_info (impl->tree_model, iter);
1526 "text", gtk_file_info_get_display_name (info),
1532 list_icon_data_func (GtkTreeViewColumn *tree_column,
1533 GtkCellRenderer *cell,
1534 GtkTreeModel *tree_model,
1538 GtkFileChooserImplDefault *impl = data;
1539 const GtkFileInfo *info = get_list_file_info (impl, iter);
1543 GtkWidget *widget = GTK_TREE_VIEW_COLUMN (tree_column)->tree_view;
1544 GdkPixbuf *pixbuf = gtk_file_info_render_icon (info, widget, 36);
1551 g_object_unref (pixbuf);
1555 /* Sets a cellrenderer's text, making it bold if the GtkFileInfo is a folder */
1557 set_cell_text_bold_if_folder (const GtkFileInfo *info, GtkCellRenderer *cell, const char *text)
1561 "weight", gtk_file_info_get_is_folder (info) ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL,
1566 list_name_data_func (GtkTreeViewColumn *tree_column,
1567 GtkCellRenderer *cell,
1568 GtkTreeModel *tree_model,
1572 GtkFileChooserImplDefault *impl = data;
1573 const GtkFileInfo *info = get_list_file_info (impl, iter);
1578 set_cell_text_bold_if_folder (info, cell, gtk_file_info_get_display_name (info));
1583 list_size_data_func (GtkTreeViewColumn *tree_column,
1584 GtkCellRenderer *cell,
1585 GtkTreeModel *tree_model,
1589 GtkFileChooserImplDefault *impl = data;
1590 const GtkFileInfo *info = get_list_file_info (impl, iter);
1591 gint64 size = gtk_file_info_get_size (info);
1594 if (!info || gtk_file_info_get_is_folder (info))
1597 if (size < (gint64)1024)
1598 str = g_strdup_printf ("%d bytes", (gint)size);
1599 else if (size < (gint64)1024*1024)
1600 str = g_strdup_printf ("%.1f K", size / (1024.));
1601 else if (size < (gint64)1024*1024*1024)
1602 str = g_strdup_printf ("%.1f M", size / (1024.*1024.));
1604 str = g_strdup_printf ("%.1f G", size / (1024.*1024.*1024.));
1614 /* Tree column data callback for the file list; fetches the mtime of a file */
1616 list_mtime_data_func (GtkTreeViewColumn *tree_column,
1617 GtkCellRenderer *cell,
1618 GtkTreeModel *tree_model,
1622 GtkFileChooserImplDefault *impl;
1623 const GtkFileInfo *info;
1625 struct tm tm, now_tm;
1630 info = get_list_file_info (impl, iter);
1634 mtime = (time_t) gtk_file_info_get_modification_time (info);
1635 tm = *localtime (&mtime);
1638 now_tm = *localtime (&now);
1641 if (tm.tm_mday == now_tm.tm_mday
1642 && tm.tm_mon == now_tm.tm_mon
1643 && tm.tm_year == now_tm.tm_year)
1644 strcpy (buf, "Today");
1649 /* Days from last week */
1651 for (i = 1; i < 7; i++)
1656 then = now - i * 60 * 60 * 24;
1657 then_tm = *localtime (&then);
1659 if (tm.tm_mday == then_tm.tm_mday
1660 && tm.tm_mon == then_tm.tm_mon
1661 && tm.tm_year == then_tm.tm_year)
1664 strcpy (buf, "Yesterday");
1666 if (strftime (buf, sizeof (buf), "%A", &tm) == 0)
1667 strcpy (buf, "Unknown");
1673 /* Any other date */
1677 if (strftime (buf, sizeof (buf), "%d/%b/%Y", &tm) == 0)
1678 strcpy (buf, "Unknown");
1682 set_cell_text_bold_if_folder (info, cell, buf);
1686 _gtk_file_chooser_impl_default_new (GtkFileSystem *file_system)
1688 return g_object_new (GTK_TYPE_FILE_CHOOSER_IMPL_DEFAULT,
1689 "file-system", file_system,