[nautilus/wip/antoniof/gtk4-preparation-popovers: 11/14] toolbar: Use models for view and app menus




commit 9878701333e1cee995a37d21f7a6b9d6b4fc7bc2
Author: António Fernandes <antoniof gnome org>
Date:   Thu Dec 16 10:54:58 2021 +0000

    toolbar: Use models for view and app menus
    
    Building menus with regular widgets brings too much complexity. Also,
    it makes porting to GTK4 harder because GtkPopoverMenu as we know it
    and its GtkModelButtons are gone.
    
    Let's use a GMenuModel-built GtkPopover instead. While we are at it,
    also move Undo and Redo to the primary menu, where they belong.

 src/nautilus-files-view.c                      | 118 ++------
 src/nautilus-places-view.c                     |  13 +-
 src/nautilus-toolbar-menu-sections.h           |   7 +-
 src/nautilus-toolbar.c                         |  93 +++---
 src/nautilus-ui-utilities.c                    |  66 +++++
 src/nautilus-ui-utilities.h                    |   7 +
 src/resources/css/nautilus.css                 |   6 -
 src/resources/ui/nautilus-toolbar-view-menu.ui | 321 ++++-----------------
 src/resources/ui/nautilus-toolbar.ui           | 374 +++++++------------------
 9 files changed, 309 insertions(+), 696 deletions(-)
---
diff --git a/src/nautilus-files-view.c b/src/nautilus-files-view.c
index da263aa78..5a0aa7fb0 100644
--- a/src/nautilus-files-view.c
+++ b/src/nautilus-files-view.c
@@ -265,13 +265,6 @@ typedef struct
 
     /* Toolbar menu */
     NautilusToolbarMenuSections *toolbar_menu_sections;
-    GtkWidget *sort_menu;
-    GtkWidget *sort_trash_time;
-    GtkWidget *visible_columns;
-    GtkWidget *stop;
-    GtkWidget *reload;
-    GtkWidget *zoom_controls_box;
-    GtkWidget *zoom_level_label;
 
     /* Exposed menus, for the path bar etc. */
     GMenuModel *extensions_background_menu;
@@ -280,9 +273,6 @@ typedef struct
     /* Non exported menu, only for caching */
     GMenuModel *scripts_menu;
 
-    gulong stop_signal_handler;
-    gulong reload_signal_handler;
-
     GCancellable *starred_cancellable;
     NautilusTagManager *tag_manager;
 
@@ -3327,7 +3317,7 @@ nautilus_files_view_finalize (GObject *object)
     g_clear_object (&priv->background_menu_model);
     g_clear_object (&priv->selection_menu_model);
     g_clear_object (&priv->toolbar_menu_sections->zoom_section);
-    g_clear_object (&priv->toolbar_menu_sections->extended_section);
+    g_clear_object (&priv->toolbar_menu_sections->sort_section);
     g_clear_object (&priv->extensions_background_menu);
     g_clear_object (&priv->templates_menu);
     g_clear_object (&priv->rename_file_controller);
@@ -8309,34 +8299,32 @@ nautilus_files_view_update_context_menus (NautilusFilesView *view)
 static void
 nautilus_files_view_reset_view_menu (NautilusFilesView *view)
 {
-    NautilusFilesViewPrivate *priv;
-    GActionGroup *view_action_group;
-    gboolean sort_available;
-    g_autofree gchar *zoom_level_percent = NULL;
+    NautilusFilesViewPrivate *priv = nautilus_files_view_get_instance_private (view);
     NautilusFile *file;
+    GMenuModel *zoom_section = priv->toolbar_menu_sections->zoom_section;
+    GMenuModel *sort_section = priv->toolbar_menu_sections->sort_section;
+    g_autofree gchar *zoom_level_percent = NULL;
+    const gchar *trashed_action;
+    gint i;
 
-    view_action_group = nautilus_files_view_get_action_group (view);
-    priv = nautilus_files_view_get_instance_private (view);
     file = nautilus_files_view_get_directory_as_file (NAUTILUS_FILES_VIEW (view));
 
-    gtk_widget_set_visible (priv->visible_columns,
-                            g_action_group_has_action (view_action_group, "visible-columns"));
-
-    sort_available = g_action_group_get_action_enabled (view_action_group, "sort");
-    gtk_widget_set_visible (priv->sort_menu, sort_available);
-    gtk_widget_set_visible (priv->sort_trash_time,
-                            nautilus_file_is_in_trash (file));
-
-    /* We want to make insensitive available actions but that are not current
-     * available due to the directory
-     */
-    gtk_widget_set_sensitive (priv->sort_menu,
-                              !nautilus_files_view_is_empty (view));
-    gtk_widget_set_sensitive (priv->zoom_controls_box,
-                              !nautilus_files_view_is_empty (view));
-
+    /* We want to show the percentage like this:    [ - | 100% | + ]   */
     zoom_level_percent = g_strdup_printf ("%.0f%%", nautilus_files_view_get_zoom_level_percentage (view) * 
100.0);
-    gtk_label_set_label (GTK_LABEL (priv->zoom_level_label), zoom_level_percent);
+    i = nautilus_g_menu_model_find_by_string (zoom_section, "action", "view.zoom-standard");
+    g_return_if_fail (i != -1);
+    nautilus_g_menu_replace_string_in_item (G_MENU (zoom_section), i,
+                                            "label", zoom_level_percent);
+
+    /* When not in Trash, set an inexistant action to hide the menu item. This
+     * works under the assumptiont that the menu item has its "hidden-when"
+     * attribute set to "action-disabled", and that an inexistant action is
+     * treated as a disabled action. */
+    trashed_action = nautilus_file_is_in_trash (file) ? "view.sort" : "doesnt-exist";
+    i = nautilus_g_menu_model_find_by_string (sort_section, "target", "trash-time");
+    g_return_if_fail (i != -1);
+    nautilus_g_menu_replace_string_in_item (G_MENU (sort_section), i,
+                                            "action", trashed_action);
 }
 
 /* Convenience function to reset the menus owned by the view but managed on
@@ -9364,32 +9352,6 @@ on_event (GtkWidget *widget,
     return GDK_EVENT_PROPAGATE;
 }
 
-static void
-action_reload_enabled_changed (GActionGroup      *action_group,
-                               gchar             *action_name,
-                               gboolean           enabled,
-                               NautilusFilesView *view)
-{
-    NautilusFilesViewPrivate *priv;
-
-    priv = nautilus_files_view_get_instance_private (view);
-
-    gtk_widget_set_visible (priv->reload, enabled);
-}
-
-static void
-action_stop_enabled_changed (GActionGroup      *action_group,
-                             gchar             *action_name,
-                             gboolean           enabled,
-                             NautilusFilesView *view)
-{
-    NautilusFilesViewPrivate *priv;
-
-    priv = nautilus_files_view_get_instance_private (view);
-
-    gtk_widget_set_visible (priv->stop, enabled);
-}
-
 static void
 on_parent_changed (GObject    *object,
                    GParamSpec *pspec,
@@ -9408,18 +9370,6 @@ on_parent_changed (GObject    *object,
     parent = gtk_widget_get_parent (widget);
     window = nautilus_files_view_get_window (view);
 
-    if (priv->stop_signal_handler > 0)
-    {
-        g_signal_handler_disconnect (window, priv->stop_signal_handler);
-        priv->stop_signal_handler = 0;
-    }
-
-    if (priv->reload_signal_handler > 0)
-    {
-        g_signal_handler_disconnect (window, priv->reload_signal_handler);
-        priv->reload_signal_handler = 0;
-    }
-
     if (parent != NULL)
     {
         if (priv->slot == nautilus_window_get_active_slot (window))
@@ -9429,17 +9379,6 @@ on_parent_changed (GObject    *object,
                                             "view",
                                             G_ACTION_GROUP (priv->view_action_group));
         }
-
-        priv->stop_signal_handler =
-            g_signal_connect (window,
-                              "action-enabled-changed::stop",
-                              G_CALLBACK (action_stop_enabled_changed),
-                              view);
-        priv->reload_signal_handler =
-            g_signal_connect (window,
-                              "action-enabled-changed::reload",
-                              G_CALLBACK (action_reload_enabled_changed),
-                              view);
     }
     else
     {
@@ -9833,17 +9772,8 @@ nautilus_files_view_init (NautilusFilesView *view)
     /* Toolbar menu */
     builder = gtk_builder_new_from_resource ("/org/gnome/nautilus/ui/nautilus-toolbar-view-menu.ui");
     priv->toolbar_menu_sections = g_new0 (NautilusToolbarMenuSections, 1);
