[dconf-editor] Add folder informations entry.



commit 59ed7cab97ec2149d46b3a13314496d41c346eff
Author: Arnaud Bonatti <arnaud bonatti gmail com>
Date:   Thu Sep 20 12:55:18 2018 +0200

    Add folder informations entry.

 editor/browser-stack.vala         |  28 ++++----
 editor/browser-view.vala          |  30 ++++++---
 editor/config-list-box-row.ui     |  30 +++++++++
 editor/dconf-editor.css           |  20 ++++--
 editor/dconf-editor.gresource.xml |   2 +
 editor/dconf-model.vala           |  14 ++++
 editor/dconf-window.vala          | 127 ++++++++++++++++++++++++++++++-------
 editor/help-overlay.ui            |  87 +++++++++++++++++--------
 editor/key-list-box-row.vala      |  42 ++++++++++--
 editor/meson.build                |   2 +
 editor/pathbar.vala               | 130 ++++++++++++++++++++++++++++++--------
 editor/pathentry.ui               |   2 -
 editor/pathentry.vala             |  26 ++++----
 editor/pathwidget.vala            |  29 ++++++---
 editor/registry-info.vala         |  19 +++++-
 editor/registry-list.vala         | 113 +++++++++++++++++++++++++--------
 editor/registry-search.vala       |  95 ++++++++++++++++++----------
 editor/registry-view.vala         |  31 +++++++--
 editor/return-list-box-row.ui     |  30 +++++++++
 19 files changed, 662 insertions(+), 195 deletions(-)
---
diff --git a/editor/browser-stack.vala b/editor/browser-stack.vala
index f353ef0..e42b626 100644
--- a/editor/browser-stack.vala
+++ b/editor/browser-stack.vala
@@ -51,7 +51,7 @@ private class BrowserStack : Grid
 
     internal string get_selected_row_name ()
     {
-        if (current_view != ViewType.OBJECT)
+        if (ViewType.displays_objects_list (current_view))
             return ((RegistryList) stack.get_visible_child ()).get_selected_row_name ();
         return object_view.full_name;
     }
@@ -64,7 +64,7 @@ private class BrowserStack : Grid
     }
 
     internal void select_row (string selected, uint16 last_context_id)
-        requires (current_view != ViewType.OBJECT)
+        requires (ViewType.displays_objects_list (current_view))
     {
         if (selected == "")
             ((RegistryList) stack.get_visible_child ()).select_first_row ();
@@ -88,14 +88,16 @@ private class BrowserStack : Grid
         current_view = type;
         if (type == ViewType.FOLDER)
             stack.set_visible_child (folder_view);
-        else if (type == ViewType.OBJECT)
+        else if (ViewType.displays_object_infos (type))
             stack.set_visible_child (object_view);
-        else // (type == ViewType.SEARCH)
+        else if (type == ViewType.SEARCH)
         {
             search_view.start_search (path);
             stack.set_transition_type (StackTransitionType.NONE);
             stack.set_visible_child (search_view);
+            search_view.select_first_row ();
         }
+        else assert_not_reached ();
 
         if (clean_object_view)
             object_view.clean ();
@@ -119,26 +121,26 @@ private class BrowserStack : Grid
 
     internal bool toggle_row_popover ()
     {
-        if (current_view != ViewType.OBJECT)
+        if (ViewType.displays_objects_list (current_view))
             return ((RegistryList) stack.get_visible_child ()).toggle_row_popover ();
         return false;
     }
 
     internal void toggle_boolean_key ()
     {
-        if (current_view != ViewType.OBJECT)
+        if (ViewType.displays_objects_list (current_view))
             ((RegistryList) stack.get_visible_child ()).toggle_boolean_key ();
     }
 
     internal void set_selected_to_default ()
     {
-        if (current_view != ViewType.OBJECT)
+        if (ViewType.displays_objects_list (current_view))
             ((RegistryList) stack.get_visible_child ()).set_selected_to_default ();
     }
 
     internal void discard_row_popover ()
     {
-        if (current_view != ViewType.OBJECT)
+        if (ViewType.displays_objects_list (current_view))
             ((RegistryList) stack.get_visible_child ()).discard_row_popover ();
     }
 
@@ -158,9 +160,9 @@ private class BrowserStack : Grid
     * * Reload
     \*/
 
-    internal void set_search_parameters (string current_path, string [] bookmarks, SortingOptions 
sorting_options)
+    internal void set_search_parameters (string current_path, uint16 current_context_id, string [] 
bookmarks, SortingOptions sorting_options)
     {
-        search_view.set_search_parameters (current_path, bookmarks, sorting_options);
+        search_view.set_search_parameters (current_path, current_context_id, bookmarks, sorting_options);
     }
 
     internal bool check_reload_folder (Variant? fresh_key_model)
@@ -198,7 +200,7 @@ private class BrowserStack : Grid
 
     internal void row_grab_focus ()
     {
-        if (current_view != ViewType.OBJECT)
+        if (ViewType.displays_objects_list (current_view))
             ((RegistryList) stack.get_visible_child ()).row_grab_focus ();
     }
 
@@ -210,14 +212,14 @@ private class BrowserStack : Grid
 
     internal bool up_pressed ()
     {
-        if (current_view != ViewType.OBJECT)
+        if (ViewType.displays_objects_list (current_view))
             return ((RegistryList) stack.get_visible_child ()).up_or_down_pressed (false);
         return false;
     }
 
     internal bool down_pressed ()
     {
-        if (current_view != ViewType.OBJECT)
+        if (ViewType.displays_objects_list (current_view))
             return ((RegistryList) stack.get_visible_child ()).up_or_down_pressed (true);
         return false;
     }
diff --git a/editor/browser-view.vala b/editor/browser-view.vala
index e447645..00658ca 100644
--- a/editor/browser-view.vala
+++ b/editor/browser-view.vala
@@ -19,7 +19,11 @@ using Gtk;
 
 private class SimpleSettingObject : Object
 {
+    public bool is_pinned           { internal get; internal construct; }
+
+    public bool is_config           { internal get; private construct; }
     public bool is_search           { internal get; internal construct; }
+
     public uint16 context_id        { internal get; internal construct; }
     public string name              { internal get; internal construct; }
     public string full_name         { internal get; internal construct; }
@@ -28,18 +32,19 @@ private class SimpleSettingObject : Object
 
     construct
     {
+        is_config = is_pinned && !is_search;
         casefolded_name = name.casefold ();
     }
 
-    internal SimpleSettingObject.from_base_path (uint16 _context_id, string _name, string _base_path, bool 
_is_search = false)
+    internal SimpleSettingObject.from_base_path (uint16 _context_id, string _name, string _base_path, bool 
_is_search = false, bool _is_config_or_is_pinned_search = false)
     {
         string _full_name = ModelUtils.recreate_full_name (_base_path, _name, 
ModelUtils.is_folder_context_id (_context_id));
-        Object (context_id: _context_id, name: _name, full_name: _full_name, is_search: _is_search);
+        Object (context_id: _context_id, name: _name, full_name: _full_name, is_search: _is_search, 
is_pinned: _is_config_or_is_pinned_search);
     }
 
-    internal SimpleSettingObject.from_full_name (uint16 _context_id, string _name, string _full_name, bool 
_is_search = false)
+    internal SimpleSettingObject.from_full_name (uint16 _context_id, string _name, string _full_name, bool 
_is_search = false, bool _is_config_or_is_pinned_search = false)
     {
-        Object (context_id: _context_id, name: _name, full_name: _full_name, is_search: _is_search);
+        Object (context_id: _context_id, name: _name, full_name: _full_name, is_search: _is_search, 
is_pinned: _is_config_or_is_pinned_search);
     }
 }
 
@@ -200,7 +205,7 @@ private class BrowserView : Grid
     }
 
     internal void select_row (string selected)
-        requires (current_view != ViewType.OBJECT)
+        requires (ViewType.displays_objects_list (current_view))
     {
         current_child.select_row (selected, last_context_id);
     }
@@ -236,14 +241,14 @@ private class BrowserView : Grid
     internal void set_search_parameters (string current_path, string [] bookmarks)
     {
         hide_reload_warning ();
-        current_child.set_search_parameters (current_path, bookmarks, sorting_options);
+        current_child.set_search_parameters (current_path, last_context_id, bookmarks, sorting_options);
     }
 
     internal bool check_reload (ViewType type, string path, bool show_infobar)
     {
         SettingsModel model = modifications_handler.model;
 
-        if (type == ViewType.FOLDER)
+        if (type == ViewType.FOLDER || (type == ViewType.CONFIG && ModelUtils.is_folder_path (path)))
         {
             if (!current_child.check_reload_folder (model.get_children (path)))
                 return false;
@@ -253,7 +258,7 @@ private class BrowserView : Grid
                 return false;
             }
         }
