Created
April 10, 2015 08:18
-
-
Save wfr/c8e431a61d300b4f3d15 to your computer and use it in GitHub Desktop.
Simo Kivimäki's "bgo141154-filechooser-icon-view" rebased to git-3.8.9
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/gtk/gtkfilechooserdefault.c b/gtk/gtkfilechooserdefault.c | |
index 1be1fd1..fa58d9f 100644 | |
--- a/gtk/gtkfilechooserdefault.c | |
+++ b/gtk/gtkfilechooserdefault.c | |
@@ -207,7 +207,8 @@ enum { | |
MODEL_COL_NAME_COLLATED, | |
MODEL_COL_IS_FOLDER, | |
MODEL_COL_IS_SENSITIVE, | |
- MODEL_COL_PIXBUF, | |
+ MODEL_COL_LIST_PIXBUF, | |
+ MODEL_COL_ICON_PIXBUF, | |
MODEL_COL_SIZE_TEXT, | |
MODEL_COL_MTIME_TEXT, | |
MODEL_COL_ELLIPSIZE, | |
@@ -224,7 +225,8 @@ enum { | |
G_TYPE_STRING, /* MODEL_COL_NAME_COLLATED */ \ | |
G_TYPE_BOOLEAN, /* MODEL_COL_IS_FOLDER */ \ | |
G_TYPE_BOOLEAN, /* MODEL_COL_IS_SENSITIVE */ \ | |
- GDK_TYPE_PIXBUF, /* MODEL_COL_PIXBUF */ \ | |
+ GDK_TYPE_PIXBUF, /* MODEL_COL_LIST_PIXBUF */ \ | |
+ GDK_TYPE_PIXBUF, /* MODEL_COL_ICON_PIXBUF */ \ | |
G_TYPE_STRING, /* MODEL_COL_SIZE_TEXT */ \ | |
G_TYPE_STRING, /* MODEL_COL_MTIME_TEXT */ \ | |
PANGO_TYPE_ELLIPSIZE_MODE /* MODEL_COL_ELLIPSIZE */ | |
@@ -250,7 +252,11 @@ typedef enum { | |
} ShortcutsIndex; | |
/* Icon size for if we can't get it from the theme */ | |
-#define FALLBACK_ICON_SIZE 16 | |
+#define FALLBACK_ICON_SIZE_FOR_LIST_VIEW 16 | |
+#define FALLBACK_ICON_SIZE_FOR_ICON_VIEW 48 | |
+ | |
+#define THUMBNAIL_ICON_SIZE 100 | |
+#define ICON_VIEW_ITEM_WIDTH 120 | |
#define PREVIEW_HBOX_SPACING 12 | |
#define NUM_LINES 45 | |
@@ -372,12 +378,19 @@ static gboolean list_select_func (GtkTreeSelection *selection, | |
gboolean path_currently_selected, | |
gpointer data); | |
-static void list_selection_changed (GtkTreeSelection *tree_selection, | |
+static void list_selection_changed (void *tree_selection_or_icon_view, | |
GtkFileChooserDefault *impl); | |
static void list_row_activated (GtkTreeView *tree_view, | |
GtkTreePath *path, | |
GtkTreeViewColumn *column, | |
GtkFileChooserDefault *impl); | |
+static void icon_item_activated (GtkIconView *icon_view, | |
+ GtkTreePath *path, | |
+ GtkFileChooserDefault *impl); | |
+static void item_activated (GtkTreeModel *model, | |
+ GtkTreePath *path, | |
+ GtkFileChooserDefault *impl); | |
+ | |
static void path_bar_clicked (GtkPathBar *path_bar, | |
GFile *file, | |
@@ -395,6 +408,9 @@ static void update_cell_renderer_attributes (GtkFileChooserDefault *impl); | |
static void load_remove_timer (GtkFileChooserDefault *impl, LoadState new_load_state); | |
static void browse_files_center_selected_row (GtkFileChooserDefault *impl); | |
+static void view_mode_set (GtkFileChooserDefault *impl, ViewMode view_mode); | |
+static void view_mode_combo_box_changed_cb (GtkComboBox *combo, | |
+ GtkFileChooserDefault *impl); | |
static void location_button_toggled_cb (GtkToggleButton *toggle, | |
GtkFileChooserDefault *impl); | |
static void location_switch_to_path_bar (GtkFileChooserDefault *impl); | |
@@ -421,8 +437,27 @@ static gboolean recent_should_respond (GtkFileChooserDefault *impl); | |
static GSList * recent_get_selected_files (GtkFileChooserDefault *impl); | |
static void set_file_system_backend (GtkFileChooserDefault *impl); | |
static void unset_file_system_backend (GtkFileChooserDefault *impl); | |
- | |
- | |
+static gboolean get_selected_tree_iter_from_icon_view (GtkFileChooserDefault *impl, | |
+ GtkTreeIter *iter_out); | |
+static void current_selection_selected_foreach (GtkFileChooserDefault *impl, | |
+ GtkTreeSelectionForeachFunc func, | |
+ gpointer data); | |
+static guint current_selection_count_selected_rows (GtkFileChooserDefault *impl); | |
+static void current_selection_select_iter (GtkFileChooserDefault *impl, | |
+ GtkTreeIter *iter); | |
+static void copy_old_selection_to_current_view (GtkFileChooserDefault *impl, | |
+ ViewMode old_view_mode); | |
+static void current_selection_unselect_iter (GtkFileChooserDefault *impl, | |
+ GtkTreeIter *iter); | |
+static void current_selection_unselect_all (GtkFileChooserDefault *impl); | |
+static void current_view_set_file_model (GtkFileChooserDefault *impl, | |
+ GtkTreeModel *model); | |
+static void current_view_set_cursor (GtkFileChooserDefault *impl, | |
+ GtkTreePath *path); | |
+static void current_view_set_select_multiple (GtkFileChooserDefault *impl, | |
+ gboolean select_multiple); | |
+ | |
+static GSource *add_idle_while_impl_is_alive (GtkFileChooserDefault *impl, GCallback callback); | |
@@ -722,7 +757,8 @@ _gtk_file_chooser_default_init (GtkFileChooserDefault *impl) | |
impl->select_multiple = FALSE; | |
impl->show_hidden = FALSE; | |
impl->show_size_column = TRUE; | |
- impl->icon_size = FALLBACK_ICON_SIZE; | |
+ impl->icon_size_for_list_view = FALLBACK_ICON_SIZE_FOR_LIST_VIEW; | |
+ impl->icon_size_for_icon_view = FALLBACK_ICON_SIZE_FOR_ICON_VIEW; | |
impl->load_state = LOAD_EMPTY; | |
impl->reload_state = RELOAD_EMPTY; | |
impl->pending_select_files = NULL; | |
@@ -732,6 +768,7 @@ _gtk_file_chooser_default_init (GtkFileChooserDefault *impl) | |
impl->sort_order = GTK_SORT_ASCENDING; | |
impl->recent_manager = gtk_recent_manager_get_default (); | |
impl->create_folders = TRUE; | |
+ impl->view_mode = VIEW_MODE_LIST; | |
gtk_orientable_set_orientation (GTK_ORIENTABLE (impl), | |
GTK_ORIENTATION_VERTICAL); | |
@@ -1162,7 +1199,7 @@ render_recent_icon (GtkFileChooserDefault *impl) | |
theme = gtk_icon_theme_get_default (); | |
retval = gtk_icon_theme_load_icon (theme, "document-open-recent", | |
- impl->icon_size, 0, | |
+ impl->icon_size_for_list_view, 0, | |
NULL); | |
/* fallback */ | |
@@ -1200,7 +1237,7 @@ shortcuts_reload_icons_get_info_cb (GCancellable *cancellable, | |
if (cancelled || error) | |
goto out; | |
- pixbuf = _gtk_file_info_render_icon (info, GTK_WIDGET (data->impl), data->impl->icon_size); | |
+ pixbuf = _gtk_file_info_render_icon (info, GTK_WIDGET (data->impl), data->impl->icon_size_for_list_view); | |
path = gtk_tree_row_reference_get_path (data->row_ref); | |
if (path) | |
@@ -1264,7 +1301,7 @@ shortcuts_reload_icons (GtkFileChooserDefault *impl) | |
volume = data; | |
pixbuf = _gtk_file_system_volume_render_icon (volume, GTK_WIDGET (impl), | |
- impl->icon_size, NULL); | |
+ impl->icon_size_for_list_view, NULL); | |
} | |
else if (shortcut_type == SHORTCUT_TYPE_FILE) | |
{ | |
@@ -1300,7 +1337,7 @@ shortcuts_reload_icons (GtkFileChooserDefault *impl) | |
*/ | |
icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (impl))); | |
pixbuf = gtk_icon_theme_load_icon (icon_theme, "folder-remote", | |
- impl->icon_size, 0, NULL); | |
+ impl->icon_size_for_list_view, 0, NULL); | |
} | |
} | |
else if (shortcut_type == SHORTCUT_TYPE_SEARCH) | |
@@ -1503,7 +1540,7 @@ get_file_info_finished (GCancellable *cancellable, | |
if (!request->label_copy) | |
request->label_copy = g_strdup (g_file_info_get_display_name (info)); | |
pixbuf = _gtk_file_info_render_icon (info, GTK_WIDGET (request->impl), | |
- request->impl->icon_size); | |
+ request->impl->icon_size_for_list_view); | |
gtk_list_store_set (request->impl->shortcuts_model, &iter, | |
SHORTCUTS_COL_PIXBUF, pixbuf, | |
@@ -1612,7 +1649,7 @@ shortcuts_insert_file (GtkFileChooserDefault *impl, | |
data = volume; | |
label_copy = _gtk_file_system_volume_get_display_name (volume); | |
pixbuf = _gtk_file_system_volume_render_icon (volume, GTK_WIDGET (impl), | |
- impl->icon_size, NULL); | |
+ impl->icon_size_for_list_view, NULL); | |
} | |
else if (shortcut_type == SHORTCUT_TYPE_FILE) | |
{ | |
@@ -1671,7 +1708,7 @@ shortcuts_insert_file (GtkFileChooserDefault *impl, | |
*/ | |
icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (impl))); | |
pixbuf = gtk_icon_theme_load_icon (icon_theme, "folder-remote", | |
- impl->icon_size, 0, NULL); | |
+ impl->icon_size_for_list_view, 0, NULL); | |
} | |
} | |
else | |
@@ -2208,6 +2245,51 @@ shortcuts_model_create (GtkFileChooserDefault *impl) | |
NULL); | |
} | |
+static gboolean | |
+start_editing_icon_view_idle_cb (GtkFileChooserDefault *impl) | |
+{ | |
+ GDK_THREADS_ENTER (); | |
+ | |
+ g_source_destroy (impl->start_editing_icon_view_idle); | |
+ impl->start_editing_icon_view_idle = NULL; | |
+ | |
+ gtk_icon_view_scroll_to_path (GTK_ICON_VIEW (impl->browse_files_icon_view), | |
+ impl->start_editing_icon_view_path, | |
+ TRUE, | |
+ 0.5, | |
+ 0.0); | |
+ | |
+ g_object_set (impl->list_name_renderer, "editable", TRUE, NULL); | |
+ gtk_icon_view_set_cursor (GTK_ICON_VIEW (impl->browse_files_icon_view), | |
+ impl->start_editing_icon_view_path, | |
+ impl->list_name_renderer, | |
+ TRUE); | |
+ | |
+ gtk_tree_path_free (impl->start_editing_icon_view_path); | |
+ impl->start_editing_icon_view_path = NULL; | |
+ | |
+ GDK_THREADS_LEAVE (); | |
+ | |
+ return FALSE; | |
+} | |
+ | |
+static void | |
+add_idle_to_edit_icon_view (GtkFileChooserDefault *impl, GtkTreePath *path) | |
+{ | |
+ /* Normally we would run the code in the start_editing_icon_view_idle_cb() synchronously, | |
+ * but GtkIconView doesn't like to start editing itself immediately after getting an item | |
+ * added - it wants to run its layout loop first. So, we add the editable item first, and | |
+ * only start editing it until an idle handler. | |
+ */ | |
+ | |
+ g_assert (impl->start_editing_icon_view_idle == NULL); | |
+ g_assert (impl->start_editing_icon_view_path == NULL); | |
+ | |
+ impl->start_editing_icon_view_path = path; | |
+ impl->start_editing_icon_view_idle = add_idle_while_impl_is_alive (impl, | |
+ G_CALLBACK (start_editing_icon_view_idle_cb)); | |
+} | |
+ | |
/* Callback used when the "New Folder" button is clicked */ | |
static void | |
new_folder_button_clicked (GtkButton *button, | |
@@ -2225,17 +2307,26 @@ new_folder_button_clicked (GtkButton *button, | |
_gtk_file_system_model_add_editable (impl->browse_files_model, &iter); | |
path = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->browse_files_model), &iter); | |
- gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (impl->browse_files_tree_view), | |
- path, impl->list_name_column, | |
- FALSE, 0.0, 0.0); | |
+ if (impl->view_mode == VIEW_MODE_LIST) | |
+ { | |
+ gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (impl->browse_files_tree_view), | |
+ path, impl->list_name_column, | |
+ FALSE, 0.0, 0.0); | |
- g_object_set (impl->list_name_renderer, "editable", TRUE, NULL); | |
- gtk_tree_view_set_cursor (GTK_TREE_VIEW (impl->browse_files_tree_view), | |
- path, | |
- impl->list_name_column, | |
- TRUE); | |
+ g_object_set (impl->list_name_renderer, "editable", TRUE, NULL); | |
+ gtk_tree_view_set_cursor (GTK_TREE_VIEW (impl->browse_files_tree_view), | |
+ path, | |
+ impl->list_name_column, | |
+ TRUE); | |
+ gtk_tree_path_free (path); | |
+ } | |
+ else if (impl->view_mode == VIEW_MODE_ICON) | |
+ { | |
+ add_idle_to_edit_icon_view (impl, path); | |
+ } | |
+ else | |
+ g_assert_not_reached (); | |
- gtk_tree_path_free (path); | |
} | |
static GSource * | |
@@ -2512,16 +2603,10 @@ add_bookmark_foreach_cb (GtkTreeModel *model, | |
static void | |
bookmarks_add_selected_folder (GtkFileChooserDefault *impl) | |
{ | |
- GtkTreeSelection *selection; | |
- | |
- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view)); | |
- | |
- if (gtk_tree_selection_count_selected_rows (selection) == 0) | |
+ if (current_selection_count_selected_rows (impl) == 0) | |
shortcuts_add_bookmark_from_file (impl, impl->current_folder, -1); | |
else | |
- gtk_tree_selection_selected_foreach (selection, | |
- add_bookmark_foreach_cb, | |
- impl); | |
+ current_selection_selected_foreach (impl, add_bookmark_foreach_cb, impl); | |
} | |
/* Callback used when the "Add bookmark" button is clicked */ | |
@@ -2637,17 +2722,15 @@ selection_check (GtkFileChooserDefault *impl, | |
gboolean *all_folders) | |
{ | |
struct selection_check_closure closure; | |
- GtkTreeSelection *selection; | |
closure.impl = impl; | |
closure.num_selected = 0; | |
closure.all_files = TRUE; | |
closure.all_folders = TRUE; | |
- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view)); | |
- gtk_tree_selection_selected_foreach (selection, | |
- selection_check_foreach_cb, | |
- &closure); | |
+ current_selection_selected_foreach (impl, | |
+ selection_check_foreach_cb, | |
+ &closure); | |
g_assert (closure.num_selected == 0 || !(closure.all_files && closure.all_folders)); | |
@@ -2691,16 +2774,12 @@ static GFile * | |
get_selected_file (GtkFileChooserDefault *impl) | |
{ | |
struct get_selected_file_closure closure; | |
- GtkTreeSelection *selection; | |
- | |
closure.impl = impl; | |
closure.file = NULL; | |
- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view)); | |
- gtk_tree_selection_selected_foreach (selection, | |
- get_selected_file_foreach_cb, | |
- &closure); | |
- | |
+ current_selection_selected_foreach(impl, | |
+ get_selected_file_foreach_cb, | |
+ &closure); | |
return closure.file; | |
} | |
@@ -2774,13 +2853,10 @@ bookmarks_check_add_sensitivity (GtkFileChooserDefault *impl) | |
tip = g_strdup_printf (_("Add the selected folders to the bookmarks")); | |
else | |
{ | |
- GtkTreeSelection *selection; | |
UpdateTooltipData data; | |
- | |
- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view)); | |
data.impl = impl; | |
data.tip = NULL; | |
- gtk_tree_selection_selected_foreach (selection, update_tooltip, &data); | |
+ current_selection_selected_foreach(impl, update_tooltip, &data); | |
tip = data.tip; | |
} | |
@@ -3751,7 +3827,7 @@ browse_files_key_press_event_cb (GtkWidget *widget, | |
return TRUE; | |
} | |
- if (key_is_left_or_right (event)) | |
+ if (impl->view_mode == VIEW_MODE_LIST && key_is_left_or_right (event)) | |
{ | |
gtk_widget_grab_focus (impl->browse_shortcuts_tree_view); | |
return TRUE; | |
@@ -4118,11 +4194,9 @@ file_list_drag_motion_cb (GtkWidget *widget, | |
static void | |
check_file_list_menu_sensitivity (GtkFileChooserDefault *impl) | |
{ | |
- GtkTreeSelection *selection; | |
gboolean active; | |
- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view)); | |
- if (gtk_tree_selection_count_selected_rows (selection) == 0) | |
+ if (current_selection_count_selected_rows (impl) == 0) | |
active = FALSE; | |
else | |
active = TRUE; | |
@@ -4179,7 +4253,7 @@ file_list_build_popup_menu (GtkFileChooserDefault *impl) | |
impl->browse_files_popup_menu = gtk_menu_new (); | |
gtk_menu_attach_to_widget (GTK_MENU (impl->browse_files_popup_menu), | |
- impl->browse_files_tree_view, | |
+ impl->browse_files_current_view, | |
popup_menu_detach_cb); | |
impl->browse_files_popup_menu_visit_file_item = file_list_add_image_menu_item (impl, GTK_STOCK_DIRECTORY, _("_Visit this file"), | |
@@ -4283,7 +4357,7 @@ file_list_popup_menu (GtkFileChooserDefault *impl, | |
{ | |
gtk_menu_popup (GTK_MENU (impl->browse_files_popup_menu), | |
NULL, NULL, | |
- popup_position_func, impl->browse_files_tree_view, | |
+ popup_position_func, impl->browse_files_current_view, | |
0, GDK_CURRENT_TIME); | |
gtk_menu_shell_select_first (GTK_MENU_SHELL (impl->browse_files_popup_menu), | |
FALSE); | |
@@ -4317,28 +4391,25 @@ list_button_press_event_cb (GtkWidget *widget, | |
return FALSE; | |
in_press = TRUE; | |
- gtk_widget_event (impl->browse_files_tree_view, (GdkEvent *) event); | |
+ gtk_widget_event (widget, (GdkEvent *) event); | |
in_press = FALSE; | |
file_list_popup_menu (impl, event); | |
return TRUE; | |
} | |
-typedef struct { | |
- OperationMode operation_mode; | |
- gint general_column; | |
- gint model_column; | |
-} ColumnMap; | |
- | |
/* Sets the sort column IDs for the file list; needs to be done whenever we | |
* change the model on the treeview. | |
*/ | |
static void | |
file_list_set_sort_column_ids (GtkFileChooserDefault *impl) | |
{ | |
- gtk_tree_view_column_set_sort_column_id (impl->list_name_column, MODEL_COL_NAME); | |
- gtk_tree_view_column_set_sort_column_id (impl->list_mtime_column, MODEL_COL_MTIME); | |
- gtk_tree_view_column_set_sort_column_id (impl->list_size_column, MODEL_COL_SIZE); | |
+ if (impl->view_mode == VIEW_MODE_LIST) | |
+ { | |
+ gtk_tree_view_column_set_sort_column_id (impl->list_name_column, MODEL_COL_NAME); | |
+ gtk_tree_view_column_set_sort_column_id (impl->list_mtime_column, MODEL_COL_MTIME); | |
+ gtk_tree_view_column_set_sort_column_id (impl->list_size_column, MODEL_COL_SIZE); | |
+ } | |
} | |
static gboolean | |
@@ -4396,28 +4467,18 @@ set_icon_cell_renderer_fixed_size (GtkFileChooserDefault *impl, GtkCellRenderer | |
gtk_cell_renderer_get_padding (renderer, &xpad, &ypad); | |
gtk_cell_renderer_set_fixed_size (renderer, | |
- xpad * 2 + impl->icon_size, | |
- ypad * 2 + impl->icon_size); | |
+ xpad * 2 + impl->icon_size_for_list_view, | |
+ ypad * 2 + impl->icon_size_for_list_view); | |
} | |
-/* Creates the widgets for the file list */ | |
+/* Creates list view */ | |
static GtkWidget * | |
-create_file_list (GtkFileChooserDefault *impl) | |
+create_browse_files_tree_view (GtkFileChooserDefault *impl) | |
{ | |
- GtkWidget *swin; | |
GtkTreeSelection *selection; | |
GtkTreeViewColumn *column; | |
GtkCellRenderer *renderer; | |
- /* Scrolled window */ | |
- swin = gtk_scrolled_window_new (NULL, NULL); | |
- gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swin), | |
- GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); | |
- gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (swin), | |
- GTK_SHADOW_IN); | |
- | |
- /* Tree/list view */ | |
- | |
impl->browse_files_tree_view = gtk_tree_view_new (); | |
#ifdef PROFILE_FILE_CHOOSER | |
g_object_set_data (G_OBJECT (impl->browse_files_tree_view), "fmq-name", "file_list"); | |
@@ -4426,7 +4487,6 @@ create_file_list (GtkFileChooserDefault *impl) | |
atk_object_set_name (gtk_widget_get_accessible (impl->browse_files_tree_view), _("Files")); | |
gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (impl->browse_files_tree_view), TRUE); | |
- gtk_container_add (GTK_CONTAINER (swin), impl->browse_files_tree_view); | |
gtk_drag_dest_set (impl->browse_files_tree_view, | |
GTK_DEST_DEFAULT_ALL, | |
@@ -4521,6 +4581,83 @@ create_file_list (GtkFileChooserDefault *impl) | |
file_list_set_sort_column_ids (impl); | |
update_cell_renderer_attributes (impl); | |
+ return impl->browse_files_tree_view; | |
+} | |
+ | |
+/* Creates icon view (alternative for the list view) */ | |
+static GtkWidget * | |
+create_browse_files_icon_view (GtkFileChooserDefault *impl) | |
+{ | |
+ impl->browse_files_icon_view = gtk_icon_view_new (); | |
+ gtk_icon_view_set_text_column (GTK_ICON_VIEW (impl->browse_files_icon_view), | |
+ MODEL_COL_NAME); | |
+ gtk_icon_view_set_pixbuf_column (GTK_ICON_VIEW (impl->browse_files_icon_view), | |
+ MODEL_COL_ICON_PIXBUF); | |
+ gtk_icon_view_set_item_width (GTK_ICON_VIEW (impl->browse_files_icon_view), | |
+ ICON_VIEW_ITEM_WIDTH); | |
+ | |
+ g_signal_connect (impl->browse_files_icon_view, "item-activated", | |
+ G_CALLBACK (icon_item_activated), impl); | |
+ g_signal_connect (impl->browse_files_icon_view, "key-press-event", | |
+ G_CALLBACK (browse_files_key_press_event_cb), impl); | |
+ g_signal_connect (impl->browse_files_icon_view, "selection-changed", | |
+ G_CALLBACK (list_selection_changed), impl); | |
+ g_signal_connect (impl->browse_files_icon_view, "popup-menu", | |
+ G_CALLBACK (list_popup_menu_cb), impl); | |
+ g_signal_connect (impl->browse_files_icon_view, "button-press-event", | |
+ G_CALLBACK (list_button_press_event_cb), impl); | |
+ | |
+ gtk_drag_dest_set (impl->browse_files_icon_view, | |
+ GTK_DEST_DEFAULT_ALL, | |
+ NULL, 0, | |
+ GDK_ACTION_COPY | GDK_ACTION_MOVE); | |
+ gtk_drag_dest_add_uri_targets (impl->browse_files_icon_view); | |
+ g_signal_connect (impl->browse_files_icon_view, "drag-data-received", | |
+ G_CALLBACK (file_list_drag_data_received_cb), impl); | |
+ g_signal_connect (impl->browse_files_icon_view, "drag-drop", | |
+ G_CALLBACK (file_list_drag_drop_cb), impl); | |
+ g_signal_connect (impl->browse_files_icon_view, "drag-motion", | |
+ G_CALLBACK (file_list_drag_motion_cb), impl); | |
+ gtk_icon_view_enable_model_drag_source (GTK_ICON_VIEW (impl->browse_files_icon_view), | |
+ GDK_BUTTON1_MASK, | |
+ NULL, 0, | |
+ GDK_ACTION_COPY | GDK_ACTION_MOVE); | |
+ gtk_drag_source_add_uri_targets (impl->browse_files_icon_view); | |
+ | |
+ impl->list_name_renderer = gtk_cell_renderer_text_new (); | |
+ g_object_set (impl->list_name_renderer, | |
+ "ellipsize", PANGO_ELLIPSIZE_END, | |
+ NULL); | |
+ g_signal_connect (impl->list_name_renderer, "edited", | |
+ G_CALLBACK (renderer_edited_cb), impl); | |
+ g_signal_connect (impl->list_name_renderer, "editing-canceled", | |
+ G_CALLBACK (renderer_editing_canceled_cb), impl); | |
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (impl->browse_files_icon_view), | |
+ impl->list_name_renderer, | |
+ TRUE); | |
+ | |
+ return impl->browse_files_icon_view; | |
+} | |
+ | |
+/* Creates the widgets for the file list */ | |
+static GtkWidget * | |
+create_file_list (GtkFileChooserDefault *impl) | |
+{ | |
+ GtkWidget *swin; | |
+ | |
+ /* Scrolled window */ | |
+ swin = gtk_scrolled_window_new (NULL, NULL); | |
+ impl->browse_files_scrolled_window = swin; | |
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swin), | |
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); | |
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (swin), | |
+ GTK_SHADOW_IN); | |
+ | |
+ /* Initially VIEW_MODE_LIST is used, settings_load may change this later. */ | |
+ create_browse_files_tree_view (impl); | |
+ impl->browse_files_current_view = impl->browse_files_tree_view; | |
+ gtk_container_add (GTK_CONTAINER (swin), impl->browse_files_tree_view); | |
+ | |
gtk_widget_show_all (swin); | |
return swin; | |
@@ -4734,7 +4871,7 @@ location_mode_set (GtkFileChooserDefault *impl, | |
location_switch_to_path_bar (impl); | |
if (switch_to_file_list) | |
- gtk_widget_grab_focus (impl->browse_files_tree_view); | |
+ gtk_widget_grab_focus (impl->browse_files_current_view); | |
break; | |
@@ -4794,6 +4931,75 @@ location_toggle_popup_handler (GtkFileChooserDefault *impl) | |
} | |
} | |
+/* Callback used when view mode combo box active item is changed */ | |
+static void | |
+view_mode_set (GtkFileChooserDefault *impl, ViewMode view_mode) | |
+{ | |
+ GtkWidget *old_view = NULL; | |
+ ViewMode old_view_mode = impl->view_mode; | |
+ | |
+ if (old_view_mode == view_mode) | |
+ return; | |
+ | |
+ impl->view_mode = view_mode; | |
+ gtk_combo_box_set_active (GTK_COMBO_BOX (impl->view_mode_combo_box), | |
+ view_mode); | |
+ | |
+ /* Creating the target view */ | |
+ if (view_mode == VIEW_MODE_ICON) | |
+ { | |
+ create_browse_files_icon_view (impl); | |
+ impl->browse_files_current_view = impl->browse_files_icon_view; | |
+ old_view = impl->browse_files_tree_view; | |
+ } | |
+ else if (view_mode == VIEW_MODE_LIST) | |
+ { | |
+ create_browse_files_tree_view (impl); | |
+ impl->browse_files_current_view = impl->browse_files_tree_view; | |
+ old_view = impl->browse_files_icon_view; | |
+ } | |
+ else | |
+ g_assert_not_reached (); | |
+ | |
+ /* Set model and selection */ | |
+ current_view_set_file_model (impl, impl->current_model); | |
+ current_view_set_select_multiple (impl, impl->select_multiple); | |
+ copy_old_selection_to_current_view (impl, old_view_mode); | |
+ | |
+ /* Destroy the old view */ | |
+ if (view_mode == VIEW_MODE_ICON) | |
+ { | |
+ impl->browse_files_tree_view = NULL; | |
+ impl->list_name_column = NULL; | |
+ impl->list_mtime_column = NULL; | |
+ impl->list_size_column = NULL; | |
+ } | |
+ else if (view_mode == VIEW_MODE_LIST) | |
+ impl->browse_files_icon_view = NULL; | |
+ else | |
+ g_assert_not_reached (); | |
+ | |
+ if (impl->browse_shortcuts_popup_menu) | |
+ gtk_menu_detach (GTK_MENU (impl->browse_shortcuts_popup_menu)); | |
+ | |
+ gtk_widget_destroy (old_view); | |
+ | |
+ /* Display the new view */ | |
+ gtk_container_add (GTK_CONTAINER (impl->browse_files_scrolled_window), | |
+ impl->browse_files_current_view); | |
+ gtk_widget_show (impl->browse_files_current_view); | |
+} | |
+ | |
+/* Callback used when view mode combo box active item is changed */ | |
+static void | |
+view_mode_combo_box_changed_cb (GtkComboBox *combo, | |
+ GtkFileChooserDefault *impl) | |
+{ | |
+ ViewMode target = gtk_combo_box_get_active (combo); | |
+ | |
+ view_mode_set (impl, target); | |
+} | |
+ | |
/* Callback used when one of the location mode buttons is toggled */ | |
static void | |
location_button_toggled_cb (GtkToggleButton *toggle, | |
@@ -4818,6 +5024,22 @@ location_button_toggled_cb (GtkToggleButton *toggle, | |
location_mode_set (impl, new_mode, FALSE); | |
} | |
+/* Creates a combo box with two items: List View and Icon View. */ | |
+static void | |
+view_mode_combo_box_create (GtkFileChooserDefault *impl) | |
+{ | |
+ impl->view_mode_combo_box = gtk_combo_box_text_new(); | |
+ gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT(impl->view_mode_combo_box), | |
+ "List View"); /* VIEW_MODE_LIST */ | |
+ gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT(impl->view_mode_combo_box), | |
+ "Icon View"); /* VIEW_MODE_ICON */ | |
+ gtk_combo_box_set_active (GTK_COMBO_BOX(impl->view_mode_combo_box), | |
+ VIEW_MODE_LIST); | |
+ | |
+ g_signal_connect (impl->view_mode_combo_box, "changed", | |
+ G_CALLBACK (view_mode_combo_box_changed_cb), impl); | |
+} | |
+ | |
/* Creates a toggle button for the location entry. */ | |
static void | |
location_button_create (GtkFileChooserDefault *impl) | |
@@ -4937,6 +5159,10 @@ path_bar_widgets_create (GtkFileChooserDefault *impl) | |
impl->browse_path_bar_size_group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL); | |
gtk_size_group_set_ignore_hidden (impl->browse_path_bar_size_group, FALSE); | |
+ /* View mode combo box */ | |
+ view_mode_combo_box_create (impl); | |
+ gtk_box_pack_start (GTK_BOX (impl->browse_path_bar_hbox), impl->view_mode_combo_box, FALSE, FALSE, 0); | |
+ | |
/* Location button */ | |
location_button_create (impl); | |
gtk_size_group_add_widget (impl->browse_path_bar_size_group, impl->location_button); | |
@@ -5202,18 +5428,10 @@ set_select_multiple (GtkFileChooserDefault *impl, | |
gboolean select_multiple, | |
gboolean property_notify) | |
{ | |
- GtkTreeSelection *selection; | |
- GtkSelectionMode mode; | |
- | |
if (select_multiple == impl->select_multiple) | |
return; | |
- mode = select_multiple ? GTK_SELECTION_MULTIPLE : GTK_SELECTION_SINGLE; | |
- | |
- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view)); | |
- gtk_tree_selection_set_mode (selection, mode); | |
- | |
- gtk_tree_view_set_rubber_banding (GTK_TREE_VIEW (impl->browse_files_tree_view), select_multiple); | |
+ current_view_set_select_multiple (impl, select_multiple); | |
impl->select_multiple = select_multiple; | |
g_object_notify (G_OBJECT (impl), "select-multiple"); | |
@@ -5529,6 +5747,12 @@ update_appearance (GtkFileChooserDefault *impl) | |
location_mode_set (impl, impl->location_mode, TRUE); | |
} | |
+ if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN || | |
+ impl->action == GTK_FILE_CHOOSER_ACTION_SAVE) | |
+ gtk_widget_show (impl->view_mode_combo_box); | |
+ else | |
+ gtk_widget_hide (impl->view_mode_combo_box); | |
+ | |
if (impl->location_entry) | |
_gtk_file_chooser_entry_set_action (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), impl->action); | |
@@ -5538,7 +5762,7 @@ update_appearance (GtkFileChooserDefault *impl) | |
/* This *is* needed; we need to redraw the file list because the "sensitivity" | |
* of files may change depending whether we are in a file or folder-only mode. | |
*/ | |
- gtk_widget_queue_draw (impl->browse_files_tree_view); | |
+ gtk_widget_queue_draw (impl->browse_files_current_view); | |
emit_default_size_changed (impl); | |
} | |
@@ -5891,20 +6115,31 @@ change_icon_theme (GtkFileChooserDefault *impl) | |
settings = gtk_settings_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (impl))); | |
if (gtk_icon_size_lookup_for_settings (settings, GTK_ICON_SIZE_MENU, &width, &height)) | |
- impl->icon_size = MAX (width, height); | |
+ impl->icon_size_for_list_view = MAX (width, height); | |
+ else | |
+ impl->icon_size_for_list_view = FALLBACK_ICON_SIZE_FOR_LIST_VIEW; | |
+ | |
+ if (gtk_icon_size_lookup_for_settings (settings, GTK_ICON_SIZE_DIALOG, &width, &height)) | |
+ impl->icon_size_for_icon_view = MAX (width, height); | |
else | |
- impl->icon_size = FALLBACK_ICON_SIZE; | |
+ impl->icon_size_for_icon_view = FALLBACK_ICON_SIZE_FOR_ICON_VIEW; | |
shortcuts_reload_icons (impl); | |
/* the first cell in the first column is the icon column, and we have a fixed size there */ | |
- cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT ( | |
- gtk_tree_view_get_column (GTK_TREE_VIEW (impl->browse_files_tree_view), 0))); | |
- renderer = GTK_CELL_RENDERER (cells->data); | |
- set_icon_cell_renderer_fixed_size (impl, renderer); | |
- g_list_free (cells); | |
+ if (impl->view_mode == VIEW_MODE_LIST) | |
+ { | |
+ cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT ( | |
+ gtk_tree_view_get_column (GTK_TREE_VIEW (impl->browse_files_tree_view), 0))); | |
+ renderer = GTK_CELL_RENDERER (cells->data); | |
+ set_icon_cell_renderer_fixed_size (impl, renderer); | |
+ g_list_free (cells); | |
+ } | |
if (impl->browse_files_model) | |
- _gtk_file_system_model_clear_cache (impl->browse_files_model, MODEL_COL_PIXBUF); | |
- gtk_widget_queue_resize (impl->browse_files_tree_view); | |
+ { | |
+ _gtk_file_system_model_clear_cache (impl->browse_files_model, MODEL_COL_LIST_PIXBUF); | |
+ _gtk_file_system_model_clear_cache (impl->browse_files_model, MODEL_COL_ICON_PIXBUF); | |
+ } | |
+ gtk_widget_queue_resize (impl->browse_files_current_view); | |
profile_end ("end", NULL); | |
} | |
@@ -6003,7 +6238,7 @@ set_sort_column (GtkFileChooserDefault *impl) | |
{ | |
GtkTreeSortable *sortable; | |
- sortable = GTK_TREE_SORTABLE (gtk_tree_view_get_model (GTK_TREE_VIEW (impl->browse_files_tree_view))); | |
+ sortable = GTK_TREE_SORTABLE (impl->current_model); | |
/* can happen when we're still populating the model */ | |
if (sortable == NULL) | |
@@ -6018,6 +6253,7 @@ static void | |
settings_load (GtkFileChooserDefault *impl) | |
{ | |
LocationMode location_mode; | |
+ ViewMode view_mode; | |
gboolean show_hidden; | |
gboolean show_size_column; | |
gint sort_column; | |
@@ -6028,6 +6264,7 @@ settings_load (GtkFileChooserDefault *impl) | |
settings = _gtk_file_chooser_get_settings_for_widget (GTK_WIDGET (impl)); | |
location_mode = g_settings_get_enum (settings, SETTINGS_KEY_LOCATION_MODE); | |
+ view_mode = g_settings_get_enum (settings, SETTINGS_KEY_VIEW_MODE); | |
show_hidden = g_settings_get_boolean (settings, SETTINGS_KEY_SHOW_HIDDEN); | |
show_size_column = g_settings_get_boolean (settings, SETTINGS_KEY_SHOW_SIZE_COLUMN); | |
sort_column = g_settings_get_enum (settings, SETTINGS_KEY_SORT_COLUMN); | |
@@ -6035,11 +6272,13 @@ settings_load (GtkFileChooserDefault *impl) | |
sidebar_width = g_settings_get_int (settings, SETTINGS_KEY_SIDEBAR_WIDTH); | |
location_mode_set (impl, location_mode, TRUE); | |
+ view_mode_set (impl, view_mode); | |
gtk_file_chooser_set_show_hidden (GTK_FILE_CHOOSER (impl), show_hidden); | |
impl->show_size_column = show_size_column; | |
- gtk_tree_view_column_set_visible (impl->list_size_column, show_size_column); | |
+ if (impl->list_size_column) | |
+ gtk_tree_view_column_set_visible (impl->list_size_column, show_size_column); | |
impl->sort_column = sort_column; | |
impl->sort_order = sort_order; | |
@@ -6061,6 +6300,7 @@ settings_save (GtkFileChooserDefault *impl) | |
/* All the other state */ | |
g_settings_set_enum (settings, SETTINGS_KEY_LOCATION_MODE, impl->location_mode); | |
+ g_settings_set_enum (settings, SETTINGS_KEY_VIEW_MODE, impl->view_mode); | |
g_settings_set_boolean (settings, SETTINGS_KEY_SHOW_HIDDEN, | |
gtk_file_chooser_get_show_hidden (GTK_FILE_CHOOSER (impl))); | |
g_settings_set_boolean (settings, SETTINGS_KEY_SHOW_SIZE_COLUMN, impl->show_size_column); | |
@@ -6103,7 +6343,7 @@ gtk_file_chooser_default_map (GtkWidget *widget) | |
switch (impl->reload_state) | |
{ | |
case RELOAD_EMPTY: | |
- recent_shortcut_handler (impl); | |
+ recent_shortcut_handler (impl); | |
break; | |
case RELOAD_HAS_FOLDER: | |
@@ -6273,12 +6513,16 @@ load_set_model (GtkFileChooserDefault *impl) | |
g_assert (impl->browse_files_model != NULL); | |
profile_msg (" gtk_tree_view_set_model start", NULL); | |
- gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view), | |
- GTK_TREE_MODEL (impl->browse_files_model)); | |
- gtk_tree_view_columns_autosize (GTK_TREE_VIEW (impl->browse_files_tree_view)); | |
- gtk_tree_view_set_search_column (GTK_TREE_VIEW (impl->browse_files_tree_view), | |
- MODEL_COL_NAME); | |
- file_list_set_sort_column_ids (impl); | |
+ current_view_set_file_model (impl, GTK_TREE_MODEL (impl->browse_files_model)); | |
+ | |
+ if (impl->view_mode == VIEW_MODE_LIST) | |
+ { | |
+ gtk_tree_view_columns_autosize (GTK_TREE_VIEW (impl->browse_files_tree_view)); | |
+ gtk_tree_view_set_search_column (GTK_TREE_VIEW (impl->browse_files_tree_view), | |
+ MODEL_COL_NAME); | |
+ file_list_set_sort_column_ids (impl); | |
+ } | |
+ | |
set_sort_column (impl); | |
profile_msg (" gtk_tree_view_set_model end", NULL); | |
impl->list_sort_ascending = TRUE; | |
@@ -6350,7 +6594,7 @@ browse_files_select_first_row (GtkFileChooserDefault *impl) | |
GtkTreeIter dummy_iter; | |
GtkTreeModel *tree_model; | |
- tree_model = gtk_tree_view_get_model (GTK_TREE_VIEW (impl->browse_files_tree_view)); | |
+ tree_model = impl->current_model; | |
if (!tree_model) | |
return; | |
@@ -6359,7 +6603,9 @@ browse_files_select_first_row (GtkFileChooserDefault *impl) | |
/* If the list is empty, do nothing. */ | |
if (gtk_tree_model_get_iter (tree_model, &dummy_iter, path)) | |
- gtk_tree_view_set_cursor (GTK_TREE_VIEW (impl->browse_files_tree_view), path, NULL, FALSE); | |
+ { | |
+ current_view_set_cursor (impl, path); | |
+ } | |
gtk_tree_path_free (path); | |
} | |
@@ -6384,7 +6630,13 @@ center_selected_row_foreach_cb (GtkTreeModel *model, | |
if (closure->already_centered) | |
return; | |
- gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (closure->impl->browse_files_tree_view), path, NULL, TRUE, 0.5, 0.0); | |
+ if (closure->impl->view_mode == VIEW_MODE_LIST) | |
+ gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (closure->impl->browse_files_tree_view), path, NULL, TRUE, 0.5, 0.0); | |
+ else if (closure->impl->view_mode == VIEW_MODE_ICON) | |
+ gtk_icon_view_scroll_to_path (GTK_ICON_VIEW (closure->impl->browse_files_icon_view), path, TRUE, 0.5, 0.0); | |
+ else | |
+ g_assert_not_reached (); | |
+ | |
closure->already_centered = TRUE; | |
} | |
@@ -6393,20 +6645,16 @@ static void | |
browse_files_center_selected_row (GtkFileChooserDefault *impl) | |
{ | |
struct center_selected_row_closure closure; | |
- GtkTreeSelection *selection; | |
- | |
closure.impl = impl; | |
closure.already_centered = FALSE; | |
- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view)); | |
- gtk_tree_selection_selected_foreach (selection, center_selected_row_foreach_cb, &closure); | |
+ current_selection_selected_foreach(impl, center_selected_row_foreach_cb, &closure); | |
} | |
static gboolean | |
show_and_select_files (GtkFileChooserDefault *impl, | |
GSList *files) | |
{ | |
- GtkTreeSelection *selection; | |
GtkFileSystemModel *fsmodel; | |
gboolean enabled_hidden, removed_filters; | |
gboolean selected_a_file; | |
@@ -6415,8 +6663,7 @@ show_and_select_files (GtkFileChooserDefault *impl, | |
g_assert (impl->load_state == LOAD_FINISHED); | |
g_assert (impl->browse_files_model != NULL); | |
- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view)); | |
- fsmodel = GTK_FILE_SYSTEM_MODEL (gtk_tree_view_get_model (GTK_TREE_VIEW (impl->browse_files_tree_view))); | |
+ fsmodel = GTK_FILE_SYSTEM_MODEL (impl->current_model); | |
g_assert (fsmodel == impl->browse_files_model); | |
@@ -6472,11 +6719,10 @@ show_and_select_files (GtkFileChooserDefault *impl, | |
{ | |
GtkTreePath *path; | |
- gtk_tree_selection_select_iter (selection, &iter); | |
+ current_selection_select_iter (impl, &iter); | |
path = gtk_tree_model_get_path (GTK_TREE_MODEL (fsmodel), &iter); | |
- gtk_tree_view_set_cursor (GTK_TREE_VIEW (impl->browse_files_tree_view), | |
- path, NULL, FALSE); | |
+ current_view_set_cursor (impl, path); | |
gtk_tree_path_free (path); | |
selected_a_file = TRUE; | |
@@ -6591,12 +6837,14 @@ stop_loading_and_clear_list_model (GtkFileChooserDefault *impl, | |
if (impl->browse_files_model) | |
{ | |
+ if (impl->current_model == GTK_TREE_MODEL (impl->browse_files_model)) | |
+ impl->current_model = NULL; | |
g_object_unref (impl->browse_files_model); | |
impl->browse_files_model = NULL; | |
} | |
if (remove_from_treeview) | |
- gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view), NULL); | |
+ current_view_set_file_model (impl, NULL); | |
} | |
static char * | |
@@ -6749,6 +6997,17 @@ file_system_model_got_thumbnail (GObject *object, GAsyncResult *res, gpointer da | |
} | |
static gboolean | |
+get_visible_range (GtkTreePath **start, GtkTreePath **end, | |
+ GtkFileChooserDefault *impl) | |
+{ | |
+ if (impl->view_mode == VIEW_MODE_LIST) | |
+ return gtk_tree_view_get_visible_range (GTK_TREE_VIEW (impl->browse_files_tree_view), start, end); | |
+ if (impl->view_mode == VIEW_MODE_ICON) | |
+ return gtk_icon_view_get_visible_range (GTK_ICON_VIEW (impl->browse_files_icon_view), start, end); | |
+ g_assert_not_reached (); | |
+} | |
+ | |
+static gboolean | |
file_system_model_set (GtkFileSystemModel *model, | |
GFile *file, | |
GFileInfo *info, | |
@@ -6806,38 +7065,59 @@ file_system_model_set (GtkFileSystemModel *model, | |
else | |
g_value_set_boolean (value, TRUE); | |
break; | |
- case MODEL_COL_PIXBUF: | |
+ case MODEL_COL_LIST_PIXBUF: | |
+ case MODEL_COL_ICON_PIXBUF: | |
if (info) | |
{ | |
+ GtkTreeModel *tree_model; | |
+ GtkTreePath *path, *start, *end; | |
+ GtkTreeIter iter; | |
+ gboolean file_visible; | |
+ | |
+ /* not loading icon view's icon in the list view */ | |
+ if (column == MODEL_COL_ICON_PIXBUF && impl->view_mode == VIEW_MODE_LIST) | |
+ return FALSE; | |
+ | |
+ tree_model = impl->current_model; | |
+ if (tree_model != GTK_TREE_MODEL (model)) | |
+ return FALSE; | |
+ | |
+ /* #1 use standard icon if it is loaded */ | |
if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_ICON)) | |
{ | |
- g_value_take_object (value, _gtk_file_info_render_icon (info, GTK_WIDGET (impl), impl->icon_size)); | |
+ gint icon_size; | |
+ | |
+ if (column == MODEL_COL_ICON_PIXBUF) | |
+ icon_size = impl->icon_size_for_icon_view; | |
+ else | |
+ icon_size = impl->icon_size_for_list_view; | |
+ | |
+ g_value_take_object (value, _gtk_file_info_render_icon (info, GTK_WIDGET (impl), icon_size)); | |
+ return TRUE; | |
} | |
- else | |
- { | |
- GtkTreeModel *tree_model; | |
- GtkTreePath *path, *start, *end; | |
- GtkTreeIter iter; | |
- if (impl->browse_files_tree_view == NULL || | |
- g_file_info_has_attribute (info, "filechooser::queried")) | |
- return FALSE; | |
+ if (!get_visible_range (&start, &end, impl)) | |
+ return FALSE; | |
- tree_model = gtk_tree_view_get_model (GTK_TREE_VIEW (impl->browse_files_tree_view)); | |
- if (tree_model != GTK_TREE_MODEL (model)) | |
- return FALSE; | |
+ if (!_gtk_file_system_model_get_iter_for_file (model, | |
+ &iter, | |
+ file)) | |
+ g_assert_not_reached (); | |
- if (!_gtk_file_system_model_get_iter_for_file (model, | |
- &iter, | |
- file)) | |
- g_assert_not_reached (); | |
- if (!gtk_tree_view_get_visible_range (GTK_TREE_VIEW (impl->browse_files_tree_view), &start, &end)) | |
- return FALSE; | |
- path = gtk_tree_model_get_path (tree_model, &iter); | |
- if (gtk_tree_path_compare (start, path) != 1 && | |
- gtk_tree_path_compare (path, end) != 1) | |
+ path = gtk_tree_model_get_path (tree_model, &iter); | |
+ file_visible = (gtk_tree_path_compare (start, path) != 1 && | |
+ gtk_tree_path_compare (path, end) != 1); | |
+ | |
+ gtk_tree_path_free (path); | |
+ gtk_tree_path_free (start); | |
+ gtk_tree_path_free (end); | |
+ | |
+ if (file_visible) | |
+ { | |
+ /* #2 start loading standard icon (callback will be handled by #1) */ | |
+ if (!g_file_info_has_attribute (info, "filechooser::icon_queried")) | |
{ | |
- g_file_info_set_attribute_boolean (info, "filechooser::queried", TRUE); | |
+ g_file_info_set_attribute_boolean (info, "filechooser::icon_queried", TRUE); | |
g_file_query_info_async (file, | |
G_FILE_ATTRIBUTE_THUMBNAIL_PATH "," | |
G_FILE_ATTRIBUTE_THUMBNAILING_FAILED "," | |
@@ -6848,14 +7128,24 @@ file_system_model_set (GtkFileSystemModel *model, | |
file_system_model_got_thumbnail, | |
model); | |
} | |
- gtk_tree_path_free (path); | |
- gtk_tree_path_free (start); | |
- gtk_tree_path_free (end); | |
- return FALSE; | |
+ | |
} | |
+ return FALSE; | |
} | |
else | |
- g_value_set_object (value, NULL); | |
+ { | |
+ if (column == MODEL_COL_ICON_PIXBUF) | |
+ { | |
+ g_value_take_object (value, | |
+ gtk_icon_theme_load_icon (gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (impl))), | |
+ "inode-directory", | |
+ impl->icon_size_for_icon_view, | |
+ 0, | |
+ NULL)); | |
+ } | |
+ else | |
+ g_value_set_object (value, NULL); | |
+ } | |
break; | |
case MODEL_COL_SIZE: | |
g_value_set_int64 (value, info ? g_file_info_get_size (info) : 0); | |
@@ -6977,7 +7267,6 @@ update_chooser_entry_selected_foreach (GtkTreeModel *model, | |
static void | |
update_chooser_entry (GtkFileChooserDefault *impl) | |
{ | |
- GtkTreeSelection *selection; | |
struct update_chooser_entry_selected_foreach_closure closure; | |
/* no need to update the file chooser's entry if there's no entry */ | |
@@ -6994,9 +7283,8 @@ update_chooser_entry (GtkFileChooserDefault *impl) | |
g_assert (impl->location_entry != NULL); | |
- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view)); | |
closure.num_selected = 0; | |
- gtk_tree_selection_selected_foreach (selection, update_chooser_entry_selected_foreach, &closure); | |
+ current_selection_selected_foreach (impl, update_chooser_entry_selected_foreach, &closure); | |
if (closure.num_selected == 0) | |
{ | |
@@ -7467,7 +7755,6 @@ gtk_file_chooser_default_unselect_file (GtkFileChooser *chooser, | |
GFile *file) | |
{ | |
GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser); | |
- GtkTreeView *tree_view = GTK_TREE_VIEW (impl->browse_files_tree_view); | |
GtkTreeIter iter; | |
if (!impl->browse_files_model) | |
@@ -7478,8 +7765,7 @@ gtk_file_chooser_default_unselect_file (GtkFileChooser *chooser, | |
file)) | |
return; | |
- gtk_tree_selection_unselect_iter (gtk_tree_view_get_selection (tree_view), | |
- &iter); | |
+ current_selection_unselect_iter (impl, &iter); | |
} | |
static gboolean | |
@@ -7489,12 +7775,9 @@ maybe_select (GtkTreeModel *model, | |
gpointer data) | |
{ | |
GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (data); | |
- GtkTreeSelection *selection; | |
gboolean is_sensitive; | |
gboolean is_folder; | |
- | |
- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view)); | |
- | |
+ | |
gtk_tree_model_get (model, iter, | |
MODEL_COL_IS_FOLDER, &is_folder, | |
MODEL_COL_IS_SENSITIVE, &is_sensitive, | |
@@ -7503,9 +7786,9 @@ maybe_select (GtkTreeModel *model, | |
if (is_sensitive && | |
((is_folder && impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER) || | |
(!is_folder && impl->action == GTK_FILE_CHOOSER_ACTION_OPEN))) | |
- gtk_tree_selection_select_iter (selection, iter); | |
+ current_selection_select_iter (impl, iter); | |
else | |
- gtk_tree_selection_unselect_iter (selection, iter); | |
+ current_selection_unselect_iter (impl, iter); | |
return FALSE; | |
} | |
@@ -7520,8 +7803,15 @@ gtk_file_chooser_default_select_all (GtkFileChooser *chooser) | |
{ | |
GtkTreeSelection *selection; | |
- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view)); | |
- gtk_tree_selection_select_all (selection); | |
+ if (impl->view_mode == VIEW_MODE_LIST) | |
+ { | |
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view)); | |
+ gtk_tree_selection_select_all (selection); | |
+ } | |
+ else if (impl->view_mode == VIEW_MODE_ICON) | |
+ gtk_icon_view_select_all (GTK_ICON_VIEW (impl->browse_files_icon_view)); | |
+ else | |
+ g_assert_not_reached(); | |
return; | |
} | |
@@ -7534,9 +7824,8 @@ static void | |
gtk_file_chooser_default_unselect_all (GtkFileChooser *chooser) | |
{ | |
GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser); | |
- GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view)); | |
- gtk_tree_selection_unselect_all (selection); | |
+ current_selection_unselect_all (impl); | |
pending_select_files_free (impl); | |
} | |
@@ -7689,15 +7978,13 @@ gtk_file_chooser_default_get_files (GtkFileChooser *chooser) | |
current_focus = NULL; | |
file_list_seen = FALSE; | |
- if (current_focus == impl->browse_files_tree_view) | |
+ if (current_focus == impl->browse_files_current_view) | |
{ | |
- GtkTreeSelection *selection; | |
- | |
file_list: | |
file_list_seen = TRUE; | |
- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view)); | |
- gtk_tree_selection_selected_foreach (selection, get_files_foreach, &info); | |
+ | |
+ current_selection_selected_foreach (impl, get_files_foreach, &info); | |
/* If there is no selection in the file list, we probably have this situation: | |
* | |
@@ -7737,7 +8024,7 @@ gtk_file_chooser_default_get_files (GtkFileChooser *chooser) | |
else | |
return NULL; | |
} | |
- else if (impl->toplevel_last_focus_widget == impl->browse_files_tree_view) | |
+ else if (impl->toplevel_last_focus_widget == impl->browse_files_current_view) | |
goto file_list; | |
else if (impl->location_entry && impl->toplevel_last_focus_widget == impl->location_entry) | |
goto file_entry; | |
@@ -8207,7 +8494,6 @@ switch_folder_foreach_cb (GtkTreeModel *model, | |
static void | |
switch_to_selected_folder (GtkFileChooserDefault *impl) | |
{ | |
- GtkTreeSelection *selection; | |
struct switch_folder_closure closure; | |
/* We do this with foreach() rather than get_selected() as we may be in | |
@@ -8218,8 +8504,7 @@ switch_to_selected_folder (GtkFileChooserDefault *impl) | |
closure.file = NULL; | |
closure.num_selected = 0; | |
- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view)); | |
- gtk_tree_selection_selected_foreach (selection, switch_folder_foreach_cb, &closure); | |
+ current_selection_selected_foreach (impl, switch_folder_foreach_cb, &closure); | |
g_assert (closure.file && closure.num_selected == 1); | |
@@ -8238,14 +8523,29 @@ get_selected_file_info_from_file_list (GtkFileChooserDefault *impl, | |
GFileInfo *info; | |
g_assert (!impl->select_multiple); | |
- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view)); | |
- if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) | |
+ | |
+ if (impl->view_mode == VIEW_MODE_LIST) | |
{ | |
- *had_selection = FALSE; | |
- return NULL; | |
- } | |
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view)); | |
+ if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) | |
+ { | |
+ *had_selection = FALSE; | |
+ return NULL; | |
+ } | |
- *had_selection = TRUE; | |
+ *had_selection = TRUE; | |
+ } | |
+ else if (impl->view_mode == VIEW_MODE_ICON) | |
+ { | |
+ if (!get_selected_tree_iter_from_icon_view (impl, &iter)) | |
+ { | |
+ *had_selection = FALSE; | |
+ return NULL; | |
+ } | |
+ *had_selection = TRUE; | |
+ } | |
+ else | |
+ g_assert_not_reached(); | |
info = _gtk_file_system_model_get_info (impl->browse_files_model, &iter); | |
return info; | |
@@ -8726,7 +9026,7 @@ gtk_file_chooser_default_should_respond (GtkFileChooserEmbed *chooser_embed) | |
current_focus = gtk_window_get_focus (GTK_WINDOW (toplevel)); | |
- if (current_focus == impl->browse_files_tree_view) | |
+ if (current_focus == impl->browse_files_current_view) | |
{ | |
/* The following array encodes what we do based on the impl->action and the | |
* number of files selected. | |
@@ -8936,7 +9236,7 @@ gtk_file_chooser_default_should_respond (GtkFileChooserEmbed *chooser_embed) | |
g_object_unref (file); | |
} | |
- else if (impl->toplevel_last_focus_widget == impl->browse_files_tree_view) | |
+ else if (impl->toplevel_last_focus_widget == impl->browse_files_current_view) | |
{ | |
/* The focus is on a dialog's action area button, *and* the widget that | |
* was focused immediately before it is the file list. | |
@@ -8985,7 +9285,7 @@ gtk_file_chooser_default_initial_focus (GtkFileChooserEmbed *chooser_embed) | |
{ | |
if (impl->location_mode == LOCATION_MODE_PATH_BAR | |
|| impl->operation_mode == OPERATION_MODE_RECENT) | |
- widget = impl->browse_files_tree_view; | |
+ widget = impl->browse_files_current_view; | |
else | |
widget = impl->location_entry; | |
} | |
@@ -9023,12 +9323,9 @@ static GSList * | |
search_get_selected_files (GtkFileChooserDefault *impl) | |
{ | |
GSList *result; | |
- GtkTreeSelection *selection; | |
- | |
result = NULL; | |
- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view)); | |
- gtk_tree_selection_selected_foreach (selection, search_selected_foreach_get_file_cb, &result); | |
+ current_selection_selected_foreach (impl, search_selected_foreach_get_file_cb, &result); | |
result = g_slist_reverse (result); | |
return result; | |
@@ -9040,12 +9337,8 @@ search_get_selected_files (GtkFileChooserDefault *impl) | |
static gboolean | |
search_should_respond (GtkFileChooserDefault *impl) | |
{ | |
- GtkTreeSelection *selection; | |
- | |
g_assert (impl->operation_mode == OPERATION_MODE_SEARCH); | |
- | |
- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view)); | |
- return (gtk_tree_selection_count_selected_rows (selection) != 0); | |
+ return (current_selection_count_selected_rows (impl) != 0); | |
} | |
/* Adds one hit from the search engine to the search_model */ | |
@@ -9102,6 +9395,7 @@ search_engine_finished_cb (GtkSearchEngine *engine, | |
*/ | |
gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view), | |
GTK_TREE_MODEL (impl->search_model)); | |
+ current_view_set_file_model (impl, GTK_TREE_MODEL (impl->search_model)); | |
file_list_set_sort_column_ids (impl); | |
#endif | |
@@ -9149,7 +9443,7 @@ search_clear_model (GtkFileChooserDefault *impl, | |
impl->search_model = NULL; | |
if (remove_from_treeview) | |
- gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view), NULL); | |
+ current_view_set_file_model (impl, NULL); | |
} | |
/* Stops any ongoing searches; does not touch the search_model */ | |
@@ -9200,8 +9494,7 @@ search_setup_model (GtkFileChooserDefault *impl) | |
* more "alive" than setting the model at the end of the search | |
* run | |
*/ | |
- gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view), | |
- GTK_TREE_MODEL (impl->search_model)); | |
+ current_view_set_file_model (impl, GTK_TREE_MODEL (impl->search_model)); | |
file_list_set_sort_column_ids (impl); | |
} | |
@@ -9365,7 +9658,7 @@ recent_clear_model (GtkFileChooserDefault *impl, | |
return; | |
if (remove_from_treeview) | |
- gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view), NULL); | |
+ current_view_set_file_model (impl, NULL); | |
g_object_unref (impl->recent_model); | |
impl->recent_model = NULL; | |
@@ -9422,8 +9715,7 @@ recent_idle_cleanup (gpointer data) | |
RecentLoadData *load_data = data; | |
GtkFileChooserDefault *impl = load_data->impl; | |
- gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view), | |
- GTK_TREE_MODEL (impl->recent_model)); | |
+ current_view_set_file_model (impl, GTK_TREE_MODEL (impl->recent_model)); | |
file_list_set_sort_column_ids (impl); | |
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (impl->recent_model), MODEL_COL_MTIME, GTK_SORT_DESCENDING); | |
@@ -9568,12 +9860,9 @@ static GSList * | |
recent_get_selected_files (GtkFileChooserDefault *impl) | |
{ | |
GSList *result; | |
- GtkTreeSelection *selection; | |
- | |
result = NULL; | |
- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view)); | |
- gtk_tree_selection_selected_foreach (selection, recent_selected_foreach_get_file_cb, &result); | |
+ current_selection_selected_foreach (impl, recent_selected_foreach_get_file_cb, &result); | |
result = g_slist_reverse (result); | |
return result; | |
@@ -9585,12 +9874,8 @@ recent_get_selected_files (GtkFileChooserDefault *impl) | |
static gboolean | |
recent_should_respond (GtkFileChooserDefault *impl) | |
{ | |
- GtkTreeSelection *selection; | |
- | |
g_assert (impl->operation_mode == OPERATION_MODE_RECENT); | |
- | |
- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view)); | |
- return (gtk_tree_selection_count_selected_rows (selection) != 0); | |
+ return (current_selection_count_selected_rows (impl) != 0); | |
} | |
static void | |
@@ -9659,9 +9944,16 @@ check_preview_change (GtkFileChooserDefault *impl) | |
char *new_display_name; | |
GtkTreeModel *model; | |
- gtk_tree_view_get_cursor (GTK_TREE_VIEW (impl->browse_files_tree_view), &cursor_path, NULL); | |
- model = gtk_tree_view_get_model (GTK_TREE_VIEW (impl->browse_files_tree_view)); | |
- if (cursor_path) | |
+ if (impl->view_mode == VIEW_MODE_LIST) | |
+ gtk_tree_view_get_cursor (GTK_TREE_VIEW (impl->browse_files_tree_view), &cursor_path, NULL); | |
+ else if (impl->view_mode == VIEW_MODE_ICON) | |
+ gtk_icon_view_get_cursor (GTK_ICON_VIEW (impl->browse_files_icon_view), &cursor_path, NULL); | |
+ else | |
+ g_assert_not_reached (); | |
+ | |
+ model = impl->current_model; | |
+ | |
+ if (cursor_path && model) | |
{ | |
GtkTreeIter iter; | |
@@ -9971,7 +10263,7 @@ shortcuts_key_press_event_cb (GtkWidget *widget, | |
if (key_is_left_or_right (event)) | |
{ | |
- gtk_widget_grab_focus (impl->browse_files_tree_view); | |
+ gtk_widget_grab_focus (impl->browse_files_current_view); | |
return TRUE; | |
} | |
@@ -10042,8 +10334,9 @@ list_select_func (GtkTreeSelection *selection, | |
return TRUE; | |
} | |
+/* GtkTreeSelection or GtkIconView selection changed. */ | |
static void | |
-list_selection_changed (GtkTreeSelection *selection, | |
+list_selection_changed (void *tree_selection_or_icon_view, | |
GtkFileChooserDefault *impl) | |
{ | |
/* See if we are in the new folder editable row for Save mode */ | |
@@ -10082,14 +10375,33 @@ list_row_activated (GtkTreeView *tree_view, | |
GtkTreeViewColumn *column, | |
GtkFileChooserDefault *impl) | |
{ | |
+ GtkTreeModel *model; | |
+ model = gtk_tree_view_get_model (tree_view); | |
+ item_activated (model, path, impl); | |
+} | |
+ | |
+/* Callback used when a item in the icon file list is activated. */ | |
+static void | |
+icon_item_activated (GtkIconView *icon_view, | |
+ GtkTreePath *path, | |
+ GtkFileChooserDefault *impl) | |
+{ | |
+ GtkTreeModel *model; | |
+ model = gtk_icon_view_get_model (icon_view); | |
+ item_activated (model, path, impl); | |
+} | |
+ | |
+/* Common implementation for list_row_activated and icon_item_activated */ | |
+static void | |
+item_activated (GtkTreeModel *model, | |
+ GtkTreePath *path, | |
+ GtkFileChooserDefault *impl) | |
+{ | |
GFile *file; | |
GtkTreeIter iter; | |
- GtkTreeModel *model; | |
gboolean is_folder; | |
gboolean is_sensitive; | |
- model = gtk_tree_view_get_model (tree_view); | |
- | |
if (!gtk_tree_model_get_iter (model, &iter, path)) | |
return; | |
@@ -10143,6 +10455,10 @@ update_cell_renderer_attributes (GtkFileChooserDefault *impl) | |
GtkCellRenderer *renderer; | |
GList *walk, *list; | |
+ /* only applicable in the tree view (i.e. list view) */ | |
+ if (!impl->browse_files_tree_view) | |
+ return; | |
+ | |
/* Keep the following column numbers in sync with create_file_list() */ | |
/* name */ | |
@@ -10154,7 +10470,7 @@ update_cell_renderer_attributes (GtkFileChooserDefault *impl) | |
if (GTK_IS_CELL_RENDERER_PIXBUF (renderer)) | |
{ | |
gtk_tree_view_column_set_attributes (column, renderer, | |
- "pixbuf", MODEL_COL_PIXBUF, | |
+ "pixbuf", MODEL_COL_LIST_PIXBUF, | |
NULL); | |
} | |
else | |
@@ -10219,7 +10535,7 @@ location_popup_handler (GtkFileChooserDefault *impl, | |
change_folder_and_display_error (impl, impl->current_folder, FALSE); | |
if (impl->location_mode == LOCATION_MODE_PATH_BAR) | |
- widget_to_focus = impl->browse_files_tree_view; | |
+ widget_to_focus = impl->browse_files_current_view; | |
else | |
widget_to_focus = impl->location_entry; | |
@@ -10421,3 +10737,243 @@ shortcuts_pane_model_filter_new (GtkFileChooserDefault *impl, | |
return GTK_TREE_MODEL (model); | |
} | |
+ | |
+static gboolean | |
+get_selected_tree_iter_from_icon_view (GtkFileChooserDefault *impl, | |
+ GtkTreeIter *iter_out) | |
+{ | |
+ GList *icon_selection; | |
+ GtkTreePath *icon_selection_path; | |
+ | |
+ icon_selection = gtk_icon_view_get_selected_items (GTK_ICON_VIEW (impl->browse_files_icon_view)); | |
+ if (!icon_selection) | |
+ return FALSE; | |
+ | |
+ icon_selection_path = g_list_nth_data (icon_selection, 0); | |
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->current_model), | |
+ iter_out, | |
+ icon_selection_path); | |
+ | |
+ g_list_foreach (icon_selection, (GFunc) gtk_tree_path_free, NULL); | |
+ g_list_free (icon_selection); | |
+ return TRUE; | |
+} | |
+ | |
+static void | |
+icon_view_selection_selected_foreach (GtkFileChooserDefault *impl, | |
+ GtkTreeSelectionForeachFunc func, | |
+ gpointer data) | |
+{ | |
+ GtkTreeIter iter; | |
+ GList *icon_selection; | |
+ GList *elem; | |
+ GtkTreePath *icon_selection_path; | |
+ | |
+ icon_selection = gtk_icon_view_get_selected_items (GTK_ICON_VIEW (impl->browse_files_icon_view)); | |
+ for (elem = icon_selection; elem; elem = elem->next) | |
+ { | |
+ icon_selection_path = elem->data; | |
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->current_model), | |
+ &iter, | |
+ icon_selection_path); | |
+ (* func) (GTK_TREE_MODEL (impl->current_model), | |
+ icon_selection_path, | |
+ &iter, | |
+ data); | |
+ } | |
+ | |
+ g_list_foreach (icon_selection, (GFunc) gtk_tree_path_free, NULL); | |
+ g_list_free (icon_selection); | |
+} | |
+ | |
+static void | |
+selection_selected_foreach (GtkFileChooserDefault *impl, | |
+ ViewMode view, | |
+ GtkTreeSelectionForeachFunc func, | |
+ gpointer data) | |
+{ | |
+ if (impl->current_model == NULL) | |
+ return; | |
+ | |
+ if (view == VIEW_MODE_LIST) | |
+ { | |
+ GtkTreeSelection *selection; | |
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view)); | |
+ gtk_tree_selection_selected_foreach (selection, func, data); | |
+ } | |
+ else if (view == VIEW_MODE_ICON) | |
+ icon_view_selection_selected_foreach (impl, func, data); | |
+ else | |
+ g_assert_not_reached (); | |
+} | |
+ | |
+static void | |
+current_selection_selected_foreach (GtkFileChooserDefault *impl, | |
+ GtkTreeSelectionForeachFunc func, | |
+ gpointer data) | |
+{ | |
+ selection_selected_foreach (impl, impl->view_mode, func, data); | |
+} | |
+ | |
+static guint | |
+current_selection_count_selected_rows (GtkFileChooserDefault *impl) | |
+{ | |
+ if (impl->view_mode == VIEW_MODE_LIST) | |
+ { | |
+ GtkTreeSelection *selection; | |
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view)); | |
+ return gtk_tree_selection_count_selected_rows (selection); | |
+ } | |
+ if (impl->view_mode == VIEW_MODE_ICON) | |
+ { | |
+ GList *icon_selection; | |
+ icon_selection = gtk_icon_view_get_selected_items (GTK_ICON_VIEW (impl->browse_files_icon_view)); | |
+ guint count = g_list_length (icon_selection); | |
+ g_list_foreach (icon_selection, (GFunc) gtk_tree_path_free, NULL); | |
+ g_list_free (icon_selection); | |
+ return count; | |
+ } | |
+ g_assert_not_reached (); | |
+ return 0; | |
+} | |
+ | |
+static void | |
+selection_select_iter (GtkFileChooserDefault *impl, | |
+ GtkTreeIter *iter, | |
+ ViewMode target) | |
+{ | |
+ if (target == VIEW_MODE_LIST) | |
+ { | |
+ GtkTreeSelection *selection; | |
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view)); | |
+ gtk_tree_selection_select_iter (selection, iter); | |
+ } | |
+ else if (target == VIEW_MODE_ICON) | |
+ { | |
+ GtkTreePath *path; | |
+ path = gtk_tree_model_get_path (impl->current_model, iter); | |
+ gtk_icon_view_select_path (GTK_ICON_VIEW (impl->browse_files_icon_view), path); | |
+ gtk_tree_path_free (path); | |
+ } | |
+ else | |
+ g_assert_not_reached (); | |
+} | |
+ | |
+static void | |
+current_selection_select_iter (GtkFileChooserDefault *impl, | |
+ GtkTreeIter *iter) | |
+{ | |
+ selection_select_iter (impl, iter, impl->view_mode); | |
+} | |
+ | |
+struct copy_old_selection_to_current_view_closure { | |
+ GtkFileChooserDefault *impl; | |
+}; | |
+ | |
+static void | |
+copy_old_selection_to_current_view_foreach_cp (GtkTreeModel *model, | |
+ GtkTreePath *path, | |
+ GtkTreeIter *iter, | |
+ gpointer data) | |
+{ | |
+ struct copy_old_selection_to_current_view_closure *closure; | |
+ closure = data; | |
+ selection_select_iter (closure->impl, iter, closure->impl->view_mode); | |
+} | |
+ | |
+static void | |
+copy_old_selection_to_current_view (GtkFileChooserDefault *impl, | |
+ ViewMode old_view_mode) | |
+{ | |
+ struct copy_old_selection_to_current_view_closure closure; | |
+ closure.impl = impl; | |
+ | |
+ selection_selected_foreach(impl, | |
+ old_view_mode, | |
+ copy_old_selection_to_current_view_foreach_cp, | |
+ &closure); | |
+} | |
+ | |
+static void | |
+current_selection_unselect_iter (GtkFileChooserDefault *impl, | |
+ GtkTreeIter *iter) | |
+{ | |
+ if (impl->view_mode == VIEW_MODE_LIST) | |
+ { | |
+ GtkTreeSelection *selection; | |
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view)); | |
+ gtk_tree_selection_unselect_iter (selection, iter); | |
+ } | |
+ else if (impl->view_mode == VIEW_MODE_ICON) | |
+ { | |
+ GtkTreePath *path; | |
+ path = gtk_tree_model_get_path (impl->current_model, iter); | |
+ gtk_icon_view_unselect_path (GTK_ICON_VIEW (impl->browse_files_icon_view), path); | |
+ gtk_tree_path_free (path); | |
+ } | |
+ else | |
+ g_assert_not_reached (); | |
+} | |
+ | |
+static void | |
+current_selection_unselect_all (GtkFileChooserDefault *impl) | |
+{ | |
+ if (impl->view_mode == VIEW_MODE_LIST) | |
+ { | |
+ GtkTreeSelection *selection; | |
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view)); | |
+ gtk_tree_selection_unselect_all (selection); | |
+ } | |
+ else if (impl->view_mode == VIEW_MODE_ICON) | |
+ gtk_icon_view_unselect_all (GTK_ICON_VIEW (impl->browse_files_icon_view)); | |
+ else | |
+ g_assert_not_reached (); | |
+} | |
+ | |
+static void | |
+current_view_set_file_model (GtkFileChooserDefault *impl, GtkTreeModel *model) | |
+{ | |
+ GtkWidget *view; | |
+ | |
+ impl->current_model = model; | |
+ | |
+ if (impl->view_mode == VIEW_MODE_LIST) | |
+ view = impl->browse_files_tree_view; | |
+ else if (impl->view_mode == VIEW_MODE_ICON) | |
+ view = impl->browse_files_icon_view; | |
+ else | |
+ g_assert_not_reached (); | |
+ | |
+ g_object_set (view, "model", impl->current_model, NULL); | |
+} | |
+ | |
+static void | |
+current_view_set_cursor (GtkFileChooserDefault *impl, GtkTreePath *path) | |
+{ | |
+ if (impl->view_mode == VIEW_MODE_LIST) | |
+ gtk_tree_view_set_cursor (GTK_TREE_VIEW (impl->browse_files_tree_view), path, NULL, FALSE); | |
+ else if (impl->view_mode == VIEW_MODE_ICON) | |
+ gtk_icon_view_set_cursor (GTK_ICON_VIEW (impl->browse_files_icon_view), path, NULL, FALSE); | |
+ else | |
+ g_assert_not_reached (); | |
+} | |
+ | |
+static void | |
+current_view_set_select_multiple (GtkFileChooserDefault *impl, gboolean select_multiple) | |
+{ | |
+ GtkTreeSelection *selection; | |
+ GtkSelectionMode mode; | |
+ | |
+ mode = select_multiple ? GTK_SELECTION_MULTIPLE : GTK_SELECTION_BROWSE; | |
+ | |
+ if (impl->view_mode == VIEW_MODE_LIST) | |
+ { | |
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view)); | |
+ gtk_tree_selection_set_mode (selection, mode); | |
+ gtk_tree_view_set_rubber_banding (GTK_TREE_VIEW (impl->browse_files_tree_view), select_multiple); | |
+ } | |
+ else if (impl->view_mode == VIEW_MODE_ICON) | |
+ gtk_icon_view_set_selection_mode (GTK_ICON_VIEW (impl->browse_files_icon_view), mode); | |
+ else | |
+ g_assert_not_reached (); | |
+} | |
diff --git a/gtk/gtkfilechooserprivate.h b/gtk/gtkfilechooserprivate.h | |
index 96329ad..71179af 100644 | |
--- a/gtk/gtkfilechooserprivate.h | |
+++ b/gtk/gtkfilechooserprivate.h | |
@@ -31,10 +31,12 @@ | |
#include "gtktreestore.h" | |
#include "gtktreeview.h" | |
#include "gtkbox.h" | |
+#include "gtkiconview.h" | |
G_BEGIN_DECLS | |
#define SETTINGS_KEY_LOCATION_MODE "location-mode" | |
+#define SETTINGS_KEY_VIEW_MODE "view-mode" | |
#define SETTINGS_KEY_SHOW_HIDDEN "show-hidden" | |
#define SETTINGS_KEY_SHOW_SIZE_COLUMN "show-size-column" | |
#define SETTINGS_KEY_SORT_COLUMN "sort-column" | |
@@ -138,6 +140,11 @@ typedef enum { | |
} ReloadState; | |
typedef enum { | |
+ VIEW_MODE_LIST, | |
+ VIEW_MODE_ICON | |
+} ViewMode; | |
+ | |
+typedef enum { | |
LOCATION_MODE_PATH_BAR, | |
LOCATION_MODE_FILENAME_ENTRY | |
} LocationMode; | |
@@ -172,7 +179,10 @@ struct _GtkFileChooserDefault | |
GtkWidget *browse_shortcuts_popup_menu; | |
GtkWidget *browse_shortcuts_popup_menu_remove_item; | |
GtkWidget *browse_shortcuts_popup_menu_rename_item; | |
+ GtkWidget *browse_files_scrolled_window; | |
+ GtkWidget *browse_files_current_view; | |
GtkWidget *browse_files_tree_view; | |
+ GtkWidget *browse_files_icon_view; | |
GtkWidget *browse_files_popup_menu; | |
GtkWidget *browse_files_popup_menu_add_shortcut_item; | |
GtkWidget *browse_files_popup_menu_hidden_files_item; | |
@@ -189,6 +199,7 @@ struct _GtkFileChooserDefault | |
GtkWidget *browse_select_a_folder_label; | |
GtkWidget *browse_select_a_folder_icon; | |
+ GtkTreeModel *current_model; | |
GtkFileSystemModel *browse_files_model; | |
char *browse_files_last_selected_name; | |
@@ -212,6 +223,9 @@ struct _GtkFileChooserDefault | |
GtkWidget *extra_align; | |
GtkWidget *extra_widget; | |
+ GtkWidget *view_mode_combo_box; | |
+ ViewMode view_mode; | |
+ | |
GtkWidget *location_button; | |
GtkWidget *location_entry_box; | |
GtkWidget *location_label; | |
@@ -267,10 +281,14 @@ struct _GtkFileChooserDefault | |
char *edited_new_text; | |
gulong settings_signal_id; | |
- int icon_size; | |
+ int icon_size_for_list_view; | |
+ int icon_size_for_icon_view; | |
GSource *focus_entry_idle; | |
+ GSource *start_editing_icon_view_idle; | |
+ GtkTreePath *start_editing_icon_view_path; | |
+ | |
gulong toplevel_set_focus_id; | |
GtkWidget *toplevel_last_focus_widget; | |
diff --git a/gtk/org.gtk.Settings.FileChooser.gschema.xml b/gtk/org.gtk.Settings.FileChooser.gschema.xml | |
index d7d8705..15e5759 100644 | |
--- a/gtk/org.gtk.Settings.FileChooser.gschema.xml | |
+++ b/gtk/org.gtk.Settings.FileChooser.gschema.xml | |
@@ -33,6 +33,11 @@ | |
<value nick='descending' value='1'/> | |
</enum> | |
+ <enum id='org.gtk.Settings.FileChooser.ViewMode'> | |
+ <value nick='list-view' value='0'/> | |
+ <value nick='icon-view' value='1'/> | |
+ </enum> | |
+ | |
<schema id='org.gtk.Settings.FileChooser' path='/org/gtk/settings/file-chooser/'> | |
<key name='last-folder-uri' type='s'> | |
<default>""</default> | |
@@ -40,6 +45,9 @@ | |
<key name='location-mode' enum='org.gtk.Settings.FileChooser.LocationMode'> | |
<default>'path-bar'</default> | |
</key> | |
+ <key name='view-mode' enum='org.gtk.Settings.FileChooser.ViewMode'> | |
+ <default>'list-view'</default> | |
+ </key> | |
<key name='show-hidden' type='b'> | |
<default>false</default> | |
<summary>Whether to show hidden files</summary> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
any instuctions on how to apply this patch on a current distro ?