-    priv->toolbar_menu_sections->supports_undo_redo = TRUE;
-    priv->toolbar_menu_sections->zoom_section = GTK_WIDGET (g_object_ref_sink (gtk_builder_get_object 
(builder, "zoom_section")));
-    priv->toolbar_menu_sections->extended_section = GTK_WIDGET (g_object_ref_sink (gtk_builder_get_object 
(builder, "extended_section")));
-    priv->zoom_controls_box = GTK_WIDGET (gtk_builder_get_object (builder, "zoom_controls_box"));
-    priv->zoom_level_label = GTK_WIDGET (gtk_builder_get_object (builder, "zoom_level_label"));
-
-    priv->sort_menu = GTK_WIDGET (gtk_builder_get_object (builder, "sort_menu"));
-    priv->sort_trash_time = GTK_WIDGET (gtk_builder_get_object (builder, "sort_trash_time"));
-    priv->visible_columns = GTK_WIDGET (gtk_builder_get_object (builder, "visible_columns"));
-    priv->reload = GTK_WIDGET (gtk_builder_get_object (builder, "reload"));
-    priv->stop = GTK_WIDGET (gtk_builder_get_object (builder, "stop"));
+    priv->toolbar_menu_sections->zoom_section = G_MENU_MODEL (g_object_ref (gtk_builder_get_object (builder, 
"zoom_section")));
+    priv->toolbar_menu_sections->sort_section = G_MENU_MODEL (g_object_ref (gtk_builder_get_object (builder, 
"sort_section")));
 
     g_signal_connect (view,
                       "end-file-changes",
diff --git a/src/nautilus-places-view.c b/src/nautilus-places-view.c
index a167ce02c..c4d1ba72f 100644
--- a/src/nautilus-places-view.c
+++ b/src/nautilus-places-view.c
@@ -32,7 +32,6 @@ typedef struct
 {
     GFile *location;
     NautilusQuery *search_query;
-    NautilusToolbarMenuSections *toolbar_menu_sections;
 
     GtkWidget *places_view;
 } NautilusPlacesViewPrivate;
@@ -150,8 +149,6 @@ nautilus_places_view_finalize (GObject *object)
     g_clear_object (&priv->location);
     g_clear_object (&priv->search_query);
 
-    g_free (priv->toolbar_menu_sections);
-
     G_OBJECT_CLASS (nautilus_places_view_parent_class)->finalize (object);
 }
 
@@ -310,11 +307,7 @@ nautilus_places_view_set_search_query (NautilusView  *view,
 static NautilusToolbarMenuSections *
 nautilus_places_view_get_toolbar_menu_sections (NautilusView *view)
 {
-    NautilusPlacesViewPrivate *priv;
-
-    priv = nautilus_places_view_get_instance_private (NAUTILUS_PLACES_VIEW (view));
-
-    return priv->toolbar_menu_sections;
+    return NULL;
 }
 
 static gboolean
@@ -413,10 +406,6 @@ nautilus_places_view_init (NautilusPlacesView *self)
                               "show-error-message",
                               G_CALLBACK (show_error_message_cb),
                               self);
