-
-
Save ahodesuka/01213036b58e510dc074 to your computer and use it in GitHub Desktop.
| diff --git a/gtk/gtkfilechooserdefault.c b/gtk/gtkfilechooserdefault.c | |
| index 2a75365..b466ab2 100644 | |
| --- a/gtk/gtkfilechooserdefault.c | |
| +++ b/gtk/gtkfilechooserdefault.c | |
| @@ -81,6 +81,7 @@ | |
| #include <sys/stat.h> | |
| #include <sys/types.h> | |
| #include <locale.h> | |
| +#include <math.h> | |
| #ifdef HAVE_UNISTD_H | |
| #include <unistd.h> | |
| @@ -205,7 +206,8 @@ enum { | |
| MODEL_COL_FILE, | |
| MODEL_COL_NAME_COLLATED, | |
| MODEL_COL_IS_FOLDER, | |
| - MODEL_COL_PIXBUF, | |
| + MODEL_COL_LIST_PIXBUF, | |
| + MODEL_COL_ICON_PIXBUF, | |
| MODEL_COL_SIZE_TEXT, | |
| MODEL_COL_MTIME_TEXT, | |
| MODEL_COL_ELLIPSIZE, | |
| @@ -221,7 +223,8 @@ enum { | |
| G_TYPE_FILE, /* MODEL_COL_FILE */ \ | |
| G_TYPE_STRING, /* MODEL_COL_NAME_COLLATED */ \ | |
| G_TYPE_BOOLEAN, /* MODEL_COL_IS_FOLDER */ \ | |
| - 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 */ | |
| @@ -248,7 +251,10 @@ typedef enum { | |
| } ShortcutsIndex; | |
| /* Icon size for if we can't get it from the theme */ | |
| -#define FALLBACK_ICON_SIZE 16 | |
| +#define FALLBACK_LIST_VIEW_ICON_SIZE 16 | |
| +#define FALLBACK_ICON_VIEW_ICON_SIZE 48 | |
| + | |
| +#define ICON_VIEW_ITEM_WIDTH 128 | |
| #define PREVIEW_HBOX_SPACING 12 | |
| #define NUM_LINES 45 | |
| @@ -336,6 +342,7 @@ static void show_hidden_handler (GtkFileChooserDefault *impl); | |
| static void search_shortcut_handler (GtkFileChooserDefault *impl); | |
| static void recent_shortcut_handler (GtkFileChooserDefault *impl); | |
| static void update_appearance (GtkFileChooserDefault *impl); | |
| +static void set_sort_column (GtkFileChooserDefault *impl); | |
| static void set_current_filter (GtkFileChooserDefault *impl, | |
| GtkFileFilter *filter); | |
| @@ -370,12 +377,18 @@ 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_or_icon_selection, | |
| 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, | |
| @@ -393,6 +406,13 @@ 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 icon_view_scale_value_changed_cb (GtkRange *range, | |
| + GtkFileChooserDefault *impl); | |
| + | |
| static void location_button_toggled_cb (GtkToggleButton *toggle, | |
| GtkFileChooserDefault *impl); | |
| static void location_switch_to_path_bar (GtkFileChooserDefault *impl); | |
| @@ -421,7 +441,27 @@ 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 +762,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->list_view_icon_size = FALLBACK_LIST_VIEW_ICON_SIZE; | |
| + impl->icon_view_icon_size = FALLBACK_ICON_VIEW_ICON_SIZE; | |
| impl->load_state = LOAD_EMPTY; | |
| impl->reload_state = RELOAD_EMPTY; | |
| impl->pending_select_files = NULL; | |
| @@ -732,6 +773,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_box_set_spacing (GTK_BOX (impl), 12); | |
| @@ -1158,7 +1200,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->list_view_icon_size, 0, | |
| NULL); | |
| /* fallback */ | |
| @@ -1196,7 +1238,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->list_view_icon_size); | |
| path = gtk_tree_row_reference_get_path (data->row_ref); | |
| if (path) | |
| @@ -1260,7 +1302,7 @@ shortcuts_reload_icons (GtkFileChooserDefault *impl) | |
| volume = data; | |
| pixbuf = _gtk_file_system_volume_render_icon (volume, GTK_WIDGET (impl), | |
| - impl->icon_size, NULL); | |
| + impl->list_view_icon_size, NULL); | |
| } | |
| else if (shortcut_type == SHORTCUT_TYPE_FILE) | |
| { | |
| @@ -1296,7 +1338,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->list_view_icon_size, 0, NULL); | |
| } | |
| } | |
| else if (shortcut_type == SHORTCUT_TYPE_SEARCH) | |
| @@ -1507,7 +1549,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->list_view_icon_size); | |
| gtk_list_store_set (request->impl->shortcuts_model, &iter, | |
| SHORTCUTS_COL_PIXBUF, pixbuf, | |
| @@ -1615,7 +1657,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->list_view_icon_size, NULL); | |
| } | |
| else if (shortcut_type == SHORTCUT_TYPE_FILE) | |
| { | |
| @@ -1674,7 +1716,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->list_view_icon_size, 0, NULL); | |
| } | |
| } | |
| else | |
| @@ -2234,6 +2276,52 @@ 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, | |
| @@ -2251,17 +2339,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); | |
| - | |
| - 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); | |
| + 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); | |
| + 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 (); | |
| } | |
| static GSource * | |
| @@ -2354,6 +2451,17 @@ renderer_edited_cb (GtkCellRendererText *cell_renderer_text, | |
| queue_edited_idle (impl, new_text); | |
| } | |
| +/* Callback used from the icon view text renderer to center editable text */ | |
| +static void | |
| +renderer_editing_started_cb (GtkCellRendererText *cell_renderer_text, | |
| + GtkCellEditable *editable, | |
| + const gchar *path, | |
| + GtkFileChooserDefault *impl) | |
| +{ | |
| + if (GTK_IS_ENTRY (editable)) | |
| + gtk_entry_set_alignment (GTK_ENTRY (editable), 0.5); | |
| +} | |
| + | |
| /* Callback used from the text cell renderer when the new folder edition gets | |
| * canceled. | |
| */ | |
| @@ -2524,16 +2632,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 */ | |
| @@ -2649,17 +2751,16 @@ 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)); | |
| @@ -2703,15 +2804,13 @@ 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; | |
| } | |
| @@ -2786,13 +2885,11 @@ 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; | |
| } | |
| @@ -3755,7 +3852,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; | |
| @@ -3837,6 +3934,145 @@ show_size_column_toggled_cb (GtkCheckMenuItem *item, | |
| impl->show_size_column); | |
| } | |
| +/* Callback used when "Sort by Name" menu item is toggled */ | |
| +static void | |
| +sort_by_name_toggled_cb (GtkCheckMenuItem *item, | |
| + GtkFileChooserDefault *impl) | |
| +{ | |
| + GtkCheckMenuItem *size_item = GTK_CHECK_MENU_ITEM (impl->browse_files_popup_menu_sort_by_size_item), | |
| + *mtime_item = GTK_CHECK_MENU_ITEM (impl->browse_files_popup_menu_sort_by_mtime_item); | |
| + | |
| + // This could be avoided if we used GtkAction's | |
| + if (!gtk_check_menu_item_get_active (item) && | |
| + !gtk_check_menu_item_get_active (size_item) && | |
| + !gtk_check_menu_item_get_active (mtime_item)) | |
| + { | |
| + gtk_check_menu_item_set_active (item, TRUE); | |
| + return; | |
| + } | |
| + | |
| + if (gtk_check_menu_item_get_active (item)) | |
| + { | |
| + gtk_check_menu_item_set_active (size_item, FALSE); | |
| + gtk_check_menu_item_set_active (mtime_item, FALSE); | |
| + | |
| + impl->sort_column = MODEL_COL_NAME; | |
| + set_sort_column (impl); | |
| + } | |
| +} | |
| + | |
| +/* Callback used when "Sort by Size" menu item is toggled */ | |
| +static void | |
| +sort_by_size_toggled_cb (GtkCheckMenuItem *item, | |
| + GtkFileChooserDefault *impl) | |
| +{ | |
| + GtkCheckMenuItem *name_item = GTK_CHECK_MENU_ITEM (impl->browse_files_popup_menu_sort_by_name_item), | |
| + *mtime_item = GTK_CHECK_MENU_ITEM (impl->browse_files_popup_menu_sort_by_mtime_item); | |
| + | |
| + // This could be avoided if we used GtkAction's | |
| + if (!gtk_check_menu_item_get_active (item) && | |
| + !gtk_check_menu_item_get_active (name_item) && | |
| + !gtk_check_menu_item_get_active (mtime_item)) | |
| + { | |
| + gtk_check_menu_item_set_active (item, TRUE); | |
| + return; | |
| + } | |
| + | |
| + if (gtk_check_menu_item_get_active (item)) | |
| + { | |
| + gtk_check_menu_item_set_active (name_item, FALSE); | |
| + gtk_check_menu_item_set_active (mtime_item, FALSE); | |
| + | |
| + impl->sort_column = MODEL_COL_SIZE; | |
| + set_sort_column (impl); | |
| + } | |
| +} | |
| + | |
| +/* Callback used when "Sort by Modification Date" menu item is toggled */ | |
| +static void | |
| +sort_by_mtime_toggled_cb (GtkCheckMenuItem *item, | |
| + GtkFileChooserDefault *impl) | |
| +{ | |
| + GtkCheckMenuItem *name_item = GTK_CHECK_MENU_ITEM (impl->browse_files_popup_menu_sort_by_name_item), | |
| + *size_item = GTK_CHECK_MENU_ITEM (impl->browse_files_popup_menu_sort_by_size_item); | |
| + | |
| + // This could be avoided if we used GtkAction's | |
| + if (!gtk_check_menu_item_get_active (item) && | |
| + !gtk_check_menu_item_get_active (name_item) && | |
| + !gtk_check_menu_item_get_active (size_item)) | |
| + { | |
| + gtk_check_menu_item_set_active (item, TRUE); | |
| + return; | |
| + } | |
| + | |
| + if (gtk_check_menu_item_get_active (item)) | |
| + { | |
| + gtk_check_menu_item_set_active (name_item, FALSE); | |
| + gtk_check_menu_item_set_active (size_item, FALSE); | |
| + | |
| + impl->sort_column = MODEL_COL_MTIME; | |
| + set_sort_column (impl); | |
| + } | |
| +} | |
| + | |
| +/* Callback used when "Ascending" menu item is toggled */ | |
| +static void | |
| +sort_ascending_toggled_cb (GtkCheckMenuItem *item, | |
| + GtkFileChooserDefault *impl) | |
| +{ | |
| + GtkCheckMenuItem *desc_item = GTK_CHECK_MENU_ITEM (impl->browse_files_popup_menu_sort_descending_item); | |
| + | |
| + // This could be avoided if we used GtkAction's | |
| + if (!gtk_check_menu_item_get_active (item) && | |
| + !gtk_check_menu_item_get_active (desc_item)) | |
| + { | |
| + gtk_check_menu_item_set_active (item, TRUE); | |
| + return; | |
| + } | |
| + | |
| + if (gtk_check_menu_item_get_active (item)) | |
| + { | |
| + gtk_check_menu_item_set_active (desc_item, FALSE); | |
| + | |
| + // The sort column is explicitly set to mtime for the recent model | |
| + // This prevents it from switching when changing sort order | |
| + if (impl->view_mode == VIEW_MODE_ICON && impl->current_model == GTK_TREE_MODEL (impl->recent_model)) | |
| + gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (impl->current_model), &impl->sort_column, NULL); | |
| + | |
| + impl->sort_order = GTK_SORT_ASCENDING; | |
| + set_sort_column (impl); | |
| + } | |
| +} | |
| + | |
| +/* Callback used when "Descending" menu item is toggled */ | |
| +static void | |
| +sort_descending_toggled_cb (GtkCheckMenuItem *item, | |
| + GtkFileChooserDefault *impl) | |
| +{ | |
| + GtkCheckMenuItem *asc_item = GTK_CHECK_MENU_ITEM (impl->browse_files_popup_menu_sort_ascending_item); | |
| + | |
| + // This could be avoided if we used GtkAction's | |
| + if (!gtk_check_menu_item_get_active (item) && | |
| + !gtk_check_menu_item_get_active (asc_item)) | |
| + { | |
| + gtk_check_menu_item_set_active (item, TRUE); | |
| + return; | |
| + } | |
| + | |
| + if (gtk_check_menu_item_get_active (item)) | |
| + { | |
| + gtk_check_menu_item_set_active (asc_item, FALSE); | |
| + | |
| + // The sort column is explicitly set to mtime for the recent model | |
| + // This prevents it from switching when changing sort order | |
| + if (impl->view_mode == VIEW_MODE_ICON && impl->current_model == GTK_TREE_MODEL (impl->recent_model)) | |
| + gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (impl->current_model), &impl->sort_column, NULL); | |
| + | |
| + impl->sort_order = GTK_SORT_DESCENDING; | |
| + set_sort_column (impl); | |
| + } | |
| +} | |
| + | |
| /* Shows an error dialog about not being able to select a dragged file */ | |
| static void | |
| error_selecting_dragged_file_dialog (GtkFileChooserDefault *impl, | |
| @@ -3908,9 +4144,9 @@ file_list_drag_data_received_get_info_cb (GCancellable *cancellable, | |
| gtk_file_chooser_default_unselect_all (chooser); | |
| gtk_file_chooser_default_select_file (chooser, data->file, &error); | |
| if (error) | |
| - error_selecting_dragged_file_dialog (data->impl, data->file, error); | |
| + error_selecting_dragged_file_dialog (data->impl, data->file, error); | |
| else | |
| - browse_files_center_selected_row (data->impl); | |
| + browse_files_center_selected_row (data->impl); | |
| } | |
| if (data->impl->select_multiple) | |
| @@ -4014,7 +4250,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); | |
| item = gtk_image_menu_item_new_with_mnemonic (_("_Add to Bookmarks")); | |
| @@ -4037,12 +4273,72 @@ file_list_build_popup_menu (GtkFileChooserDefault *impl) | |
| gtk_widget_show (item); | |
| gtk_menu_shell_append (GTK_MENU_SHELL (impl->browse_files_popup_menu), item); | |
| - item = gtk_check_menu_item_new_with_mnemonic (_("Show _Size Column")); | |
| - impl->browse_files_popup_menu_size_column_item = item; | |
| - g_signal_connect (item, "toggled", | |
| - G_CALLBACK (show_size_column_toggled_cb), impl); | |
| - gtk_widget_show (item); | |
| - gtk_menu_shell_append (GTK_MENU_SHELL (impl->browse_files_popup_menu), item); | |
| + if (impl->view_mode == VIEW_MODE_LIST) | |
| + { | |
| + item = gtk_check_menu_item_new_with_mnemonic (_("Show _Size Column")); | |
| + impl->browse_files_popup_menu_size_column_item = item; | |
| + g_signal_connect (item, "toggled", | |
| + G_CALLBACK (show_size_column_toggled_cb), impl); | |
| + gtk_widget_show (item); | |
| + gtk_menu_shell_append (GTK_MENU_SHELL (impl->browse_files_popup_menu), item); | |
| + } | |
| + else if (impl->view_mode == VIEW_MODE_ICON) | |
| + { | |
| + GtkWidget *menu, *subitem; | |
| + | |
| + item = gtk_menu_item_new_with_label (_("Arrange Items")); | |
| + menu = gtk_menu_new (); | |
| + gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), menu); | |
| + | |
| + subitem = gtk_check_menu_item_new_with_mnemonic (_("Sort by _Name")); | |
| + impl->browse_files_popup_menu_sort_by_name_item = subitem; | |
| + gtk_check_menu_item_set_draw_as_radio (GTK_CHECK_MENU_ITEM (subitem), TRUE); | |
| + g_signal_connect (subitem, "toggled", | |
| + G_CALLBACK (sort_by_name_toggled_cb), impl); | |
| + gtk_widget_show (subitem); | |
| + gtk_menu_shell_append (GTK_MENU_SHELL (menu), subitem); | |
| + | |
| + subitem = gtk_check_menu_item_new_with_mnemonic (_("Sort by _Size")); | |
| + impl->browse_files_popup_menu_sort_by_size_item = subitem; | |
| + gtk_check_menu_item_set_draw_as_radio (GTK_CHECK_MENU_ITEM (subitem), TRUE); | |
| + g_signal_connect (subitem, "toggled", | |
| + G_CALLBACK (sort_by_size_toggled_cb), impl); | |
| + gtk_widget_show (subitem); | |
| + gtk_menu_shell_append (GTK_MENU_SHELL (menu), subitem); | |
| + | |
| + subitem = gtk_check_menu_item_new_with_mnemonic (_("Sort by Modification _Date")); | |
| + impl->browse_files_popup_menu_sort_by_mtime_item = subitem; | |
| + gtk_check_menu_item_set_draw_as_radio (GTK_CHECK_MENU_ITEM (subitem), TRUE); | |
| + g_signal_connect (subitem, "toggled", | |
| + G_CALLBACK (sort_by_mtime_toggled_cb), impl); | |
| + gtk_widget_show (subitem); | |
| + gtk_menu_shell_append (GTK_MENU_SHELL (menu), subitem); | |
| + | |
| + subitem = gtk_separator_menu_item_new (); | |
| + gtk_widget_show (subitem); | |
| + gtk_menu_shell_append (GTK_MENU_SHELL (menu), subitem); | |
| + | |
| + subitem = gtk_check_menu_item_new_with_mnemonic (_("_Ascending")); | |
| + impl->browse_files_popup_menu_sort_ascending_item = subitem; | |
| + gtk_check_menu_item_set_draw_as_radio (GTK_CHECK_MENU_ITEM (subitem), TRUE); | |
| + g_signal_connect (subitem, "toggled", | |
| + G_CALLBACK (sort_ascending_toggled_cb), impl); | |
| + gtk_widget_show (subitem); | |
| + gtk_menu_shell_append (GTK_MENU_SHELL (menu), subitem); | |
| + | |
| + subitem = gtk_check_menu_item_new_with_mnemonic (_("_Descending")); | |
| + impl->browse_files_popup_menu_sort_descending_item = subitem; | |
| + gtk_check_menu_item_set_draw_as_radio (GTK_CHECK_MENU_ITEM (subitem), TRUE); | |
| + g_signal_connect (subitem, "toggled", | |
| + G_CALLBACK (sort_descending_toggled_cb), impl); | |
| + gtk_widget_show (subitem); | |
| + gtk_menu_shell_append (GTK_MENU_SHELL (menu), subitem); | |
| + | |
| + gtk_widget_show (item); | |
| + gtk_menu_shell_append (GTK_MENU_SHELL (impl->browse_files_popup_menu), item); | |
| + } | |
| + else | |
| + g_assert_not_reached (); | |
| bookmarks_check_add_sensitivity (impl); | |
| } | |
| @@ -4067,13 +4363,61 @@ file_list_update_popup_menu (GtkFileChooserDefault *impl) | |
| g_signal_handlers_unblock_by_func (impl->browse_files_popup_menu_hidden_files_item, | |
| G_CALLBACK (show_hidden_toggled_cb), impl); | |
| - /* 'Show Size Column' */ | |
| - g_signal_handlers_block_by_func (impl->browse_files_popup_menu_size_column_item, | |
| - G_CALLBACK (show_size_column_toggled_cb), impl); | |
| - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (impl->browse_files_popup_menu_size_column_item), | |
| - impl->show_size_column); | |
| - g_signal_handlers_unblock_by_func (impl->browse_files_popup_menu_size_column_item, | |
| - G_CALLBACK (show_size_column_toggled_cb), impl); | |
| + if (impl->view_mode == VIEW_MODE_LIST) | |
| + { | |
| + /* 'Show Size Column' */ | |
| + g_signal_handlers_block_by_func (impl->browse_files_popup_menu_size_column_item, | |
| + G_CALLBACK (show_size_column_toggled_cb), impl); | |
| + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (impl->browse_files_popup_menu_size_column_item), | |
| + impl->show_size_column); | |
| + g_signal_handlers_unblock_by_func (impl->browse_files_popup_menu_size_column_item, | |
| + G_CALLBACK (show_size_column_toggled_cb), impl); | |
| + } | |
| + else if (impl->view_mode == VIEW_MODE_ICON) | |
| + { | |
| + gint column = impl->sort_column; | |
| + GtkSortType order = impl->sort_order; | |
| + | |
| + if (impl->current_model == GTK_TREE_MODEL (impl->recent_model)) | |
| + gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (impl->current_model), &column, &order); | |
| + | |
| + g_signal_handlers_block_by_func (impl->browse_files_popup_menu_sort_by_name_item, | |
| + G_CALLBACK (sort_by_name_toggled_cb), impl); | |
| + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (impl->browse_files_popup_menu_sort_by_name_item), | |
| + column == MODEL_COL_NAME); | |
| + g_signal_handlers_unblock_by_func (impl->browse_files_popup_menu_sort_by_name_item, | |
| + G_CALLBACK (sort_by_name_toggled_cb), impl); | |
| + | |
| + g_signal_handlers_block_by_func (impl->browse_files_popup_menu_sort_by_size_item, | |
| + G_CALLBACK (sort_by_size_toggled_cb), impl); | |
| + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (impl->browse_files_popup_menu_sort_by_size_item), | |
| + column == MODEL_COL_SIZE); | |
| + g_signal_handlers_unblock_by_func (impl->browse_files_popup_menu_sort_by_size_item, | |
| + G_CALLBACK (sort_by_size_toggled_cb), impl); | |
| + | |
| + g_signal_handlers_block_by_func (impl->browse_files_popup_menu_sort_by_mtime_item, | |
| + G_CALLBACK (sort_by_mtime_toggled_cb), impl); | |
| + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (impl->browse_files_popup_menu_sort_by_mtime_item), | |
| + column == MODEL_COL_MTIME); | |
| + g_signal_handlers_unblock_by_func (impl->browse_files_popup_menu_sort_by_mtime_item, | |
| + G_CALLBACK (sort_by_mtime_toggled_cb), impl); | |
| + | |
| + g_signal_handlers_block_by_func (impl->browse_files_popup_menu_sort_ascending_item, | |
| + G_CALLBACK (sort_ascending_toggled_cb), impl); | |
| + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (impl->browse_files_popup_menu_sort_ascending_item), | |
| + order == GTK_SORT_ASCENDING); | |
| + g_signal_handlers_unblock_by_func (impl->browse_files_popup_menu_sort_ascending_item, | |
| + G_CALLBACK (sort_ascending_toggled_cb), impl); | |
| + | |
| + g_signal_handlers_block_by_func (impl->browse_files_popup_menu_sort_descending_item, | |
| + G_CALLBACK (sort_descending_toggled_cb), impl); | |
| + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (impl->browse_files_popup_menu_sort_descending_item), | |
| + order == GTK_SORT_DESCENDING); | |
| + g_signal_handlers_unblock_by_func (impl->browse_files_popup_menu_sort_descending_item, | |
| + G_CALLBACK (sort_descending_toggled_cb), impl); | |
| + } | |
| + else | |
| + g_assert_not_reached (); | |
| } | |
| static void | |
| @@ -4121,7 +4465,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); | |
| @@ -4155,28 +4499,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 | |
| @@ -4228,32 +4569,34 @@ file_list_query_tooltip_cb (GtkWidget *widget, | |
| } | |
| static void | |
| -set_icon_cell_renderer_fixed_size (GtkFileChooserDefault *impl, GtkCellRenderer *renderer) | |
| +set_icon_cell_renderer_fixed_size (GtkFileChooserDefault *impl, | |
| + GtkCellRenderer *renderer, | |
| + ViewMode view_mode) | |
| { | |
| + int icon_size; | |
| gint xpad, ypad; | |
| + if (view_mode == VIEW_MODE_LIST) | |
| + icon_size = impl->list_view_icon_size; | |
| + else if (view_mode == VIEW_MODE_ICON) | |
| + icon_size = impl->icon_view_icon_size; | |
| + else | |
| + g_assert_not_reached (); | |
| + | |
| 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 + icon_size, | |
| + ypad * 2 + icon_size); | |
| } | |
| -/* Creates the widgets for the file list */ | |
| +/* Creates the 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 (); | |
| @@ -4264,7 +4607,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, | |
| @@ -4316,7 +4658,7 @@ create_file_list (GtkFileChooserDefault *impl) | |
| renderer = gtk_cell_renderer_pixbuf_new (); | |
| /* We set a fixed size so that we get an empty slot even if no icons are loaded yet */ | |
| - set_icon_cell_renderer_fixed_size (impl, renderer); | |
| + set_icon_cell_renderer_fixed_size (impl, renderer, VIEW_MODE_LIST); | |
| gtk_tree_view_column_pack_start (impl->list_name_column, renderer, FALSE); | |
| impl->list_name_renderer = gtk_cell_renderer_text_new (); | |
| @@ -4359,6 +4701,101 @@ 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 (); | |
| + | |
| + g_object_set_data (G_OBJECT (impl->browse_files_icon_view), I_("GtkFileChooserDefault"), impl); | |
| + gtk_icon_view_set_item_padding (GTK_ICON_VIEW (impl->browse_files_icon_view), 0); | |
| + | |
| + 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_icon_renderer = gtk_cell_renderer_pixbuf_new (); | |
| + g_object_set (G_OBJECT (impl->list_icon_renderer), | |
| + "ypad", 3u, | |
| + NULL); | |
| + | |
| + set_icon_cell_renderer_fixed_size (impl, GTK_CELL_RENDERER (impl->list_icon_renderer), | |
| + VIEW_MODE_ICON); | |
| + | |
| + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (impl->browse_files_icon_view), | |
| + impl->list_icon_renderer, TRUE); | |
| + gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (impl->browse_files_icon_view), | |
| + impl->list_icon_renderer, "pixbuf", MODEL_COL_ICON_PIXBUF); | |
| + | |
| + impl->list_name_renderer = gtk_cell_renderer_text_new (); | |
| + g_object_set (G_OBJECT (impl->list_name_renderer), | |
| + "alignment", PANGO_ALIGN_CENTER, | |
| + "wrap-mode", PANGO_WRAP_WORD_CHAR, | |
| + "wrap-width", ICON_VIEW_ITEM_WIDTH - 6, | |
| + "yalign", 0.0f, | |
| + NULL); | |
| + gtk_cell_renderer_set_fixed_size (GTK_CELL_RENDERER (impl->list_name_renderer), ICON_VIEW_ITEM_WIDTH, -1); | |
| + | |
| + g_signal_connect (impl->list_name_renderer, "edited", | |
| + G_CALLBACK (renderer_edited_cb), impl); | |
| + g_signal_connect (impl->list_name_renderer, "editing-started", | |
| + G_CALLBACK (renderer_editing_started_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); | |
| + gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (impl->browse_files_icon_view), | |
| + impl->list_name_renderer, "text", MODEL_COL_NAME); | |
| + | |
| + 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; | |
| @@ -4583,7 +5020,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; | |
| @@ -4643,6 +5080,108 @@ location_toggle_popup_handler (GtkFileChooserDefault *impl) | |
| } | |
| } | |
| +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; | |
| + gtk_widget_show (impl->icon_view_scale_hbox); | |
| + } | |
| + else if (view_mode == VIEW_MODE_LIST) | |
| + { | |
| + impl->browse_files_icon_view = NULL; | |
| + gtk_widget_hide (impl->icon_view_scale_hbox); | |
| + } | |
| + else | |
| + g_assert_not_reached (); | |
| + | |
| + if (impl->browse_files_popup_menu) | |
| + gtk_menu_detach (GTK_MENU (impl->browse_files_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); | |
| + | |
| + browse_files_center_selected_row (impl); | |
| +} | |
| + | |
| +/* 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 the icon view scale is changed */ | |
| +static void | |
| +icon_view_scale_value_changed_cb (GtkRange *range, | |
| + GtkFileChooserDefault *impl) | |
| +{ | |
| + gdouble value = gtk_range_get_value (range); | |
| + value = round (value / 16) * 16; | |
| + | |
| + if (impl->icon_view_icon_size == (gint)value) | |
| + return; | |
| + | |
| + impl->icon_view_icon_size = (gint)value; | |
| + | |
| + if (impl->view_mode != VIEW_MODE_ICON) | |
| + return; | |
| + | |
| + set_icon_cell_renderer_fixed_size (impl, impl->list_icon_renderer, VIEW_MODE_ICON); | |
| + | |
| + if (impl->browse_files_model) | |
| + _gtk_file_system_model_clear_cache (impl->browse_files_model, MODEL_COL_ICON_PIXBUF); | |
| + if (impl->search_model) | |
| + _gtk_file_system_model_clear_cache (impl->search_model, MODEL_COL_ICON_PIXBUF); | |
| + if (impl->recent_model) | |
| + _gtk_file_system_model_clear_cache (impl->recent_model, MODEL_COL_ICON_PIXBUF); | |
| + | |
| + gtk_widget_queue_resize (impl->browse_files_current_view); | |
| +} | |
| + | |
| /* Callback used when one of the location mode buttons is toggled */ | |
| static void | |
| location_button_toggled_cb (GtkToggleButton *toggle, | |
| @@ -4667,6 +5206,53 @@ 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 hscale for the icon view. */ | |
| +static void | |
| +icon_view_scale_create (GtkFileChooserDefault *impl) | |
| +{ | |
| + GtkObject *adj; | |
| + | |
| + impl->icon_view_scale_hbox = gtk_hbox_new (FALSE, 12); | |
| + | |
| + impl->icon_view_scale_zoom_out_icon = gtk_image_new_from_stock (GTK_STOCK_ZOOM_OUT, GTK_ICON_SIZE_BUTTON); | |
| + gtk_size_group_add_widget (impl->browse_path_bar_size_group, impl->icon_view_scale_zoom_out_icon); | |
| + gtk_box_pack_start (GTK_BOX (impl->icon_view_scale_hbox), impl->icon_view_scale_zoom_out_icon, FALSE, FALSE, 0); | |
| + gtk_widget_show (impl->icon_view_scale_zoom_out_icon); | |
| + | |
| + adj = gtk_adjustment_new (32, 32, 112, 16, 16, 0); | |
| + impl->icon_view_scale = gtk_hscale_new (GTK_ADJUSTMENT (adj)); | |
| + gtk_scale_set_draw_value (GTK_SCALE (impl->icon_view_scale), FALSE); | |
| + gtk_widget_set_size_request (impl->icon_view_scale, 100, -1); | |
| + gtk_box_pack_start (GTK_BOX (impl->icon_view_scale_hbox), impl->icon_view_scale, FALSE, FALSE, 0); | |
| + gtk_widget_show (impl->icon_view_scale); | |
| + | |
| + impl->icon_view_scale_zoom_in_icon = gtk_image_new_from_stock (GTK_STOCK_ZOOM_IN, GTK_ICON_SIZE_BUTTON); | |
| + gtk_size_group_add_widget (impl->browse_path_bar_size_group, impl->icon_view_scale_zoom_in_icon); | |
| + gtk_box_pack_start (GTK_BOX (impl->icon_view_scale_hbox), impl->icon_view_scale_zoom_in_icon, FALSE, FALSE, 0); | |
| + gtk_widget_show (impl->icon_view_scale_zoom_in_icon); | |
| + | |
| + g_signal_connect (impl->icon_view_scale, "value-changed", | |
| + G_CALLBACK (icon_view_scale_value_changed_cb), impl); | |
| + | |
| +} | |
| + | |
| + | |
| /* Creates a toggle button for the location entry. */ | |
| static void | |
| location_button_create (GtkFileChooserDefault *impl) | |
| @@ -4786,6 +5372,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); | |
| @@ -4807,6 +5397,10 @@ path_bar_widgets_create (GtkFileChooserDefault *impl) | |
| /* Widgets for special modes (recently-used in Open mode, Search mode) */ | |
| special_mode_widgets_create (impl); | |
| + /* Icon view scale */ | |
| + icon_view_scale_create (impl); | |
| + gtk_box_pack_end (GTK_BOX (impl->browse_path_bar_hbox), impl->icon_view_scale_hbox, FALSE, FALSE, 0); | |
| + | |
| /* Create Folder */ | |
| impl->browse_new_folder_button = gtk_button_new_with_mnemonic (_("Create Fo_lder")); | |
| g_signal_connect (impl->browse_new_folder_button, "clicked", | |
| @@ -5049,18 +5643,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_BROWSE; | |
| - | |
| - 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"); | |
| @@ -5168,27 +5754,27 @@ path_bar_update (GtkFileChooserDefault *impl) | |
| break; | |
| case OPERATION_MODE_RECENT: | |
| - if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE) | |
| - { | |
| - GtkTreeSelection *selection; | |
| - gboolean have_selected; | |
| - GtkTreeIter iter; | |
| + if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE && impl->view_mode == VIEW_MODE_LIST) | |
| + { | |
| + GtkTreeSelection *selection; | |
| + gboolean have_selected; | |
| + GtkTreeIter iter; | |
| - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view)); | |
| + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view)); | |
| - /* Save mode means single-selection mode, so the following is valid */ | |
| - have_selected = gtk_tree_selection_get_selected (selection, NULL, &iter); | |
| + /* Save mode means single-selection mode, so the following is valid */ | |
| + have_selected = gtk_tree_selection_get_selected (selection, NULL, &iter); | |
| - if (have_selected) | |
| - { | |
| - mode = PATH_BAR_FOLDER_PATH; | |
| - put_recent_folder_in_pathbar (impl, &iter); | |
| - } | |
| - else | |
| - mode = PATH_BAR_SELECT_A_FOLDER; | |
| - } | |
| + if (have_selected) | |
| + { | |
| + mode = PATH_BAR_FOLDER_PATH; | |
| + put_recent_folder_in_pathbar (impl, &iter); | |
| + } | |
| + else | |
| + mode = PATH_BAR_SELECT_A_FOLDER; | |
| + } | |
| else | |
| - mode = PATH_BAR_RECENTLY_USED; | |
| + mode = PATH_BAR_RECENTLY_USED; | |
| break; | |
| @@ -5378,6 +5964,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); | |
| @@ -5387,7 +5979,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); | |
| } | |
| @@ -5769,20 +6361,36 @@ 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->list_view_icon_size = MAX (width, height); | |
| else | |
| - impl->icon_size = FALLBACK_ICON_SIZE; | |
| + impl->list_view_icon_size = FALLBACK_LIST_VIEW_ICON_SIZE; | |
| 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, VIEW_MODE_LIST); | |
| + 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); | |
| + } | |
| + if (impl->search_model) | |
| + { | |
| + _gtk_file_system_model_clear_cache (impl->search_model, MODEL_COL_LIST_PIXBUF); | |
| + _gtk_file_system_model_clear_cache (impl->search_model, MODEL_COL_ICON_PIXBUF); | |
| + } | |
| + if (impl->recent_model) | |
| + { | |
| + _gtk_file_system_model_clear_cache (impl->recent_model, MODEL_COL_LIST_PIXBUF); | |
| + _gtk_file_system_model_clear_cache (impl->recent_model, MODEL_COL_ICON_PIXBUF); | |
| + } | |
| + gtk_widget_queue_resize (impl->browse_files_current_view); | |
| profile_end ("end", NULL); | |
| } | |
| @@ -5882,7 +6490,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) | |
| return; | |
| @@ -5897,15 +6505,18 @@ settings_load (GtkFileChooserDefault *impl) | |
| { | |
| GtkFileChooserSettings *settings; | |
| LocationMode location_mode; | |
| + ViewMode view_mode; | |
| gboolean show_hidden; | |
| gboolean show_size_column; | |
| - gint sort_column; | |
| + gint sort_column, icon_view_scale; | |
| GtkSortType sort_order; | |
| StartupMode startup_mode; | |
| settings = _gtk_file_chooser_settings_new (); | |
| location_mode = _gtk_file_chooser_settings_get_location_mode (settings); | |
| + view_mode = _gtk_file_chooser_settings_get_view_mode (settings); | |
| + icon_view_scale = _gtk_file_chooser_settings_get_icon_view_scale (settings); | |
| show_hidden = _gtk_file_chooser_settings_get_show_hidden (settings); | |
| show_size_column = _gtk_file_chooser_settings_get_show_size_column (settings); | |
| sort_column = _gtk_file_chooser_settings_get_sort_column (settings); | |
| @@ -5915,11 +6526,16 @@ settings_load (GtkFileChooserDefault *impl) | |
| g_object_unref (settings); | |
| location_mode_set (impl, location_mode, TRUE); | |
| + view_mode_set (impl, view_mode); | |
| + | |
| + gtk_range_set_value (GTK_RANGE (impl->icon_view_scale), icon_view_scale); | |
| + impl->icon_view_icon_size = icon_view_scale; | |
| 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; | |
| @@ -5958,6 +6574,8 @@ settings_save (GtkFileChooserDefault *impl) | |
| /* All the other state */ | |
| _gtk_file_chooser_settings_set_location_mode (settings, impl->location_mode); | |
| + _gtk_file_chooser_settings_set_view_mode (settings, impl->view_mode); | |
| + _gtk_file_chooser_settings_set_icon_view_scale (settings, impl->icon_view_icon_size); | |
| _gtk_file_chooser_settings_set_show_hidden (settings, gtk_file_chooser_get_show_hidden (GTK_FILE_CHOOSER (impl))); | |
| _gtk_file_chooser_settings_set_show_size_column (settings, impl->show_size_column); | |
| _gtk_file_chooser_settings_set_sort_column (settings, impl->sort_column); | |
| @@ -6195,12 +6813,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; | |
| @@ -6272,7 +6894,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; | |
| @@ -6281,7 +6903,7 @@ 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); | |
| } | |
| @@ -6292,7 +6914,7 @@ struct center_selected_row_closure { | |
| }; | |
| /* Callback used from gtk_tree_selection_selected_foreach(); centers the | |
| - * selected row in the tree view. | |
| + * selected row in the current view. | |
| */ | |
| static void | |
| center_selected_row_foreach_cb (GtkTreeModel *model, | |
| @@ -6306,7 +6928,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; | |
| } | |
| @@ -6315,20 +6943,17 @@ 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; | |
| @@ -6337,8 +6962,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); | |
| @@ -6394,11 +7018,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; | |
| @@ -6434,7 +7057,7 @@ pending_select_files_process (GtkFileChooserDefault *impl) | |
| */ | |
| if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN && | |
| gtk_widget_get_mapped (GTK_WIDGET (impl))) | |
| - browse_files_select_first_row (impl); | |
| + browse_files_select_first_row (impl); | |
| } | |
| g_assert (impl->pending_select_files == NULL); | |
| @@ -6513,12 +7136,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 * | |
| @@ -6671,6 +7296,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, | |
| @@ -6700,38 +7336,59 @@ file_system_model_set (GtkFileSystemModel *model, | |
| case MODEL_COL_IS_FOLDER: | |
| g_value_set_boolean (value, info == NULL || _gtk_file_info_consider_as_directory (info)); | |
| 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_view_icon_size; | |
| + else | |
| + icon_size = impl->list_view_icon_size; | |
| + | |
| + g_value_take_object (value, _gtk_file_info_render_icon (info, GTK_WIDGET (impl), icon_size)); | |
| + return TRUE; | |
| } | |
| - else | |
| + | |
| + if (!get_visible_range (&start, &end, impl)) | |
| + return FALSE; | |
| + | |
| + if (!_gtk_file_system_model_get_iter_for_file (model, | |
| + &iter, | |
| + file)) | |
| + g_assert_not_reached (); | |
| + | |
| + 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) | |
| { | |
| - 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; | |
| - | |
| - 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_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) | |
| + /* #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 "," | |
| @@ -6742,14 +7399,23 @@ 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_view_icon_size, | |
| + 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); | |
| @@ -6875,7 +7541,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 */ | |
| @@ -6892,9 +7557,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) | |
| { | |
| @@ -7366,7 +8030,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) | |
| @@ -7377,8 +8040,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 | |
| @@ -7388,20 +8050,17 @@ maybe_select (GtkTreeModel *model, | |
| gpointer data) | |
| { | |
| GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (data); | |
| - GtkTreeSelection *selection; | |
| 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, | |
| -1); | |
| if ((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; | |
| } | |
| @@ -7416,8 +8075,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; | |
| } | |
| @@ -7430,9 +8096,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); | |
| } | |
| @@ -7584,15 +8249,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: | |
| * | |
| @@ -7632,7 +8295,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; | |
| @@ -8096,7 +8759,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 | |
| @@ -8107,8 +8769,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); | |
| @@ -8127,14 +8788,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) | |
| + { | |
| + 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; | |
| + } | |
| + else if (impl->view_mode == VIEW_MODE_ICON) | |
| { | |
| - *had_selection = FALSE; | |
| - return NULL; | |
| + if (!get_selected_tree_iter_from_icon_view (impl, &iter)) | |
| + { | |
| + *had_selection = FALSE; | |
| + return NULL; | |
| + } | |
| + *had_selection = TRUE; | |
| } | |
| - | |
| - *had_selection = TRUE; | |
| + else | |
| + g_assert_not_reached (); | |
| info = _gtk_file_system_model_get_info (impl->browse_files_model, &iter); | |
| return info; | |
| @@ -8510,7 +9186,7 @@ file_exists_get_info_cb (GCancellable *cancellable, | |
| } | |
| else | |
| { | |
| - g_assert_not_reached(); | |
| + g_assert_not_reached (); | |
| } | |
| if (needs_parent_check) { | |
| @@ -8615,7 +9291,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. | |
| @@ -8825,7 +9501,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. | |
| @@ -8874,7 +9550,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; | |
| } | |
| @@ -8912,12 +9588,10 @@ 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; | |
| @@ -8929,12 +9603,9 @@ 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 */ | |
| @@ -8991,6 +9662,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 | |
| @@ -9038,7 +9710,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 */ | |
| @@ -9089,8 +9761,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); | |
| } | |
| @@ -9254,7 +9925,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; | |
| @@ -9311,8 +9982,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); | |
| @@ -9457,12 +10127,10 @@ 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; | |
| @@ -9474,12 +10142,9 @@ 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 | |
| @@ -9539,9 +10204,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) | |
| + cursor_path = NULL; | |
| + else | |
| + g_assert_not_reached (); | |
| + | |
| + model = impl->current_model; | |
| + | |
| + if (cursor_path && model) | |
| { | |
| GtkTreeIter iter; | |
| @@ -9851,7 +10523,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; | |
| } | |
| @@ -9920,8 +10592,9 @@ list_select_func (GtkTreeSelection *selection, | |
| return TRUE; | |
| } | |
| +/* GtkTreeSelection or GtkIconView selection changed. */ | |
| static void | |
| -list_selection_changed (GtkTreeSelection *selection, | |
| +list_selection_changed (void *selection, | |
| GtkFileChooserDefault *impl) | |
| { | |
| /* See if we are in the new folder editable row for Save mode */ | |
| @@ -9959,13 +10632,32 @@ 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; | |
| - model = gtk_tree_view_get_model (tree_view); | |
| - | |
| if (!gtk_tree_model_get_iter (model, &iter, path)) | |
| return; | |
| @@ -10017,6 +10709,10 @@ update_cell_renderer_attributes (GtkFileChooserDefault *impl) | |
| GList *walk, *list; | |
| gboolean always_sensitive; | |
| + /* only applicable in the tree view (i.e. list view) */ | |
| + if (!impl->browse_files_tree_view) | |
| + return; | |
| + | |
| always_sensitive = impl->action != GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER && | |
| impl->action != GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER; | |
| @@ -10031,7 +10727,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 | |
| @@ -10103,7 +10799,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; | |
| @@ -10305,3 +11001,242 @@ 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 dab74c3..ba09a55 100644 | |
| --- a/gtk/gtkfilechooserprivate.h | |
| +++ b/gtk/gtkfilechooserprivate.h | |
| @@ -33,6 +33,8 @@ | |
| #include "gtktreestore.h" | |
| #include "gtktreeview.h" | |
| #include "gtkvbox.h" | |
| +#include "gtkiconview.h" | |
| +#include "gtkhscale.h" | |
| G_BEGIN_DECLS | |
| @@ -136,6 +138,11 @@ typedef enum { | |
| } LocationMode; | |
| typedef enum { | |
| + VIEW_MODE_LIST, | |
| + VIEW_MODE_ICON | |
| +} ViewMode; | |
| + | |
| +typedef enum { | |
| OPERATION_MODE_BROWSE, | |
| OPERATION_MODE_SEARCH, | |
| OPERATION_MODE_RECENT | |
| @@ -170,10 +177,18 @@ struct _GtkFileChooserDefault | |
| GtkWidget *browse_shortcuts_popup_menu_remove_item; | |
| GtkWidget *browse_shortcuts_popup_menu_rename_item; | |
| GtkWidget *browse_files_tree_view; | |
| + GtkWidget *browse_files_scrolled_window; | |
| + GtkWidget *browse_files_current_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; | |
| GtkWidget *browse_files_popup_menu_size_column_item; | |
| + GtkWidget *browse_files_popup_menu_sort_by_name_item; | |
| + GtkWidget *browse_files_popup_menu_sort_by_size_item; | |
| + GtkWidget *browse_files_popup_menu_sort_by_mtime_item; | |
| + GtkWidget *browse_files_popup_menu_sort_ascending_item; | |
| + GtkWidget *browse_files_popup_menu_sort_descending_item; | |
| GtkWidget *browse_new_folder_button; | |
| GtkWidget *browse_path_bar_hbox; | |
| GtkSizeGroup *browse_path_bar_size_group; | |
| @@ -186,6 +201,7 @@ struct _GtkFileChooserDefault | |
| gulong toplevel_unmapped_id; | |
| + GtkTreeModel *current_model; | |
| GtkFileSystemModel *browse_files_model; | |
| char *browse_files_last_selected_name; | |
| @@ -211,6 +227,13 @@ struct _GtkFileChooserDefault | |
| GtkWidget *extra_align; | |
| GtkWidget *extra_widget; | |
| + GtkWidget *view_mode_combo_box; | |
| + GtkWidget *icon_view_scale_hbox; | |
| + GtkWidget *icon_view_scale; | |
| + GtkWidget *icon_view_scale_zoom_in_icon; | |
| + GtkWidget *icon_view_scale_zoom_out_icon; | |
| + ViewMode view_mode; | |
| + | |
| GtkWidget *location_button; | |
| GtkWidget *location_entry_box; | |
| GtkWidget *location_label; | |
| @@ -259,6 +282,7 @@ struct _GtkFileChooserDefault | |
| GtkTreeViewColumn *list_name_column; | |
| GtkCellRenderer *list_name_renderer; | |
| + GtkCellRenderer *list_icon_renderer; | |
| GtkTreeViewColumn *list_mtime_column; | |
| GtkTreeViewColumn *list_size_column; | |
| @@ -266,10 +290,14 @@ struct _GtkFileChooserDefault | |
| char *edited_new_text; | |
| gulong settings_signal_id; | |
| - int icon_size; | |
| + int list_view_icon_size; | |
| + int icon_view_icon_size; | |
| 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/gtkfilechoosersettings.c b/gtk/gtkfilechoosersettings.c | |
| index 5b8fb87..ce34291 100644 | |
| --- a/gtk/gtkfilechoosersettings.c | |
| +++ b/gtk/gtkfilechoosersettings.c | |
| @@ -39,6 +39,8 @@ | |
| #define SETTINGS_GROUP "Filechooser Settings" | |
| #define LOCATION_MODE_KEY "LocationMode" | |
| +#define VIEW_MODE_KEY "ViewMode" | |
| +#define ICON_VIEW_SCALE_KEY "IconViewScale" | |
| #define SHOW_HIDDEN_KEY "ShowHidden" | |
| #define SHOW_SIZE_COLUMN_KEY "ShowSizeColumn" | |
| #define GEOMETRY_X_KEY "GeometryX" | |
| @@ -58,8 +60,11 @@ | |
| #define STARTUP_MODE_RECENT_STRING "recent" | |
| #define STARTUP_MODE_CWD_STRING "cwd" | |
| -#define MODE_PATH_BAR "path-bar" | |
| -#define MODE_FILENAME_ENTRY "filename-entry" | |
| +#define MODE_PATH_BAR "path-bar" | |
| +#define MODE_FILENAME_ENTRY "filename-entry" | |
| + | |
| +#define MODE_LIST_VIEW "list-view" | |
| +#define MODE_ICON_VIEW "icon-view" | |
| #define EQ(a, b) (g_ascii_strcasecmp ((a), (b)) == 0) | |
| @@ -114,7 +119,7 @@ ensure_settings_read (GtkFileChooserSettings *settings) | |
| { | |
| GError *error; | |
| GKeyFile *key_file; | |
| - gchar *location_mode_str, *filename; | |
| + gchar *location_mode_str, *view_mode_str, *filename; | |
| gchar *sort_column, *sort_order; | |
| gchar *startup_mode; | |
| gboolean value; | |
| @@ -159,6 +164,27 @@ ensure_settings_read (GtkFileChooserSettings *settings) | |
| g_free (location_mode_str); | |
| } | |
| + /* View mode */ | |
| + | |
| + view_mode_str = g_key_file_get_string (key_file, SETTINGS_GROUP, | |
| + VIEW_MODE_KEY, NULL); | |
| + if (view_mode_str) | |
| + { | |
| + if (EQ (view_mode_str, MODE_LIST_VIEW)) | |
| + settings->view_mode = VIEW_MODE_LIST; | |
| + else if (EQ (view_mode_str, MODE_ICON_VIEW)) | |
| + settings->view_mode = VIEW_MODE_ICON; | |
| + else | |
| + g_warning ("Unknown view mode '%s' encountered in filechooser settings", | |
| + view_mode_str); | |
| + | |
| + g_free (view_mode_str); | |
| + } | |
| + | |
| + /* Icon view scale */ | |
| + | |
| + get_int_key (key_file, SETTINGS_GROUP, ICON_VIEW_SCALE_KEY, &settings->icon_view_scale); | |
| + | |
| /* Show hidden */ | |
| value = g_key_file_get_boolean (key_file, SETTINGS_GROUP, | |
| @@ -256,6 +282,8 @@ static void | |
| _gtk_file_chooser_settings_init (GtkFileChooserSettings *settings) | |
| { | |
| settings->location_mode = LOCATION_MODE_PATH_BAR; | |
| + settings->view_mode = VIEW_MODE_LIST; | |
| + settings->icon_view_scale = 48; | |
| settings->sort_order = GTK_SORT_ASCENDING; | |
| settings->sort_column = FILE_LIST_COL_NAME; | |
| settings->show_hidden = FALSE; | |
| @@ -287,6 +315,34 @@ _gtk_file_chooser_settings_set_location_mode (GtkFileChooserSettings *settings, | |
| settings->location_mode = location_mode; | |
| } | |
| +ViewMode | |
| +_gtk_file_chooser_settings_get_view_mode (GtkFileChooserSettings *settings) | |
| +{ | |
| + ensure_settings_read (settings); | |
| + return settings->view_mode; | |
| +} | |
| + | |
| +void | |
| +_gtk_file_chooser_settings_set_view_mode (GtkFileChooserSettings *settings, | |
| + ViewMode view_mode) | |
| +{ | |
| + settings->view_mode = view_mode; | |
| +} | |
| + | |
| +gint | |
| +_gtk_file_chooser_settings_get_icon_view_scale (GtkFileChooserSettings *settings) | |
| +{ | |
| + ensure_settings_read (settings); | |
| + return settings->icon_view_scale; | |
| +} | |
| + | |
| +void | |
| +_gtk_file_chooser_settings_set_icon_view_scale (GtkFileChooserSettings *settings, | |
| + gint icon_view_scale) | |
| +{ | |
| + settings->icon_view_scale = icon_view_scale; | |
| +} | |
| + | |
| gboolean | |
| _gtk_file_chooser_settings_get_show_hidden (GtkFileChooserSettings *settings) | |
| { | |
| @@ -389,7 +445,7 @@ gboolean | |
| _gtk_file_chooser_settings_save (GtkFileChooserSettings *settings, | |
| GError **error) | |
| { | |
| - const gchar *location_mode_str; | |
| + const gchar *location_mode_str, *view_mode_str; | |
| gchar *filename; | |
| gchar *dirname; | |
| gchar *contents; | |
| @@ -417,6 +473,16 @@ _gtk_file_chooser_settings_save (GtkFileChooserSettings *settings, | |
| return FALSE; | |
| } | |
| + if (settings->view_mode == VIEW_MODE_LIST) | |
| + view_mode_str = MODE_LIST_VIEW; | |
| + else if (settings->view_mode == VIEW_MODE_ICON) | |
| + view_mode_str = MODE_ICON_VIEW; | |
| + else | |
| + { | |
| + g_assert_not_reached (); | |
| + return FALSE; | |
| + } | |
| + | |
| switch (settings->sort_column) | |
| { | |
| case FILE_LIST_COL_NAME: | |
| @@ -473,6 +539,10 @@ _gtk_file_chooser_settings_save (GtkFileChooserSettings *settings, | |
| g_key_file_set_string (key_file, SETTINGS_GROUP, | |
| LOCATION_MODE_KEY, location_mode_str); | |
| + g_key_file_set_string (key_file, SETTINGS_GROUP, | |
| + VIEW_MODE_KEY, view_mode_str); | |
| + g_key_file_set_integer (key_file, SETTINGS_GROUP, | |
| + ICON_VIEW_SCALE_KEY, settings->icon_view_scale); | |
| g_key_file_set_boolean (key_file, SETTINGS_GROUP, | |
| SHOW_HIDDEN_KEY, settings->show_hidden); | |
| g_key_file_set_boolean (key_file, SETTINGS_GROUP, | |
| diff --git a/gtk/gtkfilechoosersettings.h b/gtk/gtkfilechoosersettings.h | |
| index 2283192..b987fca 100644 | |
| --- a/gtk/gtkfilechoosersettings.h | |
| +++ b/gtk/gtkfilechoosersettings.h | |
| @@ -45,9 +45,10 @@ struct _GtkFileChooserSettings | |
| GObject object; | |
| LocationMode location_mode; | |
| + ViewMode view_mode; | |
| GtkSortType sort_order; | |
| - gint sort_column; | |
| + gint sort_column, icon_view_scale; | |
| StartupMode startup_mode; | |
| int geometry_x; | |
| @@ -73,6 +74,14 @@ LocationMode _gtk_file_chooser_settings_get_location_mode (GtkFileChooserSetting | |
| void _gtk_file_chooser_settings_set_location_mode (GtkFileChooserSettings *settings, | |
| LocationMode location_mode); | |
| +ViewMode _gtk_file_chooser_settings_get_view_mode (GtkFileChooserSettings *settings); | |
| +void _gtk_file_chooser_settings_set_view_mode (GtkFileChooserSettings *settings, | |
| + ViewMode view_mode); | |
| + | |
| +gint _gtk_file_chooser_settings_get_icon_view_scale (GtkFileChooserSettings *settings); | |
| +void _gtk_file_chooser_settings_set_icon_view_scale (GtkFileChooserSettings *settings, | |
| + gint icon_view_scale); | |
| + | |
| gboolean _gtk_file_chooser_settings_get_show_hidden (GtkFileChooserSettings *settings); | |
| void _gtk_file_chooser_settings_set_show_hidden (GtkFileChooserSettings *settings, | |
| gboolean show_hidden); |
Please do Gentoo has dropped the ebuild for 2.24.30 and I used to use this patch times before then as it was great. Thank you for making this.
Hello, I hope you update this. such a handy feature should be upstream. Thankyou.
The patch applies perfectly (2.24.30) but I am not seeing any thumbnails. It looks like this: http://i.imgur.com/cxQwgvs.png
I do have an "icon view" option though and the ability to zoom in/out.
edit: Patched glib and installed tumbler and it works perfect, thanks
I have no idea if you're still interested in maintaining this, but I did do some minor tweaking to the patch to get it to work with the latest release, gtk+-2.24.31. Be warned, I have no idea what I'm doing, but everything seems to work fine on my end. Feel free to apply the changes upstream.
I will look into this soon.