diff options
Diffstat (limited to 'src/nautilus-list-view.c')
-rw-r--r-- | src/nautilus-list-view.c | 162 |
1 files changed, 161 insertions, 1 deletions
diff --git a/src/nautilus-list-view.c b/src/nautilus-list-view.c index 4a7f331f7..3e5c9dbe3 100644 --- a/src/nautilus-list-view.c +++ b/src/nautilus-list-view.c @@ -27,6 +27,9 @@ #include "nautilus-star-cell.h" #include "nautilus-tag-manager.h" +/* We wait two seconds after row is collapsed to unload the subdirectory */ +#define COLLAPSE_TO_UNLOAD_DELAY 2 + struct _NautilusListView { NautilusListBase parent_instance; @@ -37,6 +40,7 @@ struct _NautilusListView gint zoom_level; gboolean directories_first; + gboolean expand_as_a_tree; GQuark path_attribute_q; GFile *file_path_base_location; @@ -727,12 +731,19 @@ static void real_begin_loading (NautilusFilesView *files_view) { NautilusListView *self = NAUTILUS_LIST_VIEW (files_view); + NautilusViewModel *model; NautilusFile *file; NAUTILUS_FILES_VIEW_CLASS (nautilus_list_view_parent_class)->begin_loading (files_view); update_columns_settings_from_metadata_and_preferences (self); + /* TODO Reload the view if this setting changes. We can't easily switch + * tree mode on/off on an already loaded view and the preference is not + * expected to be changed frequently. */ + self->expand_as_a_tree = g_settings_get_boolean (nautilus_list_view_preferences, + NAUTILUS_PREFERENCES_LIST_VIEW_USE_TREE); + self->path_attribute_q = 0; g_clear_object (&self->file_path_base_location); file = nautilus_files_view_get_directory_as_file (files_view); @@ -747,7 +758,21 @@ real_begin_loading (NautilusFilesView *files_view) { self->path_attribute_q = g_quark_from_string ("where"); self->file_path_base_location = get_base_location (self); + + /* Forcefully disabling tree in these special locations because this + * view and its model currently don't expect the same file appearing + * more than once. + * + * NautilusFilesView still has support for the same file being present + * in multiple directories (struct FileAndDirectory), so, if someone + * cares enough about expanding folders in these special locations: + * TODO: Making the model items aware of their current model instead of + * relying on `nautilus_file_get_parent()`. */ + self->expand_as_a_tree = FALSE; } + + model = nautilus_list_base_get_model (NAUTILUS_LIST_BASE (self)); + nautilus_view_model_expand_as_a_tree (model, self->expand_as_a_tree); } static void @@ -825,7 +850,6 @@ static void real_sort_directories_first_changed (NautilusFilesView *files_view) { NautilusListView *self = NAUTILUS_LIST_VIEW (files_view); - NautilusViewModel *model; self->directories_first = nautilus_files_view_should_sort_directories_first (NAUTILUS_FILES_VIEW (self)); @@ -838,6 +862,114 @@ real_get_view_id (NautilusFilesView *files_view) return NAUTILUS_VIEW_LIST_ID; } +typedef struct +{ + NautilusListView *self; + NautilusViewItem *item; + NautilusDirectory *directory; +} UnloadDelayData; + +static void +unload_delay_data_free (UnloadDelayData *unload_data) +{ + g_clear_weak_pointer (&unload_data->self); + g_clear_object (&unload_data->item); + g_clear_object (&unload_data->directory); + + g_free (unload_data); +} + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (UnloadDelayData, unload_delay_data_free) + +static UnloadDelayData * +unload_delay_data_new (NautilusListView *self, + NautilusViewItem *item, + NautilusDirectory *directory) +{ + UnloadDelayData *unload_data; + + unload_data = g_new0 (UnloadDelayData, 1); + g_set_weak_pointer (&unload_data->self, self); + g_set_object (&unload_data->item, item); + g_set_object (&unload_data->directory, directory); + + return unload_data; +} + +static gboolean +unload_file_timeout (gpointer data) +{ + g_autoptr (UnloadDelayData) unload_data = data; + NautilusListView *self = unload_data->self; + NautilusViewModel *model = nautilus_list_base_get_model (NAUTILUS_LIST_BASE (self)); + if (unload_data->self == NULL) + { + return G_SOURCE_REMOVE; + } + + for (guint i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (model)); i++) + { + g_autoptr (GtkTreeListRow) row = g_list_model_get_item (G_LIST_MODEL (model), i); + g_autoptr (NautilusViewItem) item = gtk_tree_list_row_get_item (row); + if (item != NULL && item == unload_data->item) + { + if (gtk_tree_list_row_get_expanded (row)) + { + /* It has been expanded again before the timeout. Do nothing. */ + return G_SOURCE_REMOVE; + } + break; + } + } + + if (nautilus_files_view_has_subdirectory (NAUTILUS_FILES_VIEW (self), + unload_data->directory)) + { + nautilus_files_view_remove_subdirectory (NAUTILUS_FILES_VIEW (self), + unload_data->directory); + } + + /* The model holds a GListStore for every subdirectory. Empty it. */ + nautilus_view_model_clear_subdirectory (model, unload_data->item); + + return G_SOURCE_REMOVE; +} + +static void +on_row_expanded_changed (GObject *gobject, + GParamSpec *pspec, + gpointer user_data) +{ + GtkTreeListRow *row = GTK_TREE_LIST_ROW (gobject); + NautilusListView *self = NAUTILUS_LIST_VIEW (user_data); + NautilusViewItem *item; + g_autoptr (NautilusDirectory) directory = NULL; + gboolean expanded; + + item = NAUTILUS_VIEW_ITEM (gtk_tree_list_row_get_item (row)); + if (item == NULL) + { + /* Row has been destroyed. */ + return; + } + + directory = nautilus_directory_get_for_file (nautilus_view_item_get_file (item)); + expanded = gtk_tree_list_row_get_expanded (row); + if (expanded) + { + if (!nautilus_files_view_has_subdirectory (NAUTILUS_FILES_VIEW (self), directory)) + { + nautilus_files_view_add_subdirectory (NAUTILUS_FILES_VIEW (self), directory); + } + } + else + { + g_timeout_add_seconds (COLLAPSE_TO_UNLOAD_DELAY, + unload_file_timeout, + unload_delay_data_new (self, item, directory)); + } +} + static void on_item_click_released_workaround (GtkGestureClick *gesture, gint n_press, @@ -910,6 +1042,17 @@ setup_name_cell (GtkSignalListItemFactory *factory, } setup_selection_click_workaround (cell); + + if (self->expand_as_a_tree) + { + GtkTreeExpander *expander; + + expander = nautilus_name_cell_get_expander (NAUTILUS_NAME_CELL (cell)); + gtk_tree_expander_set_indent_for_icon (expander, TRUE); + g_object_bind_property (listitem, "item", + expander, "list-row", + G_BINDING_SYNC_CREATE); + } } static void @@ -918,6 +1061,7 @@ bind_name_cell (GtkSignalListItemFactory *factory, gpointer user_data) { GtkWidget *cell; + NautilusListView *self = user_data; NautilusViewItem *item; cell = gtk_list_item_get_child (listitem); @@ -938,6 +1082,14 @@ bind_name_cell (GtkSignalListItemFactory *factory, GTK_ACCESSIBLE_RELATION_LABELLED_BY, cell, NULL, -1); } + + if (self->expand_as_a_tree) + { + g_signal_connect_object (GTK_TREE_LIST_ROW (gtk_list_item_get_item (listitem)), + "notify::expanded", + G_CALLBACK (on_row_expanded_changed), + self, 0); + } } static void @@ -945,12 +1097,20 @@ unbind_name_cell (GtkSignalListItemFactory *factory, GtkListItem *listitem, gpointer user_data) { + NautilusListView *self = user_data; NautilusViewItem *item; item = listitem_get_view_item (listitem); g_return_if_fail (NAUTILUS_IS_VIEW_ITEM (item)); nautilus_view_item_set_item_ui (item, NULL); + + if (self->expand_as_a_tree) + { + g_signal_handlers_disconnect_by_func (gtk_list_item_get_item (listitem), + on_row_expanded_changed, + self); + } } static void |