-
-    /* Toolbar menu */
-    priv->toolbar_menu_sections = g_new0 (NautilusToolbarMenuSections, 1);
-    priv->toolbar_menu_sections->supports_undo_redo = FALSE;
 }
 
 NautilusPlacesView *
diff --git a/src/nautilus-toolbar-menu-sections.h b/src/nautilus-toolbar-menu-sections.h
index c7864eac8..9b5c136fb 100644
--- a/src/nautilus-toolbar-menu-sections.h
+++ b/src/nautilus-toolbar-menu-sections.h
@@ -24,9 +24,8 @@ G_BEGIN_DECLS
 typedef struct _NautilusToolbarMenuSections NautilusToolbarMenuSections;
 
 struct _NautilusToolbarMenuSections {
-        GtkWidget *zoom_section;
-        GtkWidget *extended_section;
-        gboolean   supports_undo_redo;
+        GMenuModel *sort_section;
+        GMenuModel *zoom_section;
 };
 
-G_END_DECLS
\ No newline at end of file
+G_END_DECLS
diff --git a/src/nautilus-toolbar.c b/src/nautilus-toolbar.c
index c133e9cbd..8b1ef1801 100644
--- a/src/nautilus-toolbar.c
+++ b/src/nautilus-toolbar.c
@@ -80,15 +80,15 @@ struct _NautilusToolbar
 
     GtkWidget *operations_button;
     GtkWidget *view_button;
-    GtkWidget *view_menu_zoom_section;
-    GtkWidget *view_menu_undo_redo_section;
-    GtkWidget *view_menu_extended_section;
-    GtkWidget *undo_button;
-    GtkWidget *redo_button;
     GtkWidget *view_toggle_button;
     GtkWidget *view_toggle_icon;
 
+    GtkWidget *view_menu;
+    GMenuModel *view_menu_model;
+
     GtkWidget *app_menu;
+    GMenuModel *app_menu_model;
+    GMenuModel *undo_redo_section;
 
     GtkWidget *operations_popover;
     GtkWidget *operations_list;
@@ -727,28 +727,15 @@ on_progress_has_viewers_changed (NautilusProgressInfoManager *manager,
 }
 
 static void
-update_menu_item (GtkWidget       *menu_item,
-                  NautilusToolbar *self,
-                  const char      *action_name,
-                  gboolean         enabled,
-                  char            *label)
+update_action (NautilusToolbar *self,
+               const char      *action_name,
+               gboolean         enabled)
 {
     GAction *action;
-    GValue val = G_VALUE_INIT;
 
     /* Activate/deactivate */
     action = g_action_map_lookup_action (G_ACTION_MAP (self->window), action_name);
     g_simple_action_set_enabled (G_SIMPLE_ACTION (action), enabled);
-
-    /* Set the text of the menu item. Can't use gtk_button_set_label here as
-     * we need to set the text property, not the label. There's no equivalent
-     * gtk_model_button_set_text function (refer to #766083 for discussion
-     * on adding a set_text function)
-     */
-    g_value_init (&val, G_TYPE_STRING);
-    g_value_set_string (&val, label);
-    g_object_set_property (G_OBJECT (menu_item), "text", &val);
-    g_value_unset (&val);
 }
 
 static void
@@ -763,6 +750,8 @@ undo_manager_changed (NautilusToolbar *self)
     g_autofree gchar *undo_description = NULL;
     g_autofree gchar *redo_description = NULL;
     gboolean is_undo;