-        else if (type == ViewType.OBJECT)
+        else if (type == ViewType.OBJECT || type == ViewType.CONFIG)
         {
             if (model.key_exists (path, last_context_id))
             {
@@ -270,7 +275,9 @@ private class BrowserView : Grid
                 return false;
             }
         }
-        else // (type == ViewType.SEARCH)
+        else if (type == ViewType.SEARCH)
+            assert_not_reached ();
+        else
             assert_not_reached ();
         return true;
     }
@@ -382,6 +389,11 @@ private class SettingComparator : Object
 
     internal int compare (SimpleSettingObject a, SimpleSettingObject b)
     {
+        if (a.is_pinned)
+            return -1;
+        if (b.is_pinned)
+            return 1;
+
         if (a.context_id != b.context_id)
         {
             int sort_hint = 0;
diff --git a/editor/config-list-box-row.ui b/editor/config-list-box-row.ui
new file mode 100644
index 0000000..1b959cc
--- /dev/null
+++ b/editor/config-list-box-row.ui
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <!-- interface-requires gtk+ 3.0 -->
+  <template class="ConfigListBoxRow" parent="ClickableListBoxRow">
+    <property name="visible">True</property>
+    <style>
+      <class name="managed"/>
+      <class name="config"/>
+      <class name="small"/>
+    </style>
+    <child>
+      <object class="GtkGrid">
+        <property name="visible">True</property>
+        <property name="orientation">horizontal</property>
+        <child>
+          <object class="GtkLabel" id="folder_name_label">
+            <property name="visible">True</property>
+            <property name="vexpand">True</property>
+            <property name="xalign">0</property>
+            <property name="ellipsize">end</property> <!-- Epiphany web apps during search... -->
+            <style>
+              <class name="key-name"/>
+              <class name="italic-label"/>
+            </style>
+          </object>
+        </child>
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/editor/dconf-editor.css b/editor/dconf-editor.css
index 2267741..415f888 100644
--- a/editor/dconf-editor.css
+++ b/editor/dconf-editor.css
@@ -68,12 +68,6 @@
 * * lists rows height and icon
 \*/
 
-/* hack: fix next lines misplacement when the first line is a header */
-
-list.keys-list > grid.big-popover.dim-label.vertical + grid.vertical {
-  margin-top:-1px;
-}
-
 /* row height */
                                    .keys-list          > row         { transition:min-height 0.3s,
                                                                                   margin-left 0.3s, 
margin-right 0.3s,
@@ -144,6 +138,10 @@ list.keys-list > grid.big-popover.dim-label.vertical + grid.vertical {
                                    .keys-list:dir(ltr) > row > .managed         { background-position:       
     0.75rem  center; }
                                    .keys-list:dir(rtl) > row > .managed         { 
background-position:calc(100% - 0.75rem) center; }
 
+                                   .keys-list          > row > .managed.small   { background-size:1.1rem; } 
/* ~16px usually, base size */
+                                   .keys-list:dir(ltr) > row > .managed.small   { background-position:       
     0.95rem  center; }
+                                   .keys-list:dir(rtl) > row > .managed.small   { 
background-position:calc(100% - 0.95rem) center; }
+
              .small-keys-list-rows .keys-list          > row > .managed         { background-size:1.1rem; } 
/* ~16px usually, base size */
              .small-keys-list-rows .keys-list:dir(ltr) > row > .managed         { background-position:       
     0.55rem  center; }
              .small-keys-list-rows .keys-list:dir(rtl) > row > .managed         { 
background-position:calc(100% - 0.55rem) center; }
@@ -152,9 +150,11 @@ list.keys-list > grid.big-popover.dim-label.vertical + grid.vertical {
 
              row        >                .folder               { 
background-image:-gtk-icontheme("folder-symbolic"); }
              row:active >                .folder               { 
background-image:-gtk-icontheme("folder-open-symbolic"); }
-
              row >                       .search               { 
background-image:-gtk-icontheme("edit-find-symbolic"); }
 
+             row >                       .return               { 
background-image:-gtk-icontheme("edit-undo-symbolic"); }
+             row >                       .config               { 
background-image:-gtk-icontheme("dialog-information-symbolic"); }
+
              row >                       .key.delayed,
              row >             .dconf-key.key.delayed,
              row >  .edited.gsettings-key.key.delayed          { 
background-image:-gtk-icontheme("document-open-recent-symbolic"); }
@@ -294,6 +294,12 @@ list.keys-list > grid.big-popover.dim-label.vertical + grid.vertical {
   border-bottom-color:@borders;
 }
 
+/* dashed in config */
+
+.pathbar.config   > button.active                  > .item {
+  border-bottom-style:dashed;
+}
+
 /* inexistent items */
 .pathbar > label,
 .pathbar > button.inexistent:not(.active) > label.item {
diff --git a/editor/dconf-editor.gresource.xml b/editor/dconf-editor.gresource.xml
index fe0bfe5..e21ef92 100644
--- a/editor/dconf-editor.gresource.xml
+++ b/editor/dconf-editor.gresource.xml
@@ -6,6 +6,7 @@
     <file preprocess="xml-stripblanks">browser-infobar.ui</file>
     <file preprocess="xml-stripblanks">browser-stack.ui</file>
     <file preprocess="xml-stripblanks">browser-view.ui</file>
+    <file preprocess="xml-stripblanks">config-list-box-row.ui</file>
     <file>dconf-editor.css</file>
     <file preprocess="xml-stripblanks">dconf-editor.ui</file>
     <file preprocess="xml-stripblanks">delayed-setting-view.ui</file>
@@ -20,6 +21,7 @@
     <file preprocess="xml-stripblanks">registry-info.ui</file>
     <file preprocess="xml-stripblanks">registry-placeholder.ui</file>
     <file preprocess="xml-stripblanks">registry-view.ui</file>
+    <file preprocess="xml-stripblanks">return-list-box-row.ui</file>
     <file preprocess="xml-stripblanks">search-list-box-row.ui</file>
   </gresource>
   <gresource prefix="/ca/desrt/dconf-editor/gtk">
diff --git a/editor/dconf-model.vala b/editor/dconf-model.vala
index 34dd423..70c25ea 100644
--- a/editor/dconf-model.vala
+++ b/editor/dconf-model.vala
@@ -977,6 +977,14 @@ private class SettingsModel : SettingsModelCore
     * * Directories informations
     \*/
 
+    internal Variant _get_folder_properties (string folder_path)
+    {
+        RegistryVariantDict variantdict = new RegistryVariantDict ();
+
+        variantdict.insert_value (PropertyQuery.KEY_NAME, new Variant.string (ModelUtils.get_name 
(folder_path)));
+        return variantdict.end ();
+    }
+
     internal Variant? get_children (string folder_path, bool watch = false, bool clean_watched = false)
         requires (ModelUtils.is_folder_path (folder_path))
     {
@@ -1119,6 +1127,12 @@ private class SettingsModel : SettingsModelCore
     * * Keys properties
     \*/
 
+    internal Variant get_folder_properties (string folder_path)
+        requires (ModelUtils.is_folder_path (folder_path))
+    {
+        return _get_folder_properties (folder_path);
+    }
+
     internal Variant get_key_properties (string key_path, uint16 key_context_id, uint16 query)
         requires (ModelUtils.is_key_path (key_path))
         requires (!ModelUtils.is_undefined_context_id (key_context_id))
diff --git a/editor/dconf-window.vala b/editor/dconf-window.vala
index ec6240a..643b5af 100644
--- a/editor/dconf-window.vala
+++ b/editor/dconf-window.vala
@@ -29,7 +29,8 @@ internal enum RelocatableSchemasEnabledMappings
 internal enum ViewType {
     OBJECT,
     FOLDER,
-    SEARCH;
+    SEARCH,
+    CONFIG;
 
     internal static uint8 to_byte (ViewType type)
     {
@@ -38,6 +39,7 @@ internal enum ViewType {
             case ViewType.OBJECT: return 0;
             case ViewType.FOLDER: return 1;
             case ViewType.SEARCH: return 2;
+            case ViewType.CONFIG: return 3;
             default: assert_not_reached ();
         }
     }
@@ -49,6 +51,35 @@ internal enum ViewType {
             case 0: return ViewType.OBJECT;
             case 1: return ViewType.FOLDER;
             case 2: return ViewType.SEARCH;
+            case 3: return ViewType.CONFIG;
+            default: assert_not_reached ();
+        }
+    }
+
+    internal static bool displays_objects_list (ViewType type)
+    {
+        switch (type)
+        {
+            case ViewType.OBJECT:
+            case ViewType.CONFIG:
+                return false;
+            case ViewType.FOLDER:
+            case ViewType.SEARCH:
+                return true;
+            default: assert_not_reached ();
+        }
+    }
+
+    internal static bool displays_object_infos (ViewType type)
+    {
+        switch (type)
+        {
+            case ViewType.OBJECT:
+            case ViewType.CONFIG:
+                return true;
+            case ViewType.FOLDER:
+            case ViewType.SEARCH:
+                return false;
             default: assert_not_reached ();
         }
     }
@@ -462,6 +493,7 @@ private class DConfWindow : ApplicationWindow
 
         { "open-folder", open_folder, "s" },
         { "open-object", open_object, "(sq)" },
+        { "open-config", open_config, "s" },
         { "open-search", open_search, "s" },
         { "open-parent", open_parent, "s" },
 
@@ -529,6 +561,16 @@ private class DConfWindow : ApplicationWindow
         request_object (full_name, context_id);
     }
 
+    private void open_config (SimpleAction action, Variant? path_variant)
+        requires (path_variant != null)
+    {
+        path_widget.close_popovers ();
+
+        string full_name = ((!) path_variant).get_string ();    // TODO use current_path instead?
+
+        request_config (full_name);
+    }
+
     private void open_search (SimpleAction action, Variant? search_variant)
         requires (search_variant != null)
     {
@@ -689,6 +731,17 @@ private class DConfWindow : ApplicationWindow
         return path.has_prefix ("/") && path.contains ("//");
     }
 
+    private void request_config (string full_name)
+    {
+        browser_view.prepare_object_view (full_name, ModelUtils.folder_context_id,
+                                          model.get_folder_properties (full_name),
+                                          true);
+        update_current_path (ViewType.CONFIG, strdup (full_name));
+
+        stop_search ();
+        // path_widget.search_mode_enabled = false; // do last to avoid flickering RegistryView before 
PropertiesView when selecting a search result
+    }
+
     private void request_folder (string full_name, string selected_or_empty = "", bool notify_missing = true)
     {
         string fallback_path = model.get_fallback_path (full_name);
@@ -710,17 +763,21 @@ private class DConfWindow : ApplicationWindow
     private static GLib.ListStore create_key_model (string base_path, Variant? children)
     {
         GLib.ListStore key_model = new GLib.ListStore (typeof (SimpleSettingObject));
+
+        string name = ModelUtils.get_name (base_path);
+        SimpleSettingObject sso = new SimpleSettingObject.from_full_name (ModelUtils.folder_context_id, 
name, base_path, false, true);
+        key_model.append (sso);
+
         if (children != null)
         {
             VariantIter iter = new VariantIter ((!) children);
             uint16 context_id;
-            string name;
             while (iter.next ("(qs)", out context_id, out name))
             {
                 if (ModelUtils.is_undefined_context_id (context_id))
                     assert_not_reached ();
-                SimpleSettingObject sso = new SimpleSettingObject.from_base_path (context_id, name, 
base_path);
-                ((!) key_model).append (sso);
+                sso = new SimpleSettingObject.from_base_path (context_id, name, base_path);
+                key_model.append (sso);
             }
         }
         return key_model;
@@ -767,7 +824,8 @@ private class DConfWindow : ApplicationWindow
             path_widget.prepare_search (mode, search);
         string search_text = search == null ? path_widget.text : (!) search;
         update_current_path (ViewType.SEARCH, search_text);
-        browser_view.select_row (selected_row);
+        if (mode != PathEntry.SearchMode.UNCLEAR)
+            browser_view.select_row (selected_row);
         if (!path_widget.entry_has_focus)
             path_widget.entry_grab_focus_without_selecting ();
     }
@@ -788,7 +846,7 @@ private class DConfWindow : ApplicationWindow
 
     private void update_current_path (ViewType type, string path)
     {
-        if (type != ViewType.SEARCH)
+        if (type == ViewType.OBJECT || type == ViewType.FOLDER)
         {
             saved_type = type;
             saved_view = path;
@@ -812,7 +870,7 @@ private class DConfWindow : ApplicationWindow
 
         GLib.Menu menu = new GLib.Menu ();
 
-        if (current_type == ViewType.OBJECT)   // TODO a better way to copy various representations of a key 
name/value/path
+        if (current_type == ViewType.OBJECT && !ModelUtils.is_folder_path (current_path))   // TODO a better 
way to copy various representations of a key name/value/path
         {
             Variant variant = new Variant.string (model.get_suggested_key_copy_text (current_path, 
browser_view.last_context_id));
             menu.append (_("Copy descriptor"), "app.copy(" + variant.print (false) + ")");
@@ -979,25 +1037,22 @@ private class DConfWindow : ApplicationWindow
                     return true;
 
                 case "g":   // usual shortcut for "next-match" in a SearchEntry; see also "Down"
-                    if (!path_widget.is_bookmarks_button_active
+                    if (!path_widget.has_popover ()
                      && info_button.active == false
                      && !revealer.get_modifications_list_state ())
                         return browser_view.down_pressed ();
                     return false;
                 case "G":   // usual shortcut for "previous-match" in a SearchEntry; see also "Up"
-                    if (!path_widget.is_bookmarks_button_active
+                    if (!path_widget.has_popover ()
                      && info_button.active == false
                      && !revealer.get_modifications_list_state ())
                         return browser_view.up_pressed ();
                     return false;
 
-                case "i":
-                    if (revealer.reveal_child)
-                    {
-                        revealer.toggle_modifications_list ();
-                        return true;
-                    }
-                    return false;
+                case "i": 
+                    if (browser_view.current_view == ViewType.FOLDER)
+                        request_config (current_path);
+                    return true;
 
                 case "l":
                     if (path_widget.search_mode_enabled)
@@ -1019,7 +1074,7 @@ private class DConfWindow : ApplicationWindow
 
                 case "Return":
                 case "KP_Enter":
-                    if (info_button.active || path_widget.is_bookmarks_button_active)
+                    if (info_button.active || path_widget.has_popover ())
                         return false;
                     browser_view.discard_row_popover ();
                     browser_view.toggle_boolean_key ();
@@ -1031,7 +1086,7 @@ private class DConfWindow : ApplicationWindow
                 case "decimalpoint":
                 case "period":
                 case "KP_Decimal":
-                    if (info_button.active || path_widget.is_bookmarks_button_active)
+                    if (info_button.active || path_widget.has_popover ())
                         return false;
                     if (revealer.dismiss_selected_modification ())
                     {
@@ -1053,9 +1108,22 @@ private class DConfWindow : ApplicationWindow
 
         if ((event.state & Gdk.ModifierType.MOD1_MASK) != 0)
         {
+            if (name == "i")
+            {
+                if (revealer.reveal_child)
+                {
+                    revealer.toggle_modifications_list ();
+                    return true;
+                }
+                return false;
+            }
             if (name == "Up")
             {
-                go_backward ((event.state & Gdk.ModifierType.SHIFT_MASK) != 0);
+                bool shift = (event.state & Gdk.ModifierType.SHIFT_MASK) != 0;
+                if (!shift && browser_view.current_view == ViewType.CONFIG)
+                    request_folder (current_path);
+                else
+                    go_backward (shift);
                 return true;
             }
             if (name == "Down")
@@ -1068,18 +1136,28 @@ private class DConfWindow : ApplicationWindow
         /* don't use "else if", or some widgets will not be hidden on <ctrl>F10 or such things */
         if (name == "F10")
         {
+            if ((event.state & Gdk.ModifierType.SHIFT_MASK) != 0)
+            {
+                if (!focus_is_text_widget) // && browser_view.current_view != ViewType.SEARCH
+                {
+                    path_widget.toggle_pathbar_menu ();
+                    return true;
+                }
+                return false;
+            }
+
             browser_view.discard_row_popover ();
             path_widget.close_popovers ();
             return false;
         }
 
         if (name == "Up"    // see also <ctrl>G
-         && !path_widget.is_bookmarks_button_active
+         && !path_widget.has_popover ()
          && info_button.active == false
          && !revealer.get_modifications_list_state ())
             return browser_view.up_pressed ();
         if (name == "Down"  // see also <ctrl>g
-         && !path_widget.is_bookmarks_button_active
+         && !path_widget.has_popover ()
          && info_button.active == false
          && !revealer.get_modifications_list_state ())
             return browser_view.down_pressed ();
@@ -1100,6 +1178,11 @@ private class DConfWindow : ApplicationWindow
                 stop_search ();
                 return true;
             }
+            if (current_type == ViewType.CONFIG)
+            {
+                request_folder (current_path);
+                return true;
+            }
             return false;
         }
 
@@ -1124,7 +1207,7 @@ private class DConfWindow : ApplicationWindow
             return true;
         }
 
-        if (path_widget.is_bookmarks_button_active || info_button.active)
+        if (path_widget.has_popover () || info_button.active)
             return false;
 
         if (!path_widget.search_mode_enabled &&
diff --git a/editor/help-overlay.ui b/editor/help-overlay.ui
index f0e8476..09d48e2 100644
--- a/editor/help-overlay.ui
+++ b/editor/help-overlay.ui
@@ -37,51 +37,52 @@
                 <property name="accelerator">F10</property>
               </object>
             </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="visible">True</property>
+                <property name="title" translatable="yes" context="shortcut window">Path bar menu</property>
+                <property name="accelerator">&lt;Shift&gt;F10</property>
+              </object>
+            </child>
           </object>
         </child>
         <child>
           <object class="GtkShortcutsGroup">
             <property name="visible">True</property>
-            <property name="title" translatable="yes" context="shortcut window">Clipboard</property>
+            <property name="title" translatable="yes" context="shortcut window">Search options</property>
             <child>
               <object class="GtkShortcutsShortcut">
                 <property name="visible">True</property>
-                <property name="title" translatable="yes" context="shortcut window">Copy 
descriptor</property>
-                <property name="accelerator">&lt;Primary&gt;c</property>
+                <property name="title" translatable="yes" context="shortcut window">Toggle search</property>
+                <property name="accelerator">&lt;Primary&gt;f</property>
               </object>
             </child>
             <child>
               <object class="GtkShortcutsShortcut">
                 <property name="visible">True</property>
-                <property name="title" translatable="yes" context="shortcut window">Copy path</property>
-                <property name="accelerator">&lt;Primary&gt;&lt;Shift&gt;c</property>
+                <property name="title" translatable="yes" context="shortcut window">Edit path</property>
+                <property name="accelerator">&lt;Primary&gt;l</property>
               </object>
             </child>
-          </object>
-        </child>
-        <child>
-          <object class="GtkShortcutsGroup">
-            <property name="visible">True</property>
-            <property name="title" translatable="yes" context="shortcut window">Modifications list 
actions</property>
             <child>
               <object class="GtkShortcutsShortcut">
                 <property name="visible">True</property>
-                <property name="title" translatable="yes" context="shortcut window">Toggle modifications 
list</property>
-                <property name="accelerator">&lt;Primary&gt;i</property>
+                <property name="title" translatable="yes" context="shortcut window">Edit parent 
path</property>
+                <property name="accelerator">&lt;Primary&gt;&lt;Shift&gt;l</property>
               </object>
             </child>
             <child>
               <object class="GtkShortcutsShortcut">
                 <property name="visible">True</property>
-                <property name="title" translatable="yes" context="shortcut window">Open selected row 
key</property>
-                <property name="accelerator">Return</property>
+                <property name="title" translatable="yes" context="shortcut window">Edit root path</property>
+                <property name="accelerator">slash</property>
               </object>
             </child>
             <child>
               <object class="GtkShortcutsShortcut">
                 <property name="visible">True</property>
-                <property name="title" translatable="yes" context="shortcut window">Dismiss 
modification</property>
-                <property name="accelerator">&lt;Primary&gt;Delete</property>
+                <property name="title" translatable="yes" context="shortcut window">Browse keys 
tree</property>
+                <property name="accelerator">Escape</property>
               </object>
             </child>
           </object>
@@ -131,6 +132,27 @@
                 <property name="accelerator">Menu</property>
               </object>
             </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="visible">True</property>
+                <property name="title" translatable="yes" context="shortcut window">Previous line</property>
+                <property name="accelerator">&lt;Primary&gt;&lt;Shift&gt;g</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="visible">True</property>
+                <property name="title" translatable="yes" context="shortcut window">Next line</property>
+                <property name="accelerator">&lt;Primary&gt;g</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="visible">True</property>
+                <property name="title" translatable="yes" context="shortcut window">Show folder 
informations</property>
+                <property name="accelerator">&lt;Primary&gt;i</property>
+              </object>
+            </child>
             <child>
               <object class="GtkShortcutsShortcut">
                 <property name="visible">True</property>
@@ -170,33 +192,46 @@
         <child>
           <object class="GtkShortcutsGroup">
             <property name="visible">True</property>
-            <property name="title" translatable="yes" context="shortcut window">Search options</property>
+            <property name="title" translatable="yes" context="shortcut window">Clipboard</property>
             <child>
               <object class="GtkShortcutsShortcut">
                 <property name="visible">True</property>
-                <property name="title" translatable="yes" context="shortcut window">Toggle search</property>
-                <property name="accelerator">&lt;Primary&gt;f</property>
+                <property name="title" translatable="yes" context="shortcut window">Copy 
descriptor</property>
+                <property name="accelerator">&lt;Primary&gt;c</property>
               </object>
             </child>
             <child>
               <object class="GtkShortcutsShortcut">
                 <property name="visible">True</property>
-                <property name="title" translatable="yes" context="shortcut window">Edit path</property>
-                <property name="accelerator">&lt;Primary&gt;l</property>
+                <property name="title" translatable="yes" context="shortcut window">Copy path</property>
+                <property name="accelerator">&lt;Primary&gt;&lt;Shift&gt;c</property>
+              </object>
+            </child>
+          </object>
+        </child>
+        <child>
+          <object class="GtkShortcutsGroup">
+            <property name="visible">True</property>
+            <property name="title" translatable="yes" context="shortcut window">Modifications list 
actions</property>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="visible">True</property>
+                <property name="title" translatable="yes" context="shortcut window">Toggle modifications 
list</property>
+                <property name="accelerator">&lt;Alt&gt;i</property>
               </object>
             </child>
             <child>
               <object class="GtkShortcutsShortcut">
                 <property name="visible">True</property>
-                <property name="title" translatable="yes" context="shortcut window">Edit parent 
path</property>
-                <property name="accelerator">&lt;Primary&gt;&lt;Shift&gt;l</property>
+                <property name="title" translatable="yes" context="shortcut window">Open selected row 
key</property>
+                <property name="accelerator">Return</property>
               </object>
             </child>
             <child>
               <object class="GtkShortcutsShortcut">
                 <property name="visible">True</property>
-                <property name="title" translatable="yes" context="shortcut window">Browse keys 
tree</property>
-                <property name="accelerator">Escape</property>
+                <property name="title" translatable="yes" context="shortcut window">Dismiss 
modification</property>
+                <property name="accelerator">&lt;Primary&gt;Delete</property>
               </object>
             </child>
           </object>
diff --git a/editor/key-list-box-row.vala b/editor/key-list-box-row.vala
index 2c7dd84..7d334e3 100644
--- a/editor/key-list-box-row.vala
+++ b/editor/key-list-box-row.vala
@@ -47,12 +47,7 @@ private class ListBoxRowHeader : Grid
 
     internal ListBoxRowHeader (bool is_first_row, string? header_text)
     {
-        if (header_text == null)
-        {
-            if (is_first_row)
-                return;
-        }
-        else
+        if (header_text != null)
         {
             orientation = Orientation.VERTICAL;
 
@@ -67,6 +62,9 @@ private class ListBoxRowHeader : Grid
 
         halign = Align.CENTER;
 
+        if (is_first_row)
+            return;
+
         Separator separator = new Separator (Orientation.HORIZONTAL);
         separator.visible = true;
         separator.hexpand = true;
@@ -126,6 +124,18 @@ private abstract class ClickableListBoxRow : EventBox
     }
 }
 
+[GtkTemplate (ui = "/ca/desrt/dconf-editor/ui/return-list-box-row.ui")]
+private class ReturnListBoxRow : ClickableListBoxRow
+{
+    [GtkChild] private Label folder_name_label;
+
+    internal ReturnListBoxRow (string _full_name, uint16 _context_id)
+    {
+        Object (full_name: _full_name, context_id: _context_id, search_result_mode: true);
+        folder_name_label.set_text (_("Go to ā€œ%sā€").printf (_full_name));
+    }
+}
+
 [GtkTemplate (ui = "/ca/desrt/dconf-editor/ui/folder-list-box-row.ui")]
 private class FolderListBoxRow : ClickableListBoxRow
 {
@@ -138,6 +148,18 @@ private class FolderListBoxRow : ClickableListBoxRow
     }
 }
 
+[GtkTemplate (ui = "/ca/desrt/dconf-editor/ui/config-list-box-row.ui")]
+private class ConfigListBoxRow : ClickableListBoxRow
+{
+    [GtkChild] private Label folder_name_label;
+
+    internal ConfigListBoxRow (string name, string path)
+    {
+        Object (full_name: path, context_id: ModelUtils.folder_context_id, search_result_mode: false);
+        folder_name_label.set_text (_("Show informations about folder ā€œ%sā€").printf (name));
+    }
+}
+
 [GtkTemplate (ui = "/ca/desrt/dconf-editor/ui/search-list-box-row.ui")]
 private class SearchListBoxRow : ClickableListBoxRow
 {
@@ -404,11 +426,17 @@ private class ContextPopover : Popover
             /* Translators: "erase key" action in the right-click menu on a key without schema */
             case "erase":           action_text = _("Erase key");           break;
 
+            /* Translators: "go to" action in the right-click menu on a "go back" line during search */
+            case "go-back":         action_text = _("Go to this path");     break;
+
             /* Translators: "open folder" action in the right-click menu on a folder */
             case "open-folder":     action_text = _("Open");                break;
 
+            /* Translators: "open" action in the right-click menu on a "show folder info" row */
+            case "open-config":     action_text = _("Show informations");   break;
+
             /* Translators: "open search" action in the right-click menu on a search */
-            case "open-search":     action_text = _("Search");                break;
+            case "open-search":     action_text = _("Search");              break;
 
             /* Translators: "open parent folder" action in the right-click menu on a folder in a search 
result */
             case "open-parent":     action_text = _("Open parent folder");  break;
diff --git a/editor/meson.build b/editor/meson.build
index 35e23b8..2a8a404 100644
--- a/editor/meson.build
+++ b/editor/meson.build
@@ -98,6 +98,7 @@ resource_data = files(
   'browser-infobar.ui',
   'browser-stack.ui',
   'browser-view.ui',
+  'config-list-box-row.ui',
   'dconf-editor.css',
   'dconf-editor.ui',
   'delayed-setting-view.ui',
@@ -113,6 +114,7 @@ resource_data = files(
   'registry-info.ui',
   'registry-placeholder.ui',
   'registry-view.ui',
+  'return-list-box-row.ui',
   'search-list-box-row.ui'
 )
 
diff --git a/editor/pathbar.vala b/editor/pathbar.vala
index c761e88..f91922f 100644
--- a/editor/pathbar.vala
+++ b/editor/pathbar.vala
@@ -30,17 +30,62 @@ private class PathBar : Box
     }
 
     /*\
-    * * public calls
+    * * keyboard
+    \*/
+
+    internal bool has_popover ()    // TODO urg
+    {
+        bool return_value = false;
+        @foreach ((child) => {
+                if (child is PathBarItem)
+                {
+                    PathBarItem item = (PathBarItem) child;
+                    if (item.is_active && item.has_popover ())
+                        return_value = true;
+                }
+            });
+        return return_value;
+    }
+
+    internal void close_menu ()     // TODO urg
+    {
+        @foreach ((child) => {
+                if (child is PathBarItem)
+                {
+                    PathBarItem item = (PathBarItem) child;
+                    if (item.is_active)
+                        item.close_menu ();
+                }
+            });
+    }
+
+    internal void toggle_menu ()    // TODO urg
+    {
+        @foreach ((child) => {
+                if (child is PathBarItem)
+                {
+                    PathBarItem item = (PathBarItem) child;
+                    if (item.is_active)
+                        item.toggle_menu ();
+                }
+            });
+    }
+
+    /*\
+    * * main public calls
     \*/
 
     internal void set_path (ViewType type, string path)
     {
         if (type == ViewType.SEARCH)
-        {
-            update_cursors_for_search (path, true);
             return;
-        }
-        update_cursors_for_search (path, false);
+
+        update_cursors (type, path);
+
+        if (type == ViewType.CONFIG)
+            get_style_context ().add_class ("config");
+        else
+            get_style_context ().remove_class ("config");
 
         activate_item (root_button, path == "/");
 
@@ -73,7 +118,7 @@ private class PathBar : Box
                 {
                     complete_path += split [0];
                     split = split [1:split.length];
-                    if (split.length == 0 || (split.length == 1 && type == ViewType.FOLDER))
+                    if (split.length == 0 || (split.length == 1 && (type == ViewType.FOLDER || type == 
ViewType.CONFIG)))
                     {
                         activate_item (item, true);
                         maintain_all = true;
@@ -96,7 +141,7 @@ private class PathBar : Box
                 foreach (string item in split [0:split.length - 1])
                 {
                     complete_path += item + "/";
-                    add_path_bar_item (item, complete_path, true, type == ViewType.FOLDER && (index == 
split.length - 2));
+                    add_path_bar_item (item, complete_path, true, (type == ViewType.FOLDER || type == 
ViewType.CONFIG) && (index == split.length - 2));
                     add_slash_label ();
                     index++;
                 }
@@ -140,7 +185,7 @@ private class PathBar : Box
                         ((!) variant).@get ("(sq)", out action_target, out unused);
                     }
 
-                    if (context.has_class ("active"))
+                    if (item.is_active)
                     {
                         if (is_search)
                         {
@@ -177,16 +222,17 @@ private class PathBar : Box
             });
     }
 
-    private void update_cursors_for_search (string current_path, bool is_search)
+    private void update_cursors (ViewType type, string current_path)
     {
+        bool active_button_has_action = type == ViewType.CONFIG;
+
         @foreach ((child) => {
                 if (!(child is PathBarItem))
                     return;
-                StyleContext context = child.get_style_context ();
-                if (!context.has_class ("active"))
-                    return;
                 PathBarItem item = (PathBarItem) child;
-                if (is_search)
+                if (!item.is_active)
+                    return;
+                if (active_button_has_action)
                 {
                     item.set_cursor_type (PathBarItem.CursorType.POINTER);
                     item.set_detailed_action_name (item.default_action);
@@ -227,22 +273,24 @@ private class PathBar : Box
         activate_item (path_bar_item, block);   // has to be after add()
     }
 
-    private void activate_item (PathBarItem item, bool state)   // never called when current_view is search
+    private static void activate_item (PathBarItem item, bool state)   // never called when current_view is 
search
     {
-        StyleContext context = item.get_style_context ();
-        if (state == context.has_class ("active"))
+        if (state == item.is_active)
             return;
+
         if (state)
         {
+            item.is_active = true;
             item.set_cursor_type (PathBarItem.CursorType.CONTEXT);
             item.set_action_name ("ui.empty");
-            context.add_class ("active");
+            item.get_style_context ().add_class ("active");
         }
         else
         {
+            item.is_active = false;
             item.set_cursor_type (PathBarItem.CursorType.POINTER);
             item.set_detailed_action_name (item.default_action);
-            context.remove_class ("active");
+            item.get_style_context ().remove_class ("active");
         }
     }
 }
@@ -250,10 +298,14 @@ private class PathBar : Box
 [GtkTemplate (ui = "/ca/desrt/dconf-editor/ui/pathbar-item.ui")]
 private class PathBarItem : Button
 {
+    public bool is_active { internal get; internal set; default = false; }
+
     public string alternative_action { internal get; internal construct; }
     public string default_action     { internal get; internal construct; }
     public string text_string        { internal get; internal construct; }
+ 
     [GtkChild] private Label text_label;
+    private Popover? popover = null;
 
     internal enum CursorType {
         DEFAULT,
@@ -297,7 +349,8 @@ private class PathBarItem : Button
     [GtkCallback]
     private void update_cursor ()
     {
-        if (get_style_context ().has_class ("inexistent") && !get_style_context ().has_class ("active"))
+        StyleContext context = get_style_context ();
+        if (context.has_class ("inexistent") && !context.has_class ("active"))  // TODO use is_active when 
sanitized
             return;
 
         if (cursor_type != CursorType.CONTEXT)
@@ -307,12 +360,8 @@ private class PathBarItem : Button
             return;
         }
 
-        GLib.Menu menu = new GLib.Menu ();
-        menu.append (_("Copy current path"), "ui.copy-path"); // or "app.copy(\"" + get_action_target_value 
().get_string () + "\")"
-        menu.freeze ();
-
-        Popover popover_test = new Popover.from_model (this, (MenuModel) menu);
-        popover_test.popup ();
+        generate_popover ();
+        ((!) popover).popup ();
     }
 
     internal PathBarItem (string label, string _default_action, string _alternative_action)
@@ -321,4 +370,35 @@ private class PathBarItem : Button
         text_label.set_text (label);
         set_detailed_action_name (_default_action);
     }
+
+    internal bool has_popover ()
+    {
+        return popover != null && ((!) popover).get_mapped ();
+    }
+
+    internal void close_menu ()
+    {
+        if (has_popover ())
+            ((!) popover).popdown ();
+    }
+
+    internal void toggle_menu ()
+    {
+        if (popover == null)
+            generate_popover ();
+
+        if (((!) popover).get_mapped ())
+            ((!) popover).popdown ();
+        else
+            ((!) popover).popup ();
+    }
+
+    private void generate_popover ()
+    {
+        GLib.Menu menu = new GLib.Menu ();
+        menu.append (_("Copy current path"), "ui.copy-path"); // or "app.copy(\"" + get_action_target_value 
().get_string () + "\")"
+        menu.freeze ();
+
+        popover = new Popover.from_model (this, (MenuModel) menu);
+    }
 }
diff --git a/editor/pathentry.ui b/editor/pathentry.ui
index 2992702..87ca2b6 100644
--- a/editor/pathentry.ui
+++ b/editor/pathentry.ui
@@ -12,8 +12,6 @@
       <object class="GtkSearchEntry" id="search_entry">
         <property name="visible">True</property>
         <property name="hexpand">True</property>
-        <signal name="search-changed" handler="search_changed_cb"/>
-        <signal name="stop-search"    handler="search_stopped_cb"/>
         <!-- "next-match" (<ctrl>g) and "previous-match" (<ctrl>G) are handled in dconf-window.vala -->
       </object>
     </child>
diff --git a/editor/pathentry.vala b/editor/pathentry.vala
index 4fa4c32..263db17 100644
--- a/editor/pathentry.vala
+++ b/editor/pathentry.vala
@@ -35,9 +35,16 @@ private class PathEntry : Box
         SEARCH
     }
 
+    private ulong search_changed_handler = 0;
     internal signal void search_changed ();
     internal signal void search_stopped ();
 
+    construct
+    {
+        search_changed_handler = search_entry.search_changed.connect (() => search_changed ()); 
+        search_entry.stop_search.connect (() => search_stopped ());
+    }
+
     internal void entry_grab_focus_without_selecting ()
     {
         if (search_entry.text_length != 0)
@@ -76,6 +83,13 @@ private class PathEntry : Box
     }
 
     internal void prepare (SearchMode mode, string? search = null)
+        requires (search_changed_handler != 0)
+    {
+        SignalHandler.block (search_entry, search_changed_handler);
+        _prepare (mode, search);
+        SignalHandler.unblock (search_entry, search_changed_handler);
+    }
+    private inline void _prepare (SearchMode mode, string? search)
     {
         switch (mode)
         {
@@ -116,16 +130,4 @@ private class PathEntry : Box
                 assert_not_reached ();
         }
     }
-
-    [GtkCallback]
-    private void search_changed_cb ()
-    {
-        search_changed ();
-    }
-
-    [GtkCallback]
-    private void search_stopped_cb ()
-    {
-        search_stopped ();
-    }
 }
diff --git a/editor/pathwidget.vala b/editor/pathwidget.vala
index 38f2d79..a2410f7 100644
--- a/editor/pathwidget.vala
+++ b/editor/pathwidget.vala
@@ -85,6 +85,22 @@ private class PathWidget : Box
             leave_search_mode ();
     }
 
+    internal void close_popovers ()
+    {
+        if (bookmarks_button.active)
+            bookmarks_button.active = false;
+        pathbar.close_menu ();
+    }
+
+    internal bool has_popover ()
+    {
+        if (bookmarks_button.active)
+            return true;
+        if (pathbar.has_popover ())
+            return true;
+        return false;
+    }
+
     /* path bar */
     internal string complete_path { get { return pathbar.complete_path; }}
 
@@ -98,6 +114,11 @@ private class PathWidget : Box
         return pathbar.get_selected_child (fallback_path);
     }
 
+    internal void toggle_pathbar_menu ()
+    {
+        pathbar.toggle_menu ();
+    }
+
     /* path entry */
     internal string text                   { get { return searchentry.text; }}
     internal bool entry_has_focus          { get { return searchentry.entry_has_focus; }}
@@ -119,8 +140,6 @@ private class PathWidget : Box
     }
 
     /* bookmarks button */
-    internal bool is_bookmarks_button_active    { get { return bookmarks_button.active;     }}
-
     internal string [] get_bookmarks ()
     {
         return bookmarks_button.get_bookmarks ();
@@ -134,12 +153,6 @@ private class PathWidget : Box
     internal void   bookmark_current_path () {   bookmarks_button.bookmark_current_path (); }
     internal void unbookmark_current_path () { bookmarks_button.unbookmark_current_path (); }
 
-    internal void close_popovers ()
-    {
-        if (bookmarks_button.active)
-            bookmarks_button.active = false;
-    }
-
     internal void update_bookmark_icon (string bookmark, bool bookmark_exists, bool bookmark_has_schema = 
false, bool bookmark_is_default = false)
     {
         bookmarks_button.update_bookmark_icon (bookmark, bookmark_exists, bookmark_has_schema, 
bookmark_is_default);
diff --git a/editor/registry-info.vala b/editor/registry-info.vala
index 7de6350..0aa62a8 100644
--- a/editor/registry-info.vala
+++ b/editor/registry-info.vala
@@ -74,6 +74,23 @@ private class RegistryInfo : Grid, BrowsableView
 
         RegistryVariantDict properties = new RegistryVariantDict.from_aqv (current_key_info);
 
+        properties_list_box.@foreach ((widget) => widget.destroy ());
+
+        if (context_id == ModelUtils.folder_context_id)
+        {
+            string folder_name;
+            if (!properties.lookup (PropertyQuery.KEY_NAME,             "s",    out folder_name))
+                assert_not_reached ();
+            add_row_from_label (_("Name"),                                          folder_name);
+
+            conflicting_key_warning_revealer.set_reveal_child (false);
+            hard_conflicting_key_error_revealer.set_reveal_child (false);
+            no_schema_warning.set_reveal_child (false);
+            one_choice_warning_revealer.set_reveal_child (false);
+
+            return;
+        }
+
         if (!properties.lookup (PropertyQuery.HASH,                     "u",    out current_key_info_hash))
             assert_not_reached ();
 
@@ -112,8 +129,6 @@ private class RegistryInfo : Grid, BrowsableView
         }
         no_schema_warning.set_reveal_child (!has_schema);
 
-        properties_list_box.@foreach ((widget) => widget.destroy ());
-
         // TODO g_variant_dict_lookup_value() return value is not annotated as nullable
         string type_code;
         if (!properties.lookup (PropertyQuery.TYPE_CODE,                "s",    out type_code))
diff --git a/editor/registry-list.vala b/editor/registry-list.vala
index a351396..b5b50be 100644
--- a/editor/registry-list.vala
+++ b/editor/registry-list.vala
@@ -187,7 +187,8 @@ private abstract class RegistryList : Grid, BrowsableView
 
         ClickableListBoxRow row = (ClickableListBoxRow) ((!) selected_row).get_child ();
 
-        if (ModelUtils.is_folder_context_id (row.context_id) || ModelUtils.is_undefined_context_id 
(row.context_id))
+        if (ModelUtils.is_folder_context_id (row.context_id)
+         || ModelUtils.is_undefined_context_id (row.context_id))
             return _get_folder_or_search_copy_text (row);
         else
             return _get_key_copy_text (row, modifications_handler);
@@ -298,14 +299,22 @@ private abstract class RegistryList : Grid, BrowsableView
                                          && (search_is_path_search
                                           || ModelUtils.get_parent_path (full_name) != (!) 
current_path_if_search_mode);
 
-        if (setting_object.is_search)
+        if (setting_object.is_config)
         {
-            row = new SearchListBoxRow (full_name.slice (1, full_name.length));
+            row = new ConfigListBoxRow (setting_object.name, full_name);
+        }
+        else if (setting_object.is_pinned)  // setting_object.is_config == false
+        {
+            row = new ReturnListBoxRow (full_name, context_id);
         }
         else if (ModelUtils.is_folder_context_id (context_id))
         {
             row = new FolderListBoxRow (setting_object.name, full_name, search_mode_non_local_result);
         }
+        else if (setting_object.is_search)
+        {
+            row = new SearchListBoxRow (full_name.slice (1, full_name.length));
+        }
         else
         {
             Variant properties = modifications_handler.model.get_key_properties (full_name, context_id, 
(uint16) (PropertyQuery.HAS_SCHEMA & PropertyQuery.KEY_NAME & PropertyQuery.TYPE_CODE & PropertyQuery.SUMMARY 
& PropertyQuery.KEY_CONFLICT));
@@ -406,24 +415,43 @@ private abstract class RegistryList : Grid, BrowsableView
 
         wrapper.set_halign (Align.CENTER);
         wrapper.add (row);
-        if (ModelUtils.is_undefined_context_id (row.context_id))
+        if (row is SearchListBoxRow)
         {
             wrapper.get_style_context ().add_class ("f-or-s-row");
             wrapper.action_name = "ui.open-search";
             wrapper.set_action_target ("s", row.full_name);
         }
+        else if (row is ReturnListBoxRow)
+        {
+            wrapper.get_style_context ().add_class ("f-or-s-row");
+            if (ModelUtils.is_folder_context_id (row.context_id))
+            {
+                wrapper.action_name = "ui.open-folder";
+                wrapper.set_action_target ("s", row.full_name);
+            }
+            else
+            {
+                wrapper.action_name = "ui.open-object";
+                wrapper.set_action_target ("(sq)", row.full_name, row.context_id);
+            }
+        }
         else if (ModelUtils.is_folder_context_id (row.context_id))
         {
             wrapper.get_style_context ().add_class ("f-or-s-row");
-            wrapper.action_name = "ui.open-folder";
+            if (row is FolderListBoxRow)
+                wrapper.action_name = "ui.open-folder";
+            else if (row is ConfigListBoxRow)
+                wrapper.action_name = "ui.open-config";
+            else assert_not_reached ();
             wrapper.set_action_target ("s", row.full_name);
         }
-        else
+        else if (row is KeyListBoxRow)
         {
             wrapper.get_style_context ().add_class ("key-row");
             wrapper.action_name = "ui.open-object";
             wrapper.set_action_target ("(sq)", row.full_name, row.context_id);
         }
+        else assert_not_reached ();
 
         return wrapper;
     }
@@ -605,28 +633,29 @@ private abstract class RegistryList : Grid, BrowsableView
     private static bool generate_popover (ClickableListBoxRow row, ModificationsHandler 
modifications_handler)
         requires (row.nullable_popover != null)
     {
-        switch (row.context_id)
+        if (row is FolderListBoxRow)
+            return generate_folder_popover (row);
+        else if (row is KeyListBoxRow)
         {
-            case ModelUtils.undefined_context_id:   // TODO search_context_id, and assert_not_reached() on 
undefined_context_id
-                return generate_search_popover (row);
-
-            case ModelUtils.folder_context_id:
-                return generate_folder_popover (row);
-
-            case ModelUtils.dconf_context_id:
-                if (modifications_handler.model.is_key_ghost (row.full_name))
-                    return generate_ghost_popover (row, _get_key_copy_text_variant (row, 
modifications_handler));
-                else
-                    return generate_dconf_popover ((KeyListBoxRow) row, modifications_handler, 
_get_key_copy_text_variant (row, modifications_handler));
-
-            default:
+            if (row.context_id != ModelUtils.dconf_context_id)
                 return generate_gsettings_popover ((KeyListBoxRow) row, modifications_handler, 
_get_key_copy_text_variant (row, modifications_handler));
+            else if (modifications_handler.model.is_key_ghost (row.full_name))
+                return generate_ghost_popover (row, _get_key_copy_text_variant (row, modifications_handler));
+            else
+                return generate_dconf_popover ((KeyListBoxRow) row, modifications_handler, 
_get_key_copy_text_variant (row, modifications_handler));
         }
+        else if (row is ConfigListBoxRow)
+            return generate_config_popover (row);
+        else if (row is ReturnListBoxRow)
+            return generate_return_popover (row);
+        else if (row is SearchListBoxRow)
+            return generate_search_popover (row);
+        else assert_not_reached ();
     }
 
     private static bool generate_search_popover (ClickableListBoxRow row)
     {
-        if (row.nullable_popover == null)   // do not place in requires 1/5
+        if (row.nullable_popover == null)   // do not place in requires 1/7
             assert_not_reached ();
 
         ContextPopover popover = (!) row.nullable_popover;
@@ -638,9 +667,43 @@ private abstract class RegistryList : Grid, BrowsableView
         return true;
     }
 
+    private static bool generate_config_popover (ClickableListBoxRow row)
+    {
+        if (row.nullable_popover == null)   // do not place in requires 2/7
+            assert_not_reached ();
+
+        ContextPopover popover = (!) row.nullable_popover;
+        Variant variant = new Variant.string (row.full_name);
+
+        popover.new_gaction ("open-config", "ui.open-config(" + variant.print (false) + ")");
+//        popover.new_gaction ("copy", "app.copy(" + _get_folder_or_search_copy_text_variant (row).print 
(false) + ")");
+
+        return true;
+    }
+
+    private static bool generate_return_popover (ClickableListBoxRow row)
+    {
+        if (row.nullable_popover == null)   // do not place in requires 3/7
+            assert_not_reached ();
+
+        ContextPopover popover = (!) row.nullable_popover;
+        if (row.context_id == ModelUtils.folder_context_id)
+        {
+            Variant variant = new Variant.string (row.full_name);
+            popover.new_gaction ("go-back", "ui.open-folder(" + variant.print (false) + ")");
+        }
+        else
+        {
+            Variant variant_sq = new Variant ("(sq)", row.full_name, row.context_id);
+            popover.new_gaction ("go-back", "ui.open-object(" + variant_sq.print (true) + ")");
+        }
+
+        return true;
+    }
+
     private static bool generate_folder_popover (ClickableListBoxRow row)
     {
-        if (row.nullable_popover == null)   // do not place in requires 2/5
+        if (row.nullable_popover == null)   // do not place in requires 4/7
             assert_not_reached ();
 
         ContextPopover popover = (!) row.nullable_popover;
@@ -663,7 +726,7 @@ private abstract class RegistryList : Grid, BrowsableView
 
     private static bool generate_gsettings_popover (KeyListBoxRow row, ModificationsHandler 
modifications_handler, Variant copy_text_variant)
     {
-        if (row.nullable_popover == null)   // do not place in requires 3/5
+        if (row.nullable_popover == null)   // do not place in requires 5/7
             assert_not_reached ();
 
         SettingsModel model = modifications_handler.model;
@@ -783,7 +846,7 @@ private abstract class RegistryList : Grid, BrowsableView
 
     private static bool generate_ghost_popover (ClickableListBoxRow row, Variant copy_text_variant)
     {
-        if (row.nullable_popover == null)   // do not place in requires 4/5
+        if (row.nullable_popover == null)   // do not place in requires 6/7
             assert_not_reached ();
 
         ContextPopover popover = (!) row.nullable_popover;
@@ -793,7 +856,7 @@ private abstract class RegistryList : Grid, BrowsableView
 
     private static bool generate_dconf_popover (KeyListBoxRow row, ModificationsHandler 
modifications_handler, Variant copy_text_variant)
     {
-        if (row.nullable_popover == null)   // do not place in requires 5/5
+        if (row.nullable_popover == null)   // do not place in requires 7/7
             assert_not_reached ();
 
         SettingsModel model = modifications_handler.model;
diff --git a/editor/registry-search.vala b/editor/registry-search.vala
index bc09a95..9f8c2e9 100644
--- a/editor/registry-search.vala
+++ b/editor/registry-search.vala
@@ -35,7 +35,7 @@ private class RegistrySearch : RegistryList
 
     internal override void select_first_row ()
     {
-        _select_first_row (key_list_box);
+        _select_first_row (key_list_box, (!) old_term);
     }
 
     internal bool return_pressed ()
@@ -62,11 +62,13 @@ private class RegistrySearch : RegistryList
         old_term = null;
     }
 
-    internal void set_search_parameters (string current_path, string [] _bookmarks, SortingOptions 
_sorting_options)
+    uint16 fallback_context_id = ModelUtils.undefined_context_id;
+    internal void set_search_parameters (string current_path, uint16 current_context_id, string [] 
_bookmarks, SortingOptions _sorting_options)
     {
         clean ();
 
         current_path_if_search_mode = current_path;
+        fallback_context_id = current_context_id;
         bookmarks = _bookmarks;
         sorting_options = _sorting_options;
     }
@@ -75,21 +77,48 @@ private class RegistrySearch : RegistryList
     * * Updating
     \*/
 
-    private static void ensure_selection (ListBox? key_list_box)    // technical nullability
+    private static void ensure_selection (ListBox? key_list_box, string full_name)    // technical 
nullability
     {
         if (key_list_box == null)   // suppresses some warnings if the window is closed while the search is 
processing
             return;                 // TODO see if 5596feae9b51563a33f1bffc6a370e6ba556adb7 fixed that in 
Gtk 4
 
         ListBoxRow? selected_row = ((!) key_list_box).get_selected_row ();
         if (selected_row == null)
-            _select_first_row ((!) key_list_box);
+            _select_first_row ((!) key_list_box, full_name);
     }
 
-    private static void _select_first_row (ListBox key_list_box)
+    private static void _select_first_row (ListBox key_list_box, string term)
     {
-        ListBoxRow? row = key_list_box.get_row_at_index (0);
-        if (row != null)
-            key_list_box.select_row ((!) row);
+        ListBoxRow? row;
+        if (term.has_prefix ("/"))
+        {
+            row = key_list_box.get_row_at_index (0);
+            if (row == null)
+                assert_not_reached ();
+
+            ClickableListBoxRow? row_child = (ClickableListBoxRow?) ((!) row).get_child ();
+            if (row_child != null)
+            {
+                if (((!) row_child).full_name != term)
+                {
+                    ListBoxRow? second_row = key_list_box.get_row_at_index (1);
+                    if (second_row != null)
+                        row = second_row;
+                }
+            }
+        }
+        else
+        {
+            row = key_list_box.get_row_at_index (1);
+            if (row == null)
+            {
+                row = key_list_box.get_row_at_index (0);
+                if (row == null)
+                    assert_not_reached ();
+            }
+        }
+
+        key_list_box.select_row ((!) row);
         key_list_box.get_adjustment ().set_value (0);
     }
 
@@ -152,7 +181,7 @@ private class RegistrySearch : RegistryList
         if ((old_term != null && term == (!) old_term)
          || DConfWindow.is_path_invalid (term))
         {
-            ensure_selection (key_list_box);
+            ensure_selection (key_list_box, (!) old_term);
             return;
         }
 
@@ -172,7 +201,7 @@ private class RegistrySearch : RegistryList
                 resume_global_search ((!) current_path_if_search_mode, term); // update search term
             }
 
-            ensure_selection (key_list_box);
+            ensure_selection (key_list_box, term);
 
             model.keys_value_push ();
         }
@@ -182,12 +211,23 @@ private class RegistrySearch : RegistryList
 
             stop_global_search ();
 
+            search_is_path_search = term.has_prefix ("/");
+            if (search_is_path_search)
+                current_path_if_search_mode = ModelUtils.get_base_path (term);
+
+            uint16 _fallback_context_id = ModelUtils.is_folder_path ((!) current_path_if_search_mode) ? 
ModelUtils.folder_context_id : fallback_context_id;
+            string name = ModelUtils.get_name ((!) current_path_if_search_mode);
+            SimpleSettingObject sso = new SimpleSettingObject.from_full_name (_fallback_context_id,
+                                                                              name,
+                                                                              (!) 
current_path_if_search_mode,
+                                                                              true, true);
+            list_model.insert (0, sso);
+
             local_search (model, sorting_options, ModelUtils.get_base_path ((!) 
current_path_if_search_mode), term, ref list_model);
 
             post_local = (int) list_model.get_n_items ();
             post_paths = post_local;
 
-            search_is_path_search = term.has_prefix ("/");
             if (search_is_path_search)
                 paths_search (model, term, ref list_model, ref post_paths);
             post_bookmarks = post_paths;
@@ -197,7 +237,7 @@ private class RegistrySearch : RegistryList
 
             key_list_box.bind_model (list_model, new_list_box_row);
 
-            _select_first_row (key_list_box);
+            _select_first_row (key_list_box, term);
 
             model.keys_value_push ();
 
@@ -209,12 +249,12 @@ private class RegistrySearch : RegistryList
 
     private static void refine_local_results (string term, ref GLib.ListStore list_model, ref int 
post_local, ref int post_paths, ref int post_bookmarks, ref int post_folders)
     {
-        if (post_local < 0)
+        if (post_local < 1)
             assert_not_reached ();
-        if (post_local == 0)
+        if (post_local == 1)
             return;
 
-        for (int i = post_local - 1; i >= 0; i--)
+        for (int i = post_local - 1; i >= 1; i--)
         {
             SimpleSettingObject? item = (SimpleSettingObject?) list_model.get_item (i);
             if (item == null)
@@ -319,26 +359,15 @@ private class RegistrySearch : RegistryList
 
     private static void paths_search (SettingsModel model, string term, ref GLib.ListStore list_model, ref 
int post_paths)
     {
-        uint16 context_id;
-        string name;
-
-        string base_path;
-        if (ModelUtils.is_key_path (term))
-            base_path = ModelUtils.get_parent_path (term);
-        else if (model.get_object (term, out context_id, out name, false))   // TODO model.get_folder
-        {
-            SimpleSettingObject sso = new SimpleSettingObject.from_full_name (context_id, name, term);
-            list_model.insert (post_paths, sso);
-            post_paths++;
-            base_path = term;
-        }
-        else    // strange construction because else something wrong happens
-            base_path = ModelUtils.get_parent_path (term);
+        string base_path = ModelUtils.get_base_path (term);
 
         Variant? key_model = model.get_children (base_path, true, false);
         if (key_model == null)
             return;
 
+        uint16 context_id;
+        string name;
+
         int post_subfolders = post_paths;
         VariantIter iter = new VariantIter ((!) key_model);
         while (iter.next ("(qs)", out context_id, out name))
@@ -468,7 +497,7 @@ private class RegistrySearch : RegistryList
             }
         }
 
-        ensure_selection (key_list_box);
+        ensure_selection (key_list_box, term);
     }
 
     private void update_row_header (ListBoxRow row, ListBoxRow? before)
@@ -479,7 +508,9 @@ private class RegistrySearch : RegistryList
     }
     private static string? get_header_text (int row_index, int post_local, int post_paths, int 
post_bookmarks, int post_folders)
     {
-        if (row_index == 0 && post_local > 0)
+        if (row_index == 0)
+            return null;
+        if (row_index == 1 && post_local > 1)
             return _("Current folder");
         if (row_index == post_local && post_local != post_paths)
             return _("Paths");
diff --git a/editor/registry-view.vala b/editor/registry-view.vala
index f69aee9..5c29e14 100644
--- a/editor/registry-view.vala
+++ b/editor/registry-view.vala
@@ -106,17 +106,25 @@ private class RegistryView : RegistryList
     private static void _update_row_header (ListBoxRow row, ListBoxRow? before, SettingsModel model)
     {
         string? label_text = null;
-        if (row.get_child () is KeyListBoxRow)  // no header for folders
+        ClickableListBoxRow? row_content = (ClickableListBoxRow) row.get_child ();
+        if (row_content == null)
+            assert_not_reached ();
+
+        if ((!) row_content is KeyListBoxRow)
         {
-            uint16 context_id = ((ClickableListBoxRow) row.get_child ()).context_id;
-            if (before == null || ((ClickableListBoxRow) ((!) before).get_child ()).context_id != context_id)
+            if (before == null)
+                return; // TODO assert_not_reached (); 1/2
+
+            KeyListBoxRow key_list_box_row = (KeyListBoxRow) (!) row_content;
+            uint16 context_id = key_list_box_row.context_id;
+            if (((ClickableListBoxRow) ((!) before).get_child ()).context_id != context_id)
             {
-                if (((KeyListBoxRow) row.get_child ()).has_schema)
+                if (key_list_box_row.has_schema)
                 {
                     if (!model.key_exists (((KeyListBoxRow) ((!) row).get_child ()).full_name, context_id))
                         return; // FIXME that happens when reloading a now-empty folder
 
-                    RegistryVariantDict properties = new RegistryVariantDict.from_aqv 
(model.get_key_properties (((KeyListBoxRow) row.get_child ()).full_name, context_id, (uint16) 
PropertyQuery.SCHEMA_ID));
+                    RegistryVariantDict properties = new RegistryVariantDict.from_aqv 
(model.get_key_properties (key_list_box_row.full_name, context_id, (uint16) PropertyQuery.SCHEMA_ID));
                     string schema_id;
                     if (!properties.lookup (PropertyQuery.SCHEMA_ID, "s", out schema_id))
                         assert_not_reached ();
@@ -126,6 +134,19 @@ private class RegistryView : RegistryList
                     label_text = _("Keys not defined by a schema");
             }
         }
+        else if ((!) row_content is FolderListBoxRow)
+        {
+            if (before == null)
+                return; // TODO assert_not_reached (); 2/2
+
+            ClickableListBoxRow? before_content = (ClickableListBoxRow?) ((!) before).get_child ();
+            if (before_content == null)
+                assert_not_reached ();
+            if ((!) before_content is ConfigListBoxRow)
+                label_text = _("Subfolders");
+        }
+        else if (!((!) row_content is ConfigListBoxRow))
+            assert_not_reached ();
 
         ListBoxRowHeader header = new ListBoxRowHeader (before == null, label_text);
         row.set_header (header);
diff --git a/editor/return-list-box-row.ui b/editor/return-list-box-row.ui
new file mode 100644
index 0000000..8365208
--- /dev/null
+++ b/editor/return-list-box-row.ui
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <!-- interface-requires gtk+ 3.0 -->
+  <template class="ReturnListBoxRow" parent="ClickableListBoxRow">
+    <property name="visible">True</property>
+    <style>
+      <class name="managed"/>
+      <class name="return"/>
+      <class name="small"/>
+    </style>
+    <child>
+      <object class="GtkGrid">
+        <property name="visible">True</property>
+        <property name="orientation">horizontal</property>
+        <child>
+          <object class="GtkLabel" id="folder_name_label">
+            <property name="visible">True</property>
+            <property name="vexpand">True</property>
+            <property name="xalign">0</property>
+            <property name="ellipsize">end</property> <!-- Epiphany web apps during search... -->
+            <style>
+              <class name="key-name"/>
+              <class name="italic-label"/>
+            </style>
+          </object>
+        </child>
+      </object>
+    </child>
+  </template>
+</interface>


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