diff --git a/src/nautilus-column-utilities.c b/src/nautilus-column-utilities.c index e3000a2b3bbc39fa5e885a748a66163777933eea..d3c883b60ea74e62802ed72d1f9bc9ed2dc93c5d 100644 --- a/src/nautilus-column-utilities.c +++ b/src/nautilus-column-utilities.c @@ -21,6 +21,7 @@ #include #include "nautilus-column-utilities.h" +#include "nautilus-global-preferences.h" #include #include @@ -30,25 +31,6 @@ #include "nautilus-metadata.h" #include "nautilus-module.h" -static const char *default_column_order[] = -{ - "name", - "size", - "type", - "owner", - "group", - "permissions", - "detailed_type", - "where", - "date_modified_with_time", - "date_modified", - "date_accessed", - "date_created", - "recency", - "starred", - NULL -}; - static const char *default_columns_for_recent[] = { "name", "size", "recency", NULL @@ -355,6 +337,10 @@ column_compare (NautilusColumn *a, char *name_a; char *name_b; int ret; + g_auto (GStrv) default_column_order = NULL; + + default_column_order = g_settings_get_strv (nautilus_list_view_preferences, + NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_COLUMN_ORDER); g_object_get (G_OBJECT (a), "name", &name_a, NULL); index_a = strv_index (column_order, name_a); diff --git a/src/nautilus-file.c b/src/nautilus-file.c index 15859b6fe959b59310e0cb0a56b0389b3763ac7a..bc2b7ebd463ed3586efebee2234fef08f2c7a9ad 100644 --- a/src/nautilus-file.c +++ b/src/nautilus-file.c @@ -336,26 +336,6 @@ metadata_hash_free (GHashTable *hash) g_hash_table_destroy (hash); } -static gboolean -_g_strv_equal (GStrv a, - GStrv b) -{ - if (g_strv_length (a) != g_strv_length (b)) - { - return FALSE; - } - - for (int i = 0; a[i] != NULL; i++) - { - if (strcmp (a[i], b[i]) != 0) - { - return FALSE; - } - } - - return TRUE; -} - static gboolean metadata_hash_equal (GHashTable *hash1, GHashTable *hash2) @@ -391,7 +371,7 @@ metadata_hash_equal (GHashTable *hash1, id = GPOINTER_TO_UINT (key1); if (id & METADATA_ID_IS_LIST_MASK) { - if (!_g_strv_equal ((char **) value1, (char **) value2)) + if (!g_strv_equal ((const char * const *) value1, (const char * const *) value2)) { return FALSE; } diff --git a/src/nautilus-list-view.c b/src/nautilus-list-view.c index 5802b7d3373e794af5508f11cb9b6f1f05a34c6f..71ffe53264fbbe3568c8eedef19c86e5338cbc79 100644 --- a/src/nautilus-list-view.c +++ b/src/nautilus-list-view.c @@ -59,6 +59,9 @@ get_view_item (GtkColumnViewCell *cell) return NAUTILUS_VIEW_ITEM (gtk_tree_list_row_get_item (GTK_TREE_LIST_ROW (gtk_column_view_cell_get_item (cell)))); } +static GStrv get_columns_from_view (NautilusListView *self, + gboolean visible_only); + static guint get_icon_size_for_zoom_level (NautilusListZoomLevel zoom_level) { @@ -101,6 +104,37 @@ real_get_view_ui (NautilusListBase *list_base_view) return GTK_WIDGET (self->view_ui); } +static void +columns_items_changed (GListModel *self, + guint position, + guint removed, + guint added, + gpointer user_data) +{ + NautilusFile *file; + NautilusListView *view = user_data; + g_auto (GStrv) column_order = NULL; + g_auto (GStrv) new_column_order = get_columns_from_view (view, FALSE); + g_auto (GStrv) new_visible_order = NULL; + + file = nautilus_files_view_get_directory_as_file (NAUTILUS_FILES_VIEW (view)); + column_order = nautilus_column_get_column_order (file); + + if (g_strv_equal ((const gchar * const *) column_order, (const gchar * const *) new_column_order)) + { + return; + } + + new_visible_order = get_columns_from_view (view, TRUE); + + nautilus_file_set_metadata_list (file, + NAUTILUS_METADATA_KEY_LIST_VIEW_COLUMN_ORDER, + new_column_order); + nautilus_file_set_metadata_list (file, + NAUTILUS_METADATA_KEY_LIST_VIEW_VISIBLE_COLUMNS, + new_visible_order); +} + static void apply_columns_settings (NautilusListView *self, char **column_order, @@ -110,7 +144,6 @@ apply_columns_settings (NautilusListView *self, NautilusFile *file; NautilusDirectory *directory; g_autoptr (GFile) location = NULL; - g_autoptr (GList) view_columns = NULL; GListModel *old_view_columns; g_autoptr (GHashTable) visible_columns_hash = NULL; g_autoptr (GHashTable) old_view_columns_hash = NULL; @@ -177,48 +210,31 @@ apply_columns_settings (NautilusListView *self, g_hash_table_insert (old_view_columns_hash, name, view_column); } - for (GList *l = all_columns; l != NULL; l = l->next) + for (GList *l = all_columns; l != NULL; l = l->next, column_i++) { + gboolean visible; g_autofree char *name = NULL; g_autofree char *lowercase = NULL; + GtkColumnViewColumn *view_column; g_object_get (G_OBJECT (l->data), "name", &name, NULL); lowercase = g_ascii_strdown (name, -1); - - if (g_hash_table_lookup (visible_columns_hash, lowercase) != NULL) + view_column = g_hash_table_lookup (old_view_columns_hash, name); + if (view_column == NULL) { - GtkColumnViewColumn *view_column; - - view_column = g_hash_table_lookup (old_view_columns_hash, name); - if (view_column != NULL) - { - view_columns = g_list_prepend (view_columns, view_column); - } + continue; } - } - view_columns = g_list_reverse (view_columns); + g_signal_handlers_block_by_func (gtk_column_view_get_columns (self->view_ui), + G_CALLBACK (columns_items_changed), self); - /* hide columns that are not present in the configuration */ - for (guint i = 0; i < g_list_model_get_n_items (old_view_columns); i++) - { - g_autoptr (GtkColumnViewColumn) view_column = NULL; + gtk_column_view_insert_column (self->view_ui, column_i, view_column); - view_column = g_list_model_get_item (old_view_columns, i); - if (g_list_find (view_columns, view_column) == NULL) - { - gtk_column_view_column_set_visible (view_column, FALSE); - } - else - { - gtk_column_view_column_set_visible (view_column, TRUE); - } - } + visible = g_hash_table_contains (visible_columns_hash, lowercase); + gtk_column_view_column_set_visible (view_column, visible); - /* place columns in the correct order */ - for (GList *l = view_columns; l != NULL; l = l->next, column_i++) - { - gtk_column_view_insert_column (self->view_ui, column_i, l->data); + g_signal_handlers_unblock_by_func (gtk_column_view_get_columns (self->view_ui), + G_CALLBACK (columns_items_changed), self); } } @@ -288,6 +304,84 @@ sort_directories_func (gconstpointer a, return GTK_ORDERING_EQUAL; } +static GStrv +get_columns_from_view (NautilusListView *self, + gboolean visible_only) +{ + g_autoptr (GStrvBuilder) builder = g_strv_builder_new (); + GListModel *columns = gtk_column_view_get_columns (self->view_ui); + for (guint i = 0; i < g_list_model_get_n_items (columns); i++) + { + g_autoptr (GtkColumnViewColumn) column = g_list_model_get_item (columns, i); + + if (!visible_only || gtk_column_view_column_get_visible (column)) + { + g_strv_builder_add (builder, gtk_column_view_column_get_id (column)); + } + } + return g_strv_builder_end (builder); +} + +static gboolean +is_default_column_in_header_menu (const char *name) +{ + if (g_strcmp0 (name, "type") == 0 || g_strcmp0 (name, "date_modified") == 0 || + g_strcmp0 (name, "size") == 0 || g_strcmp0 (name, "date_created") == 0 || + g_strcmp0 (name, "name") == 0 || g_strcmp0 (name, "starred") == 0) + { + return TRUE; + } + + return FALSE; +} + +static void +column_visible_changed (GObject *object, + GParamSpec *pspec, + gpointer user_data) +{ + GtkColumnViewColumn *column = GTK_COLUMN_VIEW_COLUMN (object); + NautilusListView *self = user_data; + g_autofree char *action_name = NULL; + g_auto (GStrv) visible_columns = NULL; + const char *column_name = gtk_column_view_column_get_id (column); + gboolean is_visible = gtk_column_view_column_get_visible (column); + NautilusFile *file; + file = nautilus_files_view_get_directory_as_file (NAUTILUS_FILES_VIEW (self)); + visible_columns = nautilus_column_get_visible_columns (file); + + if (is_visible != g_strv_contains ((const gchar * const *) visible_columns, column_name)) + { + g_auto (GStrv) new_visible_columns = get_columns_from_view (self, TRUE); + nautilus_file_set_metadata_list (file, + NAUTILUS_METADATA_KEY_LIST_VIEW_VISIBLE_COLUMNS, + new_visible_columns); + } + + /* Default columns are always visible. */ + if (is_default_column_in_header_menu (column_name)) + { + return; + } + + /* Besides the "default" columns, we only want to show column names in the + * header menu, if they are currently visible (so they can be hidden). + * We do this by removing or adding the action respectively. + */ + action_name = g_strdup_printf ("show-column-%s", column_name); + + if (!is_visible) + { + g_action_map_remove_action (G_ACTION_MAP (self->action_group), action_name); + } + else if (g_action_map_lookup_action (G_ACTION_MAP (self->action_group), action_name) == NULL) + { + g_autoptr (GAction) action = NULL; + action = G_ACTION (g_property_action_new (action_name, column, "visible")); + g_action_map_add_action (G_ACTION_MAP (self->action_group), action); + } +} + static void update_columns_settings_from_metadata_and_preferences (NautilusListView *self) { @@ -1097,7 +1191,10 @@ setup_view_columns (NautilusListView *self) { GtkListItemFactory *factory; g_autolist (NautilusColumn) nautilus_columns = NULL; + g_autoptr (GMenu) menu = NULL; + g_autoptr (GMenu) section = NULL; + menu = g_menu_new (); nautilus_columns = nautilus_get_all_columns (); self->factory_to_column_map = g_hash_table_new_full (g_direct_hash, @@ -1114,6 +1211,10 @@ setup_view_columns (NautilusListView *self) GtkSortType sort_order; g_autoptr (GtkCustomSorter) sorter = NULL; g_autoptr (GtkColumnViewColumn) view_column = NULL; + g_autoptr (GAction) action = NULL; + g_autofree char *action_name = NULL; + g_autofree char *detailed_action_name = NULL; + g_autoptr (GMenuItem) menu_item = NULL; g_object_get (nautilus_column, "name", &name, @@ -1132,6 +1233,9 @@ setup_view_columns (NautilusListView *self) gtk_column_view_column_set_resizable (view_column, TRUE); gtk_column_view_column_set_title (view_column, label); gtk_column_view_column_set_sorter (view_column, GTK_SORTER (sorter)); + gtk_column_view_column_set_id (view_column, name); + gtk_column_view_column_set_visible (view_column, FALSE); + gtk_column_view_column_set_header_menu (view_column, G_MENU_MODEL (menu)); if (!strcmp (name, "name")) { @@ -1155,13 +1259,37 @@ setup_view_columns (NautilusListView *self) g_signal_connect (factory, "setup", G_CALLBACK (setup_label_cell), self); } + action_name = g_strdup_printf ("show-column-%s", name); + detailed_action_name = g_strdup_printf ("view.%s", action_name); + + if (is_default_column_in_header_menu (name)) + { + action = G_ACTION (g_property_action_new (action_name, view_column, "visible")); + g_action_map_add_action (G_ACTION_MAP (self->action_group), action); + } + + if (g_strcmp0 (name, "name") != 0 && g_strcmp0 (name, "starred") != 0) + { + menu_item = g_menu_item_new (label, detailed_action_name); + g_menu_item_set_attribute (menu_item, "hidden-when", "s", "action-missing"); + g_menu_append_item (G_MENU (menu), menu_item); + } + gtk_column_view_append_column (self->view_ui, view_column); gtk_column_view_column_set_id (view_column, name); + g_signal_connect (view_column, "notify::visible", G_CALLBACK (column_visible_changed), self); g_hash_table_insert (self->factory_to_column_map, factory, g_object_ref (nautilus_column)); } + + section = g_menu_new (); + g_menu_append (section, _("More Columns"), "view.visible-columns"); + g_menu_append_section (menu, NULL, G_MENU_MODEL (section)); + + g_signal_connect (gtk_column_view_get_columns (self->view_ui), + "items-changed", G_CALLBACK (columns_items_changed), self); } static void @@ -1206,6 +1334,15 @@ nautilus_list_view_init (NautilusListView *self) self->view_ui = create_view_ui (self); nautilus_list_base_setup_gestures (NAUTILUS_LIST_BASE (self)); + self->action_group = nautilus_files_view_get_action_group (NAUTILUS_FILES_VIEW (self)); + g_action_map_add_action_entries (G_ACTION_MAP (self->action_group), + list_view_entries, + G_N_ELEMENTS (list_view_entries), + self); + + self->zoom_level = get_default_zoom_level (); + g_action_group_change_action_state (nautilus_files_view_get_action_group (NAUTILUS_FILES_VIEW (self)), + "zoom-to-level", g_variant_new_int32 (self->zoom_level)); setup_view_columns (self); @@ -1224,16 +1361,6 @@ nautilus_list_view_init (NautilusListView *self) gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (content_widget), GTK_WIDGET (self->view_ui)); - self->action_group = nautilus_files_view_get_action_group (NAUTILUS_FILES_VIEW (self)); - g_action_map_add_action_entries (G_ACTION_MAP (self->action_group), - list_view_entries, - G_N_ELEMENTS (list_view_entries), - self); - - self->zoom_level = get_default_zoom_level (); - g_action_group_change_action_state (nautilus_files_view_get_action_group (NAUTILUS_FILES_VIEW (self)), - "zoom-to-level", g_variant_new_int32 (self->zoom_level)); - /* Set up tree expand/collapse shortcuts in capture phase otherwise they * would be handled by GtkListBase's cursor movement shortcuts. */ controller = gtk_shortcut_controller_new (); @@ -1267,6 +1394,9 @@ nautilus_list_view_dispose (GObject *object) g_clear_pointer (&self->factory_to_column_map, g_hash_table_destroy); g_signal_handlers_disconnect_by_func (gtk_column_view_get_sorter (self->view_ui), on_sorter_changed, self); + g_signal_handlers_disconnect_by_func (gtk_column_view_get_columns (self->view_ui), + columns_items_changed, + self); G_OBJECT_CLASS (nautilus_list_view_parent_class)->dispose (object); } diff --git a/src/resources/ui/nautilus-files-view-context-menus.ui b/src/resources/ui/nautilus-files-view-context-menus.ui index 1f8474fc2e50668e475ea4fd6a7ac65573ed855a..cc37ffe7236da243d2f766cd3a789c8d07068849 100644 --- a/src/resources/ui/nautilus-files-view-context-menus.ui +++ b/src/resources/ui/nautilus-files-view-context-menus.ui @@ -34,11 +34,6 @@ Select _All view.select-all - - _Visible Columns - view.visible-columns - action-missing -