+    g_autoptr (GMenu) updated_section = g_menu_new ();
+    g_autoptr (GMenuItem) menu_item = NULL;
 
     /* Look up the last action from the undo manager, and get the text that
      * describes it, e.g. "Undo Create Folder"/"Redo Create Folder"
@@ -790,14 +779,21 @@ undo_manager_changed (NautilusToolbar *self)
         g_free (undo_label);
         undo_label = g_strdup (_("_Undo"));
     }
-    update_menu_item (self->undo_button, self, "undo", undo_active, undo_label);
+    g_set_object (&menu_item, g_menu_item_new (undo_label, "win.undo"));
+    g_menu_append_item (updated_section, menu_item);
+    update_action (self, "undo", undo_active);
 
     if (!redo_active || redo_label == NULL)
     {
         g_free (redo_label);
         redo_label = g_strdup (_("_Redo"));
     }
-    update_menu_item (self->redo_button, self, "redo", redo_active, redo_label);
+    g_set_object (&menu_item, g_menu_item_new (redo_label, "win.redo"));
+    g_menu_append_item (updated_section, menu_item);
+    update_action (self, "redo", redo_active);
+
+    nautilus_gmenu_set_from_model (G_MENU (self->undo_redo_section),
+                                   G_MENU_MODEL (updated_section));
 }
 
 static void
@@ -933,6 +929,14 @@ static void
 nautilus_toolbar_init (NautilusToolbar *self)
 {
     gtk_widget_init_template (GTK_WIDGET (self));
+
+    gtk_popover_bind_model (GTK_POPOVER (self->app_menu),
+                            self->app_menu_model,
+                            NULL);
+
+    gtk_popover_bind_model (GTK_POPOVER (self->view_menu),
+                            self->view_menu_model,
+                            NULL);
 }
 
 void
@@ -1190,7 +1194,11 @@ nautilus_toolbar_class_init (NautilusToolbarClass *klass)
     gtk_widget_class_bind_template_child (widget_class, NautilusToolbar, view_button);
     gtk_widget_class_bind_template_child (widget_class, NautilusToolbar, view_toggle_button);
     gtk_widget_class_bind_template_child (widget_class, NautilusToolbar, view_toggle_icon);
+    gtk_widget_class_bind_template_child (widget_class, NautilusToolbar, view_menu);
+    gtk_widget_class_bind_template_child (widget_class, NautilusToolbar, view_menu_model);
     gtk_widget_class_bind_template_child (widget_class, NautilusToolbar, app_menu);
+    gtk_widget_class_bind_template_child (widget_class, NautilusToolbar, app_menu_model);
+    gtk_widget_class_bind_template_child (widget_class, NautilusToolbar, undo_redo_section);
     gtk_widget_class_bind_template_child (widget_class, NautilusToolbar, back_button);
     gtk_widget_class_bind_template_child (widget_class, NautilusToolbar, back_menu);
     gtk_widget_class_bind_template_child (widget_class, NautilusToolbar, forward_button);
@@ -1200,12 +1208,6 @@ nautilus_toolbar_class_init (NautilusToolbarClass *klass)
     gtk_widget_class_bind_template_child (widget_class, NautilusToolbar, path_bar_container);
     gtk_widget_class_bind_template_child (widget_class, NautilusToolbar, location_entry_container);
 
-    gtk_widget_class_bind_template_child (widget_class, NautilusToolbar, view_menu_zoom_section);
-    gtk_widget_class_bind_template_child (widget_class, NautilusToolbar, view_menu_undo_redo_section);
-    gtk_widget_class_bind_template_child (widget_class, NautilusToolbar, view_menu_extended_section);
-    gtk_widget_class_bind_template_child (widget_class, NautilusToolbar, undo_button);
-    gtk_widget_class_bind_template_child (widget_class, NautilusToolbar, redo_button);
-
     gtk_widget_class_bind_template_child (widget_class, NautilusToolbar, search_button);
 
     gtk_widget_class_bind_template_callback (widget_class, on_operations_icon_draw);
@@ -1284,34 +1286,29 @@ on_slot_toolbar_menu_sections_changed (NautilusToolbar    *self,
                                        NautilusWindowSlot *slot)
 {
     NautilusToolbarMenuSections *new_sections;
-
-    box_remove_all_children (GTK_BOX (self->view_menu_zoom_section));
-    box_remove_all_children (GTK_BOX (self->view_menu_extended_section));
+    g_autoptr (GMenuItem) zoom_item = NULL;
+    g_autoptr (GMenuItem) sort_item = NULL;
 
     new_sections = nautilus_window_slot_get_toolbar_menu_sections (slot);
+
+    gtk_widget_set_sensitive (self->view_button, (new_sections != NULL));
     if (new_sections == NULL)
     {
         return;
     }
 
-    gtk_widget_set_visible (self->view_menu_undo_redo_section,
-                            new_sections->supports_undo_redo);
+    /* Let's assume that zoom and sort sections are the first and second items
+     * in view_menu_model, as per nautilus-toolbar.ui. */
 
-    if (new_sections->zoom_section != NULL)
-    {
-        gtk_box_pack_start (GTK_BOX (self->view_menu_zoom_section),
-                            new_sections->zoom_section, FALSE, FALSE, 0);
-    }
-
-    if (new_sections->extended_section != NULL)
-    {
-        gtk_box_pack_start (GTK_BOX (self->view_menu_extended_section),
-                            new_sections->extended_section, FALSE, FALSE, 0);
-    }
+    zoom_item = g_menu_item_new_from_model (self->view_menu_model, 0);
+    g_menu_remove (G_MENU (self->view_menu_model), 0);
+    g_menu_item_set_section (zoom_item, new_sections->zoom_section);
+    g_menu_insert_item (G_MENU (self->view_menu_model), 0, zoom_item);
 
-    gtk_widget_set_sensitive (self->view_button, (new_sections->extended_section != NULL ||
-                                                  new_sections->zoom_section != NULL ||
-                                                  new_sections->supports_undo_redo));
+    sort_item = g_menu_item_new_from_model (self->view_menu_model, 1);
+    g_menu_remove (G_MENU (self->view_menu_model), 1);
+    g_menu_item_set_section (sort_item, new_sections->sort_section);
+    g_menu_insert_item (G_MENU (self->view_menu_model), 1, sort_item);
 }
 
 
diff --git a/src/nautilus-ui-utilities.c b/src/nautilus-ui-utilities.c
index 195f765f9..2f7cf4d40 100644
--- a/src/nautilus-ui-utilities.c
+++ b/src/nautilus-ui-utilities.c
@@ -68,6 +68,72 @@ nautilus_gmenu_set_from_model (GMenu      *target_menu,
     }
 }
 
+/**
+ * nautilus_g_menu_model_find_by_string:
+ * @model: the #GMenuModel with items to search
+ * @attribute: the menu item attribute to compare with
+ * @string: the string to match the value of @attribute
+ *
+ * This will search for an item in the model which has got the @attribute and
+ * whose value is equal to @string.
+ *
+ * It is assumed that @attribute has the a GVariant format string "s".
+ *
+ * Returns: The index of the first match in the model, or -1 if no item matches.
+ */
+gint
+nautilus_g_menu_model_find_by_string (GMenuModel  *model,
+                                      const gchar *attribute,
+                                      const gchar *string)
+{
+    gint item_index = -1;
+    gint n_items;
+
+    n_items = g_menu_model_get_n_items (model);
+    for (gint i = 0; i < n_items; i++)
+    {
+        g_autofree gchar *value = NULL;
+        if (g_menu_model_get_item_attribute (model, i, attribute, "s", &value) &&
+            g_strcmp0 (value, string) == 0)
+        {
+            item_index = i;
+            break;
+        }
+    }
+    return item_index;
+}
+
+/**
+ * nautilus_g_menu_replace_string_in_item:
+ * @menu: the #GMenu to modify
+ * @i: the position of the item to change
+ * @attribute: the menu item attribute to change
+ * @string: the string to change the value of @attribute to
+ *
+ * This will replace the item at @position with a new item which is identical
+ * except that it has @attribute set to @string.
+ *
+ * This is useful e.g. when want to change the menu model of a #GtkPopover and
+ * you have a pointer to its menu model but not to the popover itself, so you
+ * can't just set a new model. With this method, the GtkPopover is notified of
+ * changes in its model and updates its contents accordingly.
+ *
+ * It is assumed that @attribute has the a GVariant format string "s".
+ */
+void
+nautilus_g_menu_replace_string_in_item (GMenu       *menu,
+                                        gint         i,
+                                        const gchar *attribute,
+                                        const gchar *string)
+{
+    g_autoptr (GMenuItem) item = NULL;
+
+    item = g_menu_item_new_from_model (G_MENU_MODEL (menu), i);
+    g_menu_item_set_attribute (item, attribute, "s", string);
+    g_menu_remove (menu, i);
+    g_menu_insert_item (menu, i, item);
+}
+
 #define NAUTILUS_THUMBNAIL_FRAME_LEFT 3
 #define NAUTILUS_THUMBNAIL_FRAME_TOP 3
 #define NAUTILUS_THUMBNAIL_FRAME_RIGHT 3
