-
-
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); |
This patch no longer applies as of gtk 2.24.31.
This patch no longer applies as of gtk 2.24.31.
I will look into this soon.
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.
If you don't mind can you increase the max thumbnail size for high DPI monitors? Thanks for the patch.