-
-
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.