diff --git a/src/nautilus-ui-utilities.h b/src/nautilus-ui-utilities.h
index 1136e1de6..24fb74eee 100644
--- a/src/nautilus-ui-utilities.h
+++ b/src/nautilus-ui-utilities.h
@@ -27,6 +27,13 @@
 
 void        nautilus_gmenu_set_from_model           (GMenu             *target_menu,
                                                      GMenuModel        *source_model);
+gint        nautilus_g_menu_model_find_by_string    (GMenuModel        *model,
+                                                     const gchar       *attribute,
+                                                     const gchar       *string);
+void        nautilus_g_menu_replace_string_in_item  (GMenu             *menu,
+                                                     gint               i,
+                                                     const gchar       *attribute,
+                                                     const gchar       *string);
 
 void        nautilus_ui_frame_image                 (GdkPixbuf        **pixbuf);
 void        nautilus_ui_frame_video                 (GdkPixbuf        **pixbuf);
diff --git a/src/resources/css/nautilus.css b/src/resources/css/nautilus.css
index ee25a36a8..82dc1d4a2 100644
--- a/src/resources/css/nautilus.css
+++ b/src/resources/css/nautilus.css
@@ -1,9 +1,3 @@
-.nautilus-menu-sort-heading {
-    min-height: 26px;
-    padding-left: 5px;
-    padding-right: 5px;
-}
-
 label.encrypted_zip,
 row.encrypted_zip label.title {
     background-image: -gtk-icontheme('system-lock-screen-symbolic');
diff --git a/src/resources/ui/nautilus-toolbar-view-menu.ui b/src/resources/ui/nautilus-toolbar-view-menu.ui
index 760820f40..265aec606 100644
--- a/src/resources/ui/nautilus-toolbar-view-menu.ui
+++ b/src/resources/ui/nautilus-toolbar-view-menu.ui
@@ -1,263 +1,66 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!-- Generated with glade 3.22.0 -->
 <interface>
-  <requires lib="gtk+" version="3.16"/>
-  <object class="GtkBox" id="extended_section">
-    <property name="width_request">160</property>
-    <property name="visible">True</property>
-    <property name="can_focus">False</property>
-    <property name="orientation">vertical</property>
-    <child>
-      <object class="GtkBox" id="sort_menu">
-        <property name="visible">True</property>
-        <property name="can_focus">False</property>
-        <property name="orientation">vertical</property>
-        <child>
-          <object class="GtkSeparator">
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
-            <property name="margin_top">6</property>
-            <property name="margin_bottom">6</property>
-          </object>
-          <packing>
-            <property name="position">0</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkLabel">
-            <property name="visible">True</property>
-            <property name="sensitive">False</property>
-            <property name="can_focus">False</property>
-            <property name="label" translatable="yes" context="menu item" comments="Translators: a menu item 
in a group of sorting options in a toolbar menu, with criterions such as &quot;A-Z&quot; or &quot;Last 
Modified&quot;.">Sort</property>
-            <property name="xalign">0</property>
-            <style>
-              <class name="nautilus-menu-sort-heading"/>
-            </style>
-          </object>
-          <packing>
-            <property name="position">1</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkModelButton" id="sort_name">
-            <property name="visible">True</property>
-            <property name="can_focus">True</property>
-            <property name="receives_default">False</property>
-            <property name="action_name">view.sort</property>
-            <property name="action_target">'name'</property>
-            <property name="text" translatable="yes" context="Sort Criterion" comments="This is used to sort 
by name in the toolbar view menu">_A-Z</property>
-          </object>
-          <packing>
-            <property name="position">2</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkModelButton" id="sort_name_desc">
-            <property name="visible">True</property>
-            <property name="can_focus">True</property>
-            <property name="receives_default">False</property>
-            <property name="action_name">view.sort</property>
-            <property name="action_target">'name-desc'</property>
-            <property name="text" translatable="yes" context="Sort Criterion" comments="This is used to sort 
by name, in descending order in the toolbar view menu">_Z-A</property>
-          </object>
-          <packing>
-            <property name="position">3</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkModelButton" id="sort_modification_date_desc">
-            <property name="visible">True</property>
-            <property name="can_focus">True</property>
-            <property name="receives_default">False</property>
-            <property name="action_name">view.sort</property>
-            <property name="action_target">'modification-date-desc'</property>
-            <property name="text" translatable="yes">Last _Modified</property>
-          </object>
-          <packing>
-            <property name="position">4</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkModelButton" id="sort_modification_date">
-            <property name="visible">True</property>
-            <property name="can_focus">True</property>
-            <property name="receives_default">False</property>
-            <property name="action_name">view.sort</property>
-            <property name="action_target">'modification-date'</property>
-            <property name="text" translatable="yes">_First Modified</property>
-          </object>
-          <packing>
-            <property name="position">5</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkModelButton" id="sort_size">
-            <property name="visible">True</property>
-            <property name="can_focus">True</property>
-            <property name="receives_default">False</property>
-            <property name="action_name">view.sort</property>
-            <property name="action_target">'size'</property>
-            <property name="text" translatable="yes">_Size</property>
-          </object>
-          <packing>
-            <property name="position">6</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkModelButton" id="sort_type">
-            <property name="visible">True</property>
-            <property name="can_focus">True</property>
-            <property name="receives_default">False</property>
-            <property name="action_name">view.sort</property>
-            <property name="action_target">'type'</property>
-            <property name="text" translatable="yes">_Type</property>
-          </object>
-          <packing>
-            <property name="position">7</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkModelButton" id="sort_trash_time">
-            <property name="can_focus">True</property>
-            <property name="receives_default">False</property>
-            <property name="action_name">view.sort</property>
-            <property name="action_target">'trash-time'</property>
-            <property name="text" translatable="yes">Last _Trashed</property>
-          </object>
-          <packing>
-            <property name="position">8</property>
-          </packing>
-        </child>
-      </object>
-      <packing>
-        <property name="position">0</property>
-      </packing>
-    </child>
-    <child>
-      <object class="GtkSeparator">
-        <property name="visible">True</property>
-        <property name="can_focus">False</property>
-        <property name="margin_top">6</property>
-        <property name="margin_bottom">6</property>
-      </object>
-      <packing>
-        <property name="position">1</property>
-      </packing>
-    </child>
-    <child>
-      <object class="GtkModelButton" id="visible_columns">
-        <property name="can_focus">True</property>
-        <property name="receives_default">False</property>
-        <property name="action_name">view.visible-columns</property>
-        <property name="text" translatable="yes">_Visible Columns…</property>
-      </object>
-      <packing>
-        <property name="position">2</property>
-      </packing>
-    </child>
-    <child>
-      <object class="GtkModelButton" id="reload">
-        <property name="visible">True</property>
-        <property name="can_focus">True</property>
-        <property name="receives_default">False</property>
-        <property name="action_name">win.reload</property>
-        <property name="text" translatable="yes">R_eload</property>
-      </object>
-      <packing>
-        <property name="position">4</property>
-      </packing>
-    </child>
-    <child>
-      <object class="GtkModelButton" id="stop">
-        <property name="can_focus">True</property>
-        <property name="receives_default">False</property>
-        <property name="action_name">win.stop</property>
-        <property name="text" translatable="yes">St_op</property>
-      </object>
-      <packing>
-        <property name="position">5</property>
-      </packing>
-    </child>
-  </object>
-  <object class="GtkBox" id="zoom_section">
-    <property name="width_request">160</property>
-    <property name="visible">True</property>
-    <property name="can_focus">False</property>
-    <property name="orientation">vertical</property>
-    <child>
-      <object class="GtkBox" id="zoom_controls_box">
-        <property name="visible">True</property>
-        <property name="can_focus">False</property>
-        <property name="homogeneous">True</property>
-        <child>
-          <object class="GtkButton" id="zoom-out">
-            <property name="hexpand">True</property>
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
-            <property name="receives_default">False</property>
-            <property name="tooltip_text" translatable="yes">Zoom out</property>
-            <property name="action_name">view.zoom-out</property>
-            <child>
-              <object class="GtkImage">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="icon_name">zoom-out-symbolic</property>
-                <property name="icon_size">1</property>
-              </object>
-            </child>
-          </object>
-          <packing>
-            <property name="position">0</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkButton" id="zoom-default">
-            <property name="hexpand">True</property>
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
-            <property name="receives_default">False</property>
-            <property name="tooltip_text" translatable="yes">Reset zoom</property>
-            <property name="action_name">view.zoom-standard</property>
-            <child>
-              <object class="GtkLabel" id="zoom_level_label">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="width_chars">5</property>
-              </object>
-            </child>
-          </object>
-          <packing>
-            <property name="position">1</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkButton" id="zoom-in">
-            <property name="hexpand">True</property>
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
-            <property name="receives_default">False</property>
-            <property name="tooltip_text" translatable="yes">Zoom in</property>
-            <property name="action_name">view.zoom-in</property>
-            <child>
-              <object class="GtkImage">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="icon_name">zoom-in-symbolic</property>
-                <property name="icon_size">1</property>
-              </object>
-            </child>
-          </object>
-          <packing>
-            <property name="position">2</property>
-          </packing>
-        </child>
-        <style>
-          <class name="linked"/>
-        </style>
-      </object>
-      <packing>
-        <property name="position">0</property>
-      </packing>
-    </child>
-  </object>
+  <menu id="zoom_section">
+    <item>
+      <attribute name="label" translatable="yes">Zoom out</attribute>
+      <attribute name="action">view.zoom-out</attribute>
+      <attribute name="verb-icon">zoom-out-symbolic</attribute>
+    </item>
+    <item>
+      <!-- This label is a placeholder. The view is going to replace it with a
+           percentage, like this:   [ - | 100% | + ]                       -->
+      <attribute name="label" translatable="yes">Reset zoom</attribute>
+      <attribute name="action">view.zoom-standard</attribute>
+    </item>
+    <item>
+      <attribute name="label" translatable="yes">Zoom in</attribute>
+      <attribute name="action">view.zoom-in</attribute>
+      <attribute name="verb-icon">zoom-in-symbolic</attribute>
+    </item>
+  </menu>
+  <menu id="sort_section">
+    <item>
+      <attribute name="action">view.sort</attribute>
+      <attribute name="target">name</attribute>
+      <attribute name="label" translatable="yes" context="Sort Criterion" comments="This is used to sort by 
name in the toolbar view menu">_A-Z</attribute>
+      <attribute name="hidden-when">action-disabled</attribute>
+    </item>
+    <item>
+      <attribute name="action">view.sort</attribute>
+      <attribute name="target">name-desc</attribute>
+      <attribute name="label" translatable="yes" context="Sort Criterion" comments="This is used to sort by 
name, in descending order in the toolbar view menu">_Z-A</attribute>
+      <attribute name="hidden-when">action-disabled</attribute>
+    </item>
+    <item>
+      <attribute name="action">view.sort</attribute>
+      <attribute name="target">modification-date-desc</attribute>
+      <attribute name="label" translatable="yes">Last _Modified</attribute>
+      <attribute name="hidden-when">action-disabled</attribute>
+    </item>
+    <item>
+      <attribute name="action">view.sort</attribute>
+      <attribute name="target">modification-date</attribute>
+      <attribute name="label" translatable="yes">_First Modified</attribute>
+      <attribute name="hidden-when">action-disabled</attribute>
+    </item>
+    <item>
+      <attribute name="action">view.sort</attribute>
+      <attribute name="target">size</attribute>
+      <attribute name="label" translatable="yes">_Size</attribute>
+      <attribute name="hidden-when">action-disabled</attribute>
+    </item>
+    <item>
+      <attribute name="action">view.sort</attribute>
+      <attribute name="target">type</attribute>
+      <attribute name="label" translatable="yes">_Type</attribute>
+      <attribute name="hidden-when">action-disabled</attribute>
+    </item>
+    <item>
+      <attribute name="action">view.sort</attribute>
+      <attribute name="target">trash-time</attribute>
+      <attribute name="label" translatable="yes">Last _Trashed</attribute>
+      <attribute name="hidden-when">action-disabled</attribute>
+    </item>
+  </menu>
 </interface>
diff --git a/src/resources/ui/nautilus-toolbar.ui b/src/resources/ui/nautilus-toolbar.ui
index e481892e4..52e24e4d9 100644
--- a/src/resources/ui/nautilus-toolbar.ui
+++ b/src/resources/ui/nautilus-toolbar.ui
@@ -10,278 +10,106 @@
     <property name="position">bottom</property>
     <property name="relative-to">forward_button</property>
   </object>
-  <object class="GtkPopoverMenu" id="app_menu">
-    <property name="can_focus">False</property>
-    <child>
-      <object class="GtkBox">
-        <property name="visible">True</property>
-        <property name="can_focus">False</property>
-        <property name="margin_start">10</property>
-        <property name="margin_end">10</property>
-        <property name="margin_top">10</property>
-        <property name="margin_bottom">10</property>
-        <property name="orientation">vertical</property>
-        <child>
-          <object class="GtkBox">
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
-            <property name="margin_bottom">6</property>
-            <property name="spacing">6</property>
-            <child>
-              <object class="GtkButton">
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="receives_default">True</property>
-                <property name="tooltip_text" translatable="yes">New Window</property>
-                <property name="hexpand">True</property>
-                <property name="action_name">app.new-window</property>
-                <child>
-                  <object class="GtkImage">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="icon_name">window-new-symbolic</property>
-                  </object>
-                </child>
-              </object>
-              <packing>
-                <property name="position">0</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkButton">
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="receives_default">True</property>
-                <property name="tooltip_text" translatable="yes">New Tab</property>
-                <property name="hexpand">True</property>
-                <property name="action_name">win.new-tab</property>
-                <child>
-                  <object class="GtkImage">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="icon_name">tab-new-symbolic</property>
-                  </object>
-                </child>
-              </object>
-              <packing>
-                <property name="position">1</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkButton">
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="receives_default">True</property>
-                <property name="tooltip_text" translatable="yes">New Folder</property>
-                <property name="hexpand">True</property>
-                <property name="action_name">view.new-folder</property>
-                <child>
-                  <object class="GtkImage">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="icon_name">folder-new-symbolic</property>
-                  </object>
-                </child>
-              </object>
-              <packing>
-                <property name="position">2</property>
-              </packing>
-            </child>
-          </object>
-          <packing>
-            <property name="position">0</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkSeparator">
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
-          </object>
-          <packing>
-            <property name="position">5</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkModelButton" id="show_hidden_files">
-            <property name="visible">True</property>
-            <property name="can_focus">True</property>
-            <property name="receives_default">False</property>
-            <property name="margin_top">6</property>
-            <property name="action_name">view.show-hidden-files</property>
-            <property name="text" translatable="yes">Show _Hidden Files</property>
-          </object>
-          <packing>
-            <property name="position">6</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkModelButton">
-            <property name="visible">True</property>
-            <property name="can_focus">True</property>
-            <property name="receives_default">True</property>
-            <property name="margin_bottom">6</property>
-            <property name="action_name">app.show-hide-sidebar</property>
-            <property name="text" translatable="yes">Show _Sidebar</property>
-          </object>
-          <packing>
-            <property name="position">7</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkSeparator">
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
-          </object>
-          <packing>
-            <property name="position">8</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkModelButton">
-            <property name="visible">True</property>
-            <property name="can_focus">True</property>
-            <property name="receives_default">True</property>
-            <property name="margin_top">6</property>
-            <property name="action_name">app.preferences</property>
-            <property name="text" translatable="yes">_Preferences</property>
-          </object>
-          <packing>
-            <property name="position">9</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkModelButton">
-            <property name="visible">True</property>
-            <property name="can_focus">True</property>
-            <property name="receives_default">True</property>
-            <property name="action_name">app.show-help-overlay</property>
-            <property name="text" translatable="yes">_Keyboard Shortcuts</property>
-          </object>
-          <packing>
-            <property name="position">10</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkModelButton">
-            <property name="visible">True</property>
-            <property name="can_focus">True</property>
-            <property name="receives_default">True</property>
-            <property name="action_name">app.help</property>
-            <property name="text" translatable="yes">_Help</property>
-          </object>
-          <packing>
-            <property name="position">11</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkModelButton">
-            <property name="visible">True</property>
-            <property name="can_focus">True</property>
-            <property name="receives_default">True</property>
-            <property name="action_name">app.about</property>
-            <property name="text" translatable="yes">_About Files</property>
-          </object>
-          <packing>
-            <property name="position">12</property>
-          </packing>
-        </child>
-      </object>
-      <packing>
-        <property name="submenu">main</property>
-        <property name="position">1</property>
-      </packing>
-    </child>
-  </object>
-  <object class="GtkPopoverMenu" id="menu_popover">
-    <property name="can_focus">False</property>
-    <child>
-      <object class="GtkBox">
-        <property name="width_request">160</property>
-        <property name="visible">True</property>
-        <property name="can_focus">False</property>
-        <property name="margin-top">9</property>
-        <property name="margin-bottom">9</property>
-        <property name="margin-start">9</property>
-        <property name="margin-end">9</property>
-        <property name="orientation">vertical</property>
-        <child>
-          <object class="GtkBox" id="view_menu_zoom_section">
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
-            <property name="orientation">vertical</property>
-            <child>
-              <placeholder/>
-            </child>
-          </object>
-          <packing>
-            <property name="position">1</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkBox" id="view_menu_undo_redo_section">
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
-            <property name="orientation">vertical</property>
-            <child>
-              <object class="GtkSeparator">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="margin_top">6</property>
-                <property name="margin_bottom">6</property>
-              </object>
-              <packing>
-                <property name="position">0</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkModelButton" id="undo_button">
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="receives_default">False</property>
-                <property name="action_name">win.undo</property>
-                <property name="text" translatable="yes">_Undo</property>
-              </object>
-              <packing>
-                <property name="position">1</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkModelButton" id="redo_button">
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="receives_default">False</property>
-                <property name="action_name">win.redo</property>
-                <property name="text" translatable="yes">_Redo</property>
-              </object>
-              <packing>
-                <property name="position">2</property>
-              </packing>
-            </child>
-          </object>
-          <packing>
-            <property name="position">2</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkBox" id="view_menu_extended_section">
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
-            <property name="orientation">vertical</property>
-            <child>
-              <placeholder/>
-            </child>
-          </object>
-          <packing>
-            <property name="position">3</property>
-          </packing>
-        </child>
-      </object>
-      <packing>
-        <property name="submenu">main</property>
-        <property name="position">1</property>
-      </packing>
-    </child>
-  </object>
+  <menu id="view_menu_model">
+    <section>
+      <attribute name="display-hint">horizontal-buttons</attribute>
+      <!--
+           Zoom section.
+
+           The toolbar code assumes this is the first item of view_menu_model.
+           Its contents is provided by the view.
+      -->
+    </section>
+    <section>
+      <attribute name="label" translatable="yes" context="menu item" comments="Translators: a menu item in a 
group of sorting options in a toolbar menu, with criterions such as &quot;A-Z&quot; or &quot;Last 
Modified&quot;.">Sort</attribute>
+      <!--
+           Sort section.
+
+           The toolbar code assumes this is the second item of view_menu_model.
+           Its contents is provided by the view.
+      -->
+    </section>
+    <section>
+      <item>
+        <attribute name="label" translatable="yes">_Visible Columns…</attribute>
+        <attribute name="action">view.visible-columns</attribute>
+        <attribute name="hidden-when">action-missing</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">R_eload</attribute>
+        <attribute name="action">win.reload</attribute>
+        <attribute name="hidden-when">action-disabled</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">St_op</attribute>
+        <attribute name="action">win.stop</attribute>
+        <attribute name="hidden-when">action-disabled</attribute>
+      </item>
+    </section>
+  </menu>
+  <menu id="app_menu_model">
+    <section>
+      <attribute name="display-hint">horizontal-buttons</attribute>
+      <item>
+        <attribute name="label" translatable="yes">New Window</attribute>
+        <attribute name="action">app.new-window</attribute>
+        <attribute name="verb-icon">window-new-symbolic</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">New Tab</attribute>
+        <attribute name="action">win.new-tab</attribute>
+        <attribute name="verb-icon">tab-new-symbolic</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">New Folder</attribute>
+        <attribute name="action">view.new-folder</attribute>
+        <attribute name="verb-icon">folder-new-symbolic</attribute>
+      </item>
+    </section>
+    <section id="undo_redo_section">
+      <!-- Note: This section is often recreated by undo_manager_changed() to
+           change the labels of the actions. If you change anything here,
+           remember to change in the code as well. -->
+      <item>
+        <attribute name="label" translatable="yes">_Undo</attribute>
+        <attribute name="action">win.undo</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">_Redo</attribute>
+        <attribute name="action">win.undo</attribute>
+      </item>
+    </section>
+    <section>
+      <item>
+        <attribute name="label" translatable="yes">Show _Hidden Files</attribute>
+        <attribute name="action">view.show-hidden-files</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">Show _Sidebar</attribute>
+        <attribute name="action">app.show-hide-sidebar</attribute>
+      </item>
+    </section>
+    <section>
+      <item>
+        <attribute name="label" translatable="yes">_Preferences</attribute>
+        <attribute name="action">app.preferences</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">_Keyboard Shortcuts</attribute>
+        <attribute name="action">app.show-help-overlay</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">_Help</attribute>
+        <attribute name="action">app.help</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">_About Files</attribute>
+        <attribute name="action">app.about</attribute>
+      </item>
+    </section>
+  </menu>
+  <object class="GtkPopover" id="app_menu"/>
+  <object class="GtkPopover" id="view_menu"/>
   <object class="GtkPopover" id="operations_popover">
     <property name="can_focus">False</property>
     <child>
@@ -528,7 +356,7 @@
                 <property name="tooltip_text" translatable="yes" comments="“View” is a noun">View 
options</property>
                 <property name="halign">start</property>
                 <property name="action_name">win.view-menu</property>
-                <property name="popover">menu_popover</property>
+                <property name="popover">view_menu</property>
                 <child>
                   <object class="GtkImage">
                     <property name="visible">True</property>


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]