[dconf-editor] Split window-related code in its own files.



commit 4d701bfac7feb763231e66ce08c315e511eca0f2
Author: Arnaud Bonatti <arnaud bonatti gmail com>
Date:   Sun Jun 19 02:47:19 2016 +0200

    Split window-related code in its own files.

 editor/Makefile.am                |    6 +-
 editor/dconf-editor.gresource.xml |    1 +
 editor/dconf-editor.ui            |  113 +---------
 editor/dconf-window.vala          |  479 +++---------------------------------
 editor/registry-view.ui           |  115 +++++++++
 editor/registry-view.vala         |  495 +++++++++++++++++++++++++++++++++++++
 po/POTFILES.in                    |    2 +
 po/POTFILES.skip                  |    1 +
 8 files changed, 652 insertions(+), 560 deletions(-)
---
diff --git a/editor/Makefile.am b/editor/Makefile.am
index 9755ef4..f59d2d7 100644
--- a/editor/Makefile.am
+++ b/editor/Makefile.am
@@ -33,7 +33,8 @@ resource_data = \
        modifications-revealer.ui \
        pathbar.ui \
        pathbar-item.ui \
-       property-row.ui
+       property-row.ui \
+       registry-view.ui
 
 resources.c: $(resource_data)
        $(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) --sourcedir=$(srcdir) --target=$@ --generate-source $<
@@ -49,7 +50,8 @@ dconf_editor_SOURCES = \
        bookmarks.vala \
        key-list-box-row.vala \
        modifications-revealer.vala \
-       pathbar.vala
+       pathbar.vala \
+       registry-view.vala
 
 desktopdir = $(datadir)/applications
 desktop_in_files = ca.desrt.dconf-editor.desktop.in.in
diff --git a/editor/dconf-editor.gresource.xml b/editor/dconf-editor.gresource.xml
index 4ccad1a..3ffabbb 100644
--- a/editor/dconf-editor.gresource.xml
+++ b/editor/dconf-editor.gresource.xml
@@ -12,6 +12,7 @@
     <file preprocess="xml-stripblanks">pathbar.ui</file>
     <file preprocess="xml-stripblanks">pathbar-item.ui</file>
     <file preprocess="xml-stripblanks">property-row.ui</file>
+    <file preprocess="xml-stripblanks">registry-view.ui</file>
   </gresource>
   <gresource prefix="/ca/desrt/dconf-editor/gtk">
     <file preprocess="xml-stripblanks" alias="menus.ui">dconf-editor-menu.ui</file>
diff --git a/editor/dconf-editor.ui b/editor/dconf-editor.ui
index 54b595a..001996f 100644
--- a/editor/dconf-editor.ui
+++ b/editor/dconf-editor.ui
@@ -64,7 +64,7 @@
             <property name="visible">True</property>
             <property name="valign">center</property>
             <!-- TODO <property name="focus-on-click">False</property> does not work here because of 
explicit focus grab -->
-            <property name="active" bind-source="search_bar" bind-property="search-mode-enabled" 
bind-flags="bidirectional|sync-create"/>
+            <property name="active" bind-source="registry_view" bind-property="show-search-bar" 
bind-flags="bidirectional|sync-create"/>
             <!-- <accelerator key="F" signal="toggled" modifiers="GDK_CONTROL_MASK"/> TODO -->
             <style>
               <class name="image-button"/>
@@ -107,117 +107,8 @@
       </object>
     </child>
     <child>
-      <object class="GtkGrid">
+      <object class="RegistryView" id="registry_view">
         <property name="visible">True</property>
-        <property name="orientation">vertical</property>
-        <child>
-          <object class="GtkSearchBar" id="search_bar">
-            <property name="visible">True</property>
-            <property name="search-mode-enabled">False</property>
-            <property name="show-close-button">False</property>
-            <child>
-              <object class="GtkGrid">
-                <property name="visible">True</property>
-                <property name="orientation">horizontal</property>
-                <style>
-                  <class name="linked"/>
-                </style>
-                <child>
-                  <object class="GtkSearchEntry" id="search_entry">
-                    <property name="visible">True</property>
-                    <property name="width-request">350</property>
-                    <signal name="activate" handler="find_next_cb"/>
-                  </object>
-                </child>
-                <child>
-                  <object class="GtkButton" id="search_next_button">
-                    <property name="visible">True</property>
-                    <signal name="clicked" handler="find_next_cb"/>
-                    <property name="sensitive" bind-source="search_button" bind-property="active"/>
-                    <child>
-                      <object class="GtkImage">
-                        <property name="visible">True</property>
-                        <property name="icon-size">1</property>
-                        <property name="icon-name">go-down-symbolic</property>
-                      </object>
-                    </child>
-                  </object>
-                </child>
-              </object>
-            </child>
-          </object>
-        </child>
-        <child>
-          <object class="GtkStack">
-            <property name="visible">True</property>
-            <property name="visible-child">browse-view</property>
-            <property name="expand">True</property>
-            <child>
-              <object class="GtkTreeView" id="dir_tree_view">
-                <property name="visible">False</property>
-                <child internal-child="selection">
-                  <object class="GtkTreeSelection" id="dir_tree_selection">
-                    <signal name="changed" handler="dir_selected_cb"/>
-                  </object>
-                </child>
-              </object>
-            </child>
-            <child>
-              <object class="GtkScrolledWindow" id="browse-view">
-                <property name="visible">True</property>
-                <child>
-                  <object class="GtkListBox" id="key_list_box">
-                    <property name="visible">True</property>
-                    <property name="activate-on-single-click">True</property>
-                    <property name="selection-mode">browse</property><!-- permits to not have an item 
selected -->
-                    <style>
-                      <class name="dconf-list"/>
-                    </style>
-                    <signal name="row-activated" handler="row_activated_cb"/>
-                    <child type="placeholder">      <!-- see 
nautilus/src/resources/ui/nautilus-folder-is-empty.ui -->
-                      <object class="GtkGrid">
-                        <property name="visible">True</property>
-                        <property name="row-spacing">12</property>
-                        <property name="expand">True</property>
-                        <property name="halign">center</property>
-                        <property name="valign">center</property>
-                        <property name="orientation">vertical</property>
-                        <style>
-                          <class name="dim-label"/>
-                        </style>
-                        <child>
-                          <object class="GtkImage">
-                            <property name="visible">True</property>
-                            <property name="icon-name">dconf-editor-symbolic</property>
-                            <property name="pixel-size">72</property>
-                            <style>
-                              <class name="dim-label"/>
-                            </style>
-                          </object>
-                        </child>
-                        <child>
-                          <object class="GtkLabel">
-                            <property name="visible">True</property>
-                            <property name="label" translatable="yes">No keys in this path</property>
-                            <attributes>
-                              <attribute name="weight" value="bold"/>
-                              <attribute name="scale" value="1.44"/>
-                            </attributes>
-                          </object>
-                        </child>
-                      </object>
-                    </child>
-                  </object>
-                </child>
-              </object>
-            </child>
-          </object>
-        </child>
-        <child>
-          <object class="ModificationsRevealer" id="revealer">
-            <property name="visible">True</property>
-          </object>
-        </child>
       </object>
     </child>
   </template>
diff --git a/editor/dconf-window.vala b/editor/dconf-window.vala
index d777531..2f4979b 100644
--- a/editor/dconf-window.vala
+++ b/editor/dconf-window.vala
@@ -26,34 +26,20 @@ class DConfWindow : ApplicationWindow
         { "reset-visible", reset }
     };
 
-    private string current_path = "/";
+    public string current_path { private get; set; default = "/"; } // not synced bidi, needed for saving on 
destroy, even after child destruction
+
     private int window_width = 0;
     private int window_height = 0;
     private bool window_is_maximized = false;
     private bool window_is_fullscreen = false;
     private bool window_is_tiled = false;
 
-    private SettingsModel model = new SettingsModel ();
-    [GtkChild] private TreeView dir_tree_view;
-    [GtkChild] private TreeSelection dir_tree_selection;
-
-    [GtkChild] private ListBox key_list_box;
-    private GLib.ListStore? key_model = null;
-
     private GLib.Settings settings = new GLib.Settings ("ca.desrt.dconf-editor.Settings");
-    [GtkChild] private Bookmarks bookmarks_button;
-
-    private GLib.ListStore rows_possibly_with_popover = new GLib.ListStore (typeof (ClickableListBoxRow));
-
-    [GtkChild] private ModificationsRevealer revealer;
-
-    [GtkChild] private SearchBar search_bar;
-    [GtkChild] private SearchEntry search_entry;
-    [GtkChild] private Button search_next_button;
 
+    [GtkChild] private Bookmarks bookmarks_button;
     [GtkChild] private MenuButton info_button;
-
     [GtkChild] private PathBar pathbar;
+    [GtkChild] private RegistryView registry_view;
 
     public DConfWindow ()
     {
@@ -61,19 +47,16 @@ class DConfWindow : ApplicationWindow
         add_action (settings.create_action ("delayed-apply-menu"));
 
         settings.changed["delayed-apply-menu"].connect (invalidate_popovers);
-        revealer.invalidate_popovers.connect (invalidate_popovers);
 
         set_default_size (settings.get_int ("window-width"), settings.get_int ("window-height"));
         if (settings.get_boolean ("window-is-fullscreen"))
-            fullscreen ();
+            fullscreen ();  // TODO deprecate
         else if (settings.get_boolean ("window-is-maximized"))
             maximize ();
 
-        search_bar.connect_entry (search_entry);
-
         settings.changed["theme"].connect (() => {
                 string theme = settings.get_string ("theme");
-                StyleContext context = get_style_context ();
+                StyleContext context = get_style_context ();    // TODO only check once?
                 if (theme == "three-twenty-two" && context.has_class ("small-rows"))
                     context.remove_class ("small-rows");
                 else if (theme == "small-rows" && !context.has_class ("small-rows"))
@@ -82,15 +65,9 @@ class DConfWindow : ApplicationWindow
         if (settings.get_string ("theme") == "small-rows")
             get_style_context ().add_class ("small-rows");
 
-        dir_tree_view.set_model (model);
-
-        current_path = settings.get_string ("saved-view");
-        if (!settings.get_boolean ("restore-view") || current_path == "" || !scroll_to_path (current_path))
-        {
-            current_path = "/";
-            if (!scroll_to_path ("/"))
-                assert_not_reached ();
-        }
+        registry_view.bind_property ("current-path", this, "current-path");    // TODO in UI file?
+        settings.bind ("delayed-apply-menu", registry_view, "delayed-apply-menu", 
SettingsBindFlags.GET|SettingsBindFlags.NO_SENSITIVITY);
+        registry_view.init (settings.get_string ("saved-view"), settings.get_boolean ("restore-view"));  // 
TODO better?
     }
 
     private static string stripped_path (string path)
@@ -164,283 +141,28 @@ class DConfWindow : ApplicationWindow
     }
 
     /*\
-    * * Dir TreeView
+    * *
     \*/
 
-    [GtkCallback]
-    private void dir_selected_cb ()
+    private void invalidate_popovers ()
     {
-        search_next_button.set_sensitive (true);        // TODO better, or maybe just hide search_bar 1/2
-
-        key_model = null;
-
-        TreeIter iter;
-        Directory dir;
-        if (dir_tree_selection.get_selected (null, out iter))
-            dir = model.get_directory (iter);
-        else
-            dir = model.get_root_directory ();
-
-        key_model = dir.key_model;
-        update_current_path (dir.full_name);
-
-        key_list_box.bind_model (key_model, new_list_box_row);
+        registry_view.invalidate_popovers ();
     }
 
     [GtkCallback]
     private bool scroll_to_path (string full_name)
     {
-        invalidate_popovers ();
-
-        if (full_name == "/")
-        {
-            dir_tree_selection.unselect_all ();
-            return true;
-        }
-
-        TreeIter iter;
-        if (model.get_iter_first (out iter))
-        {
-            do
-            {
-                Directory dir = model.get_directory (iter);
-
-                if (dir.full_name == full_name)
-                {
-                    select_dir (iter);
-                    return true;
-                }
-            }
-            while (get_next_iter (ref iter));
-        }
-        MessageDialog dialog = new MessageDialog (this, DialogFlags.MODAL, MessageType.ERROR, 
ButtonsType.OK, _("Oops! Cannot find something at this path."));
-        dialog.run ();
-        dialog.destroy ();
-        return false;
-    }
-
-    /*\
-    * * Key ListBox
-    \*/
-
-    private Widget new_list_box_row (Object item)
-    {
-        ClickableListBoxRow row;
-        if (((SettingObject) item).is_view)
-        {
-            row = new FolderListBoxRow (((SettingObject) item).name, ((SettingObject) item).full_name);
-            row.on_row_clicked.connect (() => {
-                    if (!scroll_to_path (((SettingObject) item).full_name))
-                        warning ("Something got wrong with this folder.");
-                });
-        }
-        else
-        {
-            Key key = (Key) item;
-            if (key.has_schema)
-            {
-                GSettingsKey gkey = (GSettingsKey) key;
-                row = new KeyListBoxRowEditable (gkey);
-                ((KeyListBoxRow) row).set_key_value.connect ((variant) => { set_glib_key_value (gkey, 
variant); });
-                ((KeyListBoxRow) row).change_dismissed.connect (() => { revealer.dismiss_glib_change (gkey); 
});
-            }
-            else
-            {
-                DConfKey dkey = (DConfKey) key;
-                row = new KeyListBoxRowEditableNoSchema (dkey);
-                ((KeyListBoxRow) row).set_key_value.connect ((variant) => { set_dconf_key_value (dkey, 
variant); });
-                ((KeyListBoxRow) row).change_dismissed.connect (() => { revealer.dismiss_dconf_change 
(dkey); });
-            }
-            row.on_row_clicked.connect (() => { new_key_editor (key); });
-            // TODO bug: row is always visually activated after the dialog destruction if mouse is over at 
this time
-        }
-        row.button_press_event.connect (on_button_pressed);
-        return row;
-    }
-
-    private void new_key_editor (Key key)
-    {
-        if (!key.has_schema && ((DConfKey) key).is_ghost)
-            return;
-
-        bool has_schema;
-        unowned Variant [] dict_container;
-        key.properties.get ("(ba{ss})", out has_schema, out dict_container);
-        Variant dict = dict_container [0];
-
-        // TODO use VariantDict
-        string key_name, tmp_string;
-
-        if (!dict.lookup ("key-name",     "s", out key_name))   assert_not_reached ();
-        if (!dict.lookup ("parent-path",  "s", out tmp_string)) assert_not_reached ();
-
-        KeyEditor key_editor = new KeyEditor (has_schema, key_name, tmp_string);
-
-        if (dict.lookup ("schema-id",     "s", out tmp_string)) key_editor.add_row_from_label (_("Schema"),  
    tmp_string);
-        if (dict.lookup ("summary",       "s", out tmp_string)) key_editor.add_row_from_label (_("Summary"), 
    tmp_string);
-        if (dict.lookup ("description",   "s", out tmp_string)) key_editor.add_row_from_label 
(_("Description"), tmp_string);
-        /* Translators: as in datatype (integer, boolean, string, etc.) */
-        if (dict.lookup ("type-name",     "s", out tmp_string)) key_editor.add_row_from_label (_("Type"),    
    tmp_string);
-        else assert_not_reached ();
-        if (dict.lookup ("minimum",       "s", out tmp_string)) key_editor.add_row_from_label (_("Minimum"), 
    tmp_string);
-        if (dict.lookup ("maximum",       "s", out tmp_string)) key_editor.add_row_from_label (_("Maximum"), 
    tmp_string);
-        if (dict.lookup ("default-value", "s", out tmp_string)) key_editor.add_row_from_label (_("Default"), 
    tmp_string);
-
-        if (!dict.lookup ("type-code",    "s", out tmp_string)) assert_not_reached ();
-
-        KeyEditorChild key_editor_child = create_child (key_editor, key);
-        if (has_schema)
-        {
-            Switch custom_value_switch = new Switch ();
-            custom_value_switch.width_request = 100; /* same request than for button_cancel/button_apply on 
scale 1; TODO better */
-            custom_value_switch.halign = Align.END;
-            custom_value_switch.hexpand = true;
-            custom_value_switch.show ();
-            key_editor.add_row_from_widget (_("Use default value"), custom_value_switch, null);
-
-            custom_value_switch.bind_property ("active", key_editor_child, "sensitive", 
BindingFlags.SYNC_CREATE | BindingFlags.INVERT_BOOLEAN);
-
-            GSettingsKey gkey = (GSettingsKey) key;
-            custom_value_switch.set_active (gkey.is_default);
-            custom_value_switch.notify ["active"].connect (() => {
-                    bool is_active = custom_value_switch.get_active ();
-                    key_editor.switch_is_active (is_active);
-                });
-
-            key_editor.response.connect ((dialog, response_id) => {
-                    if (response_id == ResponseType.APPLY)
-                    {
-                        if (!custom_value_switch.active)
-                        {
-                            Variant variant = key_editor_child.get_variant ();
-                            if (key.value != variant)
-                                key.value = variant;
-                        }
-                        else if (!gkey.is_default)
-                            gkey.set_to_default ();
-                    }
-                    dialog.destroy ();
-                });
-        }
-        else
-        {
-            key_editor.response.connect ((dialog, response_id) => {
-                    if (response_id == ResponseType.APPLY)
-                    {
-                        Variant variant = key_editor_child.get_variant ();
-                        if (key.value != variant)
-                            key.value = variant;
-                    }
-                    dialog.destroy ();
-                });
-        }
-        key_editor_child.value_has_changed.connect ((is_valid) => { key_editor.custom_value_is_valid = 
is_valid; });    // TODO not always useful
-        key_editor_child.child_activated.connect (() => {       // TODO "only" used for string-based and 
spin widgets
-                if (key_editor.custom_value_is_valid)
-                    key_editor.response (ResponseType.APPLY);
-            });
-        key_editor.add_row_from_widget (_("Custom value"), key_editor_child, tmp_string);
-
-        key_editor.set_transient_for (this);
-        key_editor.run ();
-    }
-
-    private static KeyEditorChild create_child (KeyEditor dialog, Key key)
-    {
-        switch (key.type_string)
-        {
-            case "<enum>":
-                return (KeyEditorChild) new KeyEditorChildEnum (key);
-            case "<flags>":
-                return (KeyEditorChild) new KeyEditorChildFlags ((GSettingsKey) key);
-            case "b":
-                return (KeyEditorChild) new KeyEditorChildBool (key.value.get_boolean ());
-            case "y":
-            case "n":
-            case "q":
-            case "i":
-            case "u":
-            case "h":   // TODO "x" and "t" are not working in spinbuttons (double-based)
-                return (KeyEditorChild) new KeyEditorChildNumberInt (key);
-            case "d":
-                return (KeyEditorChild) new KeyEditorChildNumberDouble (key);
-            case "mb":
-                return (KeyEditorChild) new KeyEditorChildNullableBool (key);
-            default:
-                return (KeyEditorChild) new KeyEditorChildDefault (key.type_string, key.value);
-        }
-    }
-
-    private bool on_button_pressed (Widget widget, Gdk.EventButton event)
-    {
-        ListBoxRow list_box_row = (ListBoxRow) widget.get_parent ();
-        key_list_box.select_row (list_box_row);
-        list_box_row.grab_focus ();
-
-        ClickableListBoxRow row = (ClickableListBoxRow) widget;
-        if (event.button == Gdk.BUTTON_SECONDARY)
-        {
-            row.show_right_click_popover (settings.get_boolean ("delayed-apply-menu"), (int) (event.x - 
row.get_allocated_width () / 2.0));
-            rows_possibly_with_popover.append (row);
-        }
-
-        return false;
-    }
-
-    [GtkCallback]
-    private void row_activated_cb (ListBoxRow list_box_row)
-    {
-        search_next_button.set_sensitive (true);        // TODO better, or maybe just hide search_bar 2/2
-
-        ((ClickableListBoxRow) list_box_row.get_child ()).on_row_clicked ();
-    }
-
-    private void invalidate_popovers ()
-    {
-        uint position = 0;
-        ClickableListBoxRow? row = (ClickableListBoxRow?) rows_possibly_with_popover.get_item (0);
-        while (row != null)
-        {
-            row.destroy_popover ();
-            position++;
-            row = (ClickableListBoxRow?) rows_possibly_with_popover.get_item (position);
-        }
-        rows_possibly_with_popover.remove_all ();
-    }
-
-    /*\
-    * * Revealer stuff
-    \*/
-
-    private void set_dconf_key_value (DConfKey key, Variant? new_value)
-    {
-        if (settings.get_boolean ("delayed-apply-menu") || key.planned_change)
-            revealer.add_delayed_dconf_settings (key, new_value);
-        else if (new_value != null)
-            key.value = new_value;
-        else
-            assert_not_reached ();
-    }
-
-    private void set_glib_key_value (GSettingsKey key, Variant? new_value)
-    {
-        if (settings.get_boolean ("delayed-apply-menu") || key.planned_change)
-            revealer.add_delayed_glib_settings (key, new_value);
-        else if (new_value != null)
-            key.value = new_value;
-        else
-            key.set_to_default ();
+        return registry_view.scroll_to_path (full_name);
     }
 
     /*\
     * * Action entries
     \*/
 
-    private void update_current_path (string path)
+    public void update_current_path ()
     {
         GLib.Menu section;
 
-        current_path = path;
         bookmarks_button.current_path = stripped_path (current_path);
         pathbar.set_path (current_path);
 
@@ -467,56 +189,18 @@ class DConfWindow : ApplicationWindow
 
     private void reset ()
     {
-        reset_generic (key_model, false);
-        invalidate_popovers ();
+        registry_view.reset (false);
     }
 
     private void reset_recursively ()
     {
-        reset_generic (key_model, true);
-        invalidate_popovers ();
-    }
-
-    private void reset_generic (GLib.ListStore? objects, bool recursively)   // TODO notification if nothing 
to reset
-    {
-        if (objects == null)
-            return;
-
-        for (uint position = 0;; position++)
-        {
-            Object? object = ((!) objects).get_object (position);
-            if (object == null)
-                return;
-
-            SettingObject setting_object = (SettingObject) ((!) object);
-            if (setting_object.is_view)
-            {
-                if (recursively)
-                    reset_generic (((Directory) setting_object).key_model, true);
-                continue;
-            }
-            if (!((Key) setting_object).has_schema)
-            {
-                if (!((DConfKey) setting_object).is_ghost)
-                    revealer.add_delayed_dconf_settings ((DConfKey) setting_object, null);
-            }
-            else if (!((GSettingsKey) setting_object).is_default)
-                revealer.add_delayed_glib_settings ((GSettingsKey) setting_object, null);
-        }
+        registry_view.reset (true);
     }
 
     /*\
-    * * Search box
+    * * Other callbacks
     \*/
 
-    private void discard_row_popover ()
-    {
-        ListBoxRow? selected_row = (ListBoxRow) key_list_box.get_selected_row ();
-        if (selected_row == null)
-            return;
-        ((ClickableListBoxRow) ((!) selected_row).get_child ()).hide_right_click_popover ();
-    }
-
     [GtkCallback]
     private bool on_key_press_event (Widget widget, Gdk.EventKey event)     // TODO better?
     {
@@ -529,19 +213,19 @@ class DConfWindow : ApplicationWindow
                 case "b":
                     if (info_button.active)
                         info_button.active = false;
-                    discard_row_popover ();
+                    registry_view.discard_row_popover ();
                     bookmarks_button.clicked ();
                     return true;
                 case "d":
                     if (info_button.active)
                         info_button.active = false;
-                    discard_row_popover ();
+                    registry_view.discard_row_popover ();
                     bookmarks_button.set_bookmarked (true);
                     return true;
                 case "D":
                     if (info_button.active)
                         info_button.active = false;
-                    discard_row_popover ();
+                    registry_view.discard_row_popover ();
                     bookmarks_button.set_bookmarked (false);
                     return true;
                 case "f":
@@ -549,21 +233,21 @@ class DConfWindow : ApplicationWindow
                         bookmarks_button.active = false;
                     if (info_button.active)
                         info_button.active = false;
-                    discard_row_popover ();
-                    search_bar.set_search_mode (!search_bar.get_search_mode ());
+                    registry_view.discard_row_popover ();
+                    registry_view.search_bar.set_search_mode (!registry_view.search_bar.get_search_mode ());
                     return true;
                 case "c":
-                    discard_row_popover (); // TODO avoid duplicate get_selected_row () call
-                    ListBoxRow? selected_row = (ListBoxRow) key_list_box.get_selected_row ();
+                    registry_view.discard_row_popover (); // TODO avoid duplicate get_selected_row () call
+                    string? selected_row_text = registry_view.get_selected_row_text ();
                     ConfigurationEditor application = (ConfigurationEditor) get_application ();
-                    application.copy (selected_row == null ? current_path : ((ClickableListBoxRow) ((!) 
selected_row).get_child ()).get_text ());
+                    application.copy (selected_row_text == null ? current_path : (!) selected_row_text);
                     return true;
                 case "C":
-                    discard_row_popover ();
+                    registry_view.discard_row_popover ();
                     ((ConfigurationEditor) get_application ()).copy (current_path);
                     return true;
                 case "F1":
-                    discard_row_popover ();
+                    registry_view.discard_row_popover ();
                     if ((event.state & Gdk.ModifierType.SHIFT_MASK) == 0)
                         return false;   // help overlay
                     ((ConfigurationEditor) get_application ()).about_cb ();
@@ -576,23 +260,19 @@ class DConfWindow : ApplicationWindow
         /* don't use "else if", or some widgets will not be hidden on <ctrl>F10 or such things */
         if (name == "F10")
         {
-            discard_row_popover ();
+            registry_view.discard_row_popover ();
             if (bookmarks_button.active)
                 bookmarks_button.active = false;
             return false;
         }
         else if (name == "Menu")
         {
-            ListBoxRow? selected_row = (ListBoxRow) key_list_box.get_selected_row ();
-            if (selected_row != null)
+            if (registry_view.show_row_popover ())
             {
                 if (bookmarks_button.active)
                     bookmarks_button.active = false;
                 if (info_button.active)
                     info_button.active = false;
-                ClickableListBoxRow row = (ClickableListBoxRow) ((!) selected_row).get_child ();
-                row.show_right_click_popover (settings.get_boolean ("delayed-apply-menu"));
-                rows_possibly_with_popover.append (row);
             }
             else if (info_button.active == false)
             {
@@ -608,108 +288,13 @@ class DConfWindow : ApplicationWindow
         if (bookmarks_button.active || info_button.active)      // TODO open bug about modal popovers and 
search_bar
             return false;
 
-        return search_bar.handle_event (event);
+        return registry_view.search_bar.handle_event (event);
     }
 
     [GtkCallback]
     private void on_menu_button_clicked ()
     {
-        discard_row_popover ();
-        search_bar.set_search_mode (false);
-    }
-
-    [GtkCallback]
-    private void find_next_cb ()
-    {
-        if (!search_bar.get_search_mode ())     // TODO better; switches to next list_box_row when 
keyboard-activating an entry of the popover
-            return;
-
-        TreeIter iter;
-        bool on_first_directory;
-        int position = 0;
-        if (dir_tree_selection.get_selected (null, out iter))
-        {
-            ListBoxRow? selected_row = (ListBoxRow) key_list_box.get_selected_row ();
-            if (selected_row != null)
-                position = ((!) selected_row).get_index () + 1;
-
-            on_first_directory = true;
-        }
-        else if (model.get_iter_first (out iter))
-            on_first_directory = false;
-        else
-            return;     // TODO better
-
-        do
-        {
-            Directory dir = model.get_directory (iter);
-
-            if (!on_first_directory && dir.name.index_of (search_entry.text) >= 0)
-            {
-                select_dir (iter);
-                return;
-            }
-            on_first_directory = false;
-
-            /* Select next key that matches */
-            GLib.ListStore key_model = dir.key_model;
-            while (position < key_model.get_n_items ())
-            {
-                SettingObject object = (SettingObject) key_model.get_object (position);
-                if (object.name.index_of (search_entry.text) >= 0 || 
-                    (!object.is_view && key_matches ((Key) object, search_entry.text)))
-                {
-                    select_dir (iter);
-                    key_list_box.select_row (key_list_box.get_row_at_index (position));
-                    // TODO select key in ListBox
-                    return;
-                }
-                position++;
-            }
-
-            position = 0;
-        }
-        while (get_next_iter (ref iter));
-
-        search_next_button.set_sensitive (false);
-    }
-
-    private void select_dir (TreeIter iter)
-    {
-        dir_tree_view.expand_to_path (model.get_path (iter));
-        dir_tree_selection.select_iter (iter);
-    }
-
-    private bool key_matches (Key key, string text)
-    {
-        /* Check in key's metadata */
-        if (key.has_schema && ((GSettingsKey) key).search_for (text))
-            return true;
-
-        /* Check key value */
-        if (key.value.is_of_type (VariantType.STRING) && key.value.get_string ().index_of (text) >= 0)
-            return true;
-
-        return false;
-    }
-
-    private bool get_next_iter (ref TreeIter iter)
-    {
-        /* Search children next */
-        if (model.iter_has_child (iter))
-        {
-            model.iter_nth_child (out iter, iter, 0);
-            return true;
-        }
-
-        /* Move to the next branch */
-        while (!model.iter_next (ref iter))
-        {
-            /* Otherwise move to the parent and onto the next iter */
-            if (!model.iter_parent (out iter, iter))
-                return false;
-        }
-
-        return true;
+        registry_view.discard_row_popover ();
+        registry_view.search_bar.set_search_mode (false);
     }
 }
diff --git a/editor/registry-view.ui b/editor/registry-view.ui
new file mode 100644
index 0000000..97927d1
--- /dev/null
+++ b/editor/registry-view.ui
@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <!-- interface-requires gtk+ 3.0 -->
+  <template class="RegistryView" parent="GtkGrid">
+    <property name="orientation">vertical</property>
+    <child>
+      <object class="GtkTreeView" id="dir_tree_view">
+        <property name="visible">False</property>
+        <child internal-child="selection">
+          <object class="GtkTreeSelection" id="dir_tree_selection">
+            <signal name="changed" handler="dir_selected_cb"/>
+          </object>
+        </child>
+      </object>
+    </child>
+    <child>
+      <object class="GtkSearchBar" id="search_bar">
+        <property name="visible">True</property>
+        <property name="search-mode-enabled">False</property>
+        <property name="show-close-button">False</property>
+        <child>
+          <object class="GtkGrid">
+            <property name="visible">True</property>
+            <property name="orientation">horizontal</property>
+            <style>
+              <class name="linked"/>
+            </style>
+            <child>
+              <object class="GtkSearchEntry" id="search_entry">
+                <property name="visible">True</property>
+                <property name="width-request">350</property>
+                <signal name="activate" handler="find_next_cb"/>
+              </object>
+            </child>
+            <child>
+              <object class="GtkButton" id="search_next_button">
+                <property name="visible">True</property>
+                <signal name="clicked" handler="find_next_cb"/>
+                <property name="sensitive" bind-source="search_bar" bind-property="search-mode-enabled"/>
+                <child>
+                  <object class="GtkImage">
+                    <property name="visible">True</property>
+                    <property name="icon-size">1</property>
+                    <property name="icon-name">go-down-symbolic</property>
+                  </object>
+                </child>
+              </object>
+            </child>
+          </object>
+        </child>
+      </object>
+    </child>
+    <child>
+      <object class="GtkStack">
+        <property name="visible">True</property>
+        <property name="visible-child">browse-view</property>
+        <property name="expand">True</property>
+        <child>
+          <object class="GtkScrolledWindow" id="browse-view">
+            <property name="visible">True</property>
+            <child>
+              <object class="GtkListBox" id="key_list_box">
+                <property name="visible">True</property>
+                <property name="activate-on-single-click">True</property>
+                <property name="selection-mode">browse</property><!-- permits to not have an item selected 
-->
+                <style>
+                  <class name="dconf-list"/>
+                </style>
+                <signal name="row-activated" handler="row_activated_cb"/>
+                <child type="placeholder">      <!-- see 
nautilus/src/resources/ui/nautilus-folder-is-empty.ui -->
+                  <object class="GtkGrid">
+                    <property name="visible">True</property>
+                    <property name="row-spacing">12</property>
+                    <property name="expand">True</property>
+                    <property name="halign">center</property>
+                    <property name="valign">center</property>
+                    <property name="orientation">vertical</property>
+                    <style>
+                      <class name="dim-label"/>
+                    </style>
+                    <child>
+                      <object class="GtkImage">
+                        <property name="visible">True</property>
+                        <property name="icon-name">dconf-editor-symbolic</property>
+                        <property name="pixel-size">72</property>
+                        <style>
+                          <class name="dim-label"/>
+                        </style>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkLabel">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">No keys in this path</property>
+                        <attributes>
+                          <attribute name="weight" value="bold"/>
+                          <attribute name="scale" value="1.44"/>
+                        </attributes>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+          </object>
+        </child>
+      </object>
+    </child>
+    <child>
+      <object class="ModificationsRevealer" id="revealer">
+        <property name="visible">True</property>
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/editor/registry-view.vala b/editor/registry-view.vala
new file mode 100644
index 0000000..294a661
--- /dev/null
+++ b/editor/registry-view.vala
@@ -0,0 +1,495 @@
+/*
+  This file is part of Dconf Editor
+
+  Dconf Editor is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  Dconf Editor is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with Dconf Editor.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+using Gtk;
+
+[GtkTemplate (ui = "/ca/desrt/dconf-editor/ui/registry-view.ui")]
+class RegistryView : Grid
+{
+    public string current_path { get; private set; }
+    public bool show_search_bar { get; set; }
+    public bool delayed_apply_menu { get; set; }
+
+    private SettingsModel model = new SettingsModel ();
+    [GtkChild] private TreeView dir_tree_view;
+    [GtkChild] private TreeSelection dir_tree_selection;
+
+    [GtkChild] private ListBox key_list_box;
+    private GLib.ListStore? key_model = null;
+
+    private GLib.ListStore rows_possibly_with_popover = new GLib.ListStore (typeof (ClickableListBoxRow));
+
+    [GtkChild] private ModificationsRevealer revealer;
+
+    [GtkChild] public SearchBar search_bar;
+    [GtkChild] private SearchEntry search_entry;
+    [GtkChild] private Button search_next_button;
+
+    construct
+    {
+        revealer.invalidate_popovers.connect (invalidate_popovers);
+
+        search_entry.get_buffer ().deleted_text.connect (() => { search_next_button.set_sensitive (true); });
+        search_bar.connect_entry (search_entry);
+        bind_property ("show-search-bar", search_bar, "search-mode-enabled", BindingFlags.BIDIRECTIONAL);   
// TODO in UI file?
+    }
+
+    public void init (string path, bool restore_view)
+    {
+        dir_tree_view.set_model (model);
+
+        current_path = path;
+        if (!restore_view || current_path == "" || !scroll_to_path (current_path))
+        {
+            current_path = "/";
+            if (!scroll_to_path ("/"))
+                assert_not_reached ();
+        }
+    }
+
+    /*\
+    * * Dir TreeView
+    \*/
+
+    [GtkCallback]
+    private void dir_selected_cb ()
+    {
+        search_next_button.set_sensitive (true);        // TODO better, or maybe just hide search_bar 1/2
+
+        key_model = null;
+
+        TreeIter iter;
+        Directory dir;
+        if (dir_tree_selection.get_selected (null, out iter))
+            dir = model.get_directory (iter);
+        else
+            dir = model.get_root_directory ();
+
+        key_model = dir.key_model;
+        current_path = dir.full_name;
+        ((DConfWindow) this.get_parent ()).update_current_path ();
+
+        key_list_box.bind_model (key_model, new_list_box_row);
+    }
+
+    public bool scroll_to_path (string full_name)
+    {
+        invalidate_popovers ();
+
+        if (full_name == "/")
+        {
+            dir_tree_selection.unselect_all ();
+            return true;
+        }
+
+        TreeIter iter;
+        if (model.get_iter_first (out iter))
+        {
+            do
+            {
+                Directory dir = model.get_directory (iter);
+
+                if (dir.full_name == full_name)
+                {
+                    select_dir (iter);
+                    return true;
+                }
+            }
+            while (get_next_iter (ref iter));
+        }
+        MessageDialog dialog = new MessageDialog ((Window) this.get_parent (), DialogFlags.MODAL, 
MessageType.ERROR, ButtonsType.OK, _("Oops! Cannot find something at this path."));
+        dialog.run ();
+        dialog.destroy ();
+        return false;
+    }
+
+    /*\
+    * * Key ListBox
+    \*/
+
+    private Widget new_list_box_row (Object item)
+    {
+        ClickableListBoxRow row;
+        if (((SettingObject) item).is_view)
+        {
+            row = new FolderListBoxRow (((SettingObject) item).name, ((SettingObject) item).full_name);
+            row.on_row_clicked.connect (() => {
+                    if (!scroll_to_path (((SettingObject) item).full_name))
+                        warning ("Something got wrong with this folder.");
+                });
+        }
+        else
+        {
+            Key key = (Key) item;
+            if (key.has_schema)
+            {
+                GSettingsKey gkey = (GSettingsKey) key;
+                row = new KeyListBoxRowEditable (gkey);
+                ((KeyListBoxRow) row).set_key_value.connect ((variant) => { set_glib_key_value (gkey, 
variant); });
+                ((KeyListBoxRow) row).change_dismissed.connect (() => { revealer.dismiss_glib_change (gkey); 
});
+            }
+            else
+            {
+                DConfKey dkey = (DConfKey) key;
+                row = new KeyListBoxRowEditableNoSchema (dkey);
+                ((KeyListBoxRow) row).set_key_value.connect ((variant) => { set_dconf_key_value (dkey, 
variant); });
+                ((KeyListBoxRow) row).change_dismissed.connect (() => { revealer.dismiss_dconf_change 
(dkey); });
+            }
+            row.on_row_clicked.connect (() => { new_key_editor (key); });
+            // TODO bug: row is always visually activated after the dialog destruction if mouse is over at 
this time
+        }
+        row.button_press_event.connect (on_button_pressed);
+        return row;
+    }
+
+    private void new_key_editor (Key key)
+    {
+        if (!key.has_schema && ((DConfKey) key).is_ghost)
+            return;
+
+        bool has_schema;
+        unowned Variant [] dict_container;
+        key.properties.get ("(ba{ss})", out has_schema, out dict_container);
+        Variant dict = dict_container [0];
+
+        // TODO use VariantDict
+        string key_name, tmp_string;
+
+        if (!dict.lookup ("key-name",     "s", out key_name))   assert_not_reached ();
+        if (!dict.lookup ("parent-path",  "s", out tmp_string)) assert_not_reached ();
+
+        KeyEditor key_editor = new KeyEditor (has_schema, key_name, tmp_string);
+
+        if (dict.lookup ("schema-id",     "s", out tmp_string)) key_editor.add_row_from_label (_("Schema"),  
    tmp_string);
+        if (dict.lookup ("summary",       "s", out tmp_string)) key_editor.add_row_from_label (_("Summary"), 
    tmp_string);
+        if (dict.lookup ("description",   "s", out tmp_string)) key_editor.add_row_from_label 
(_("Description"), tmp_string);
+        /* Translators: as in datatype (integer, boolean, string, etc.) */
+        if (dict.lookup ("type-name",     "s", out tmp_string)) key_editor.add_row_from_label (_("Type"),    
    tmp_string);
+        else assert_not_reached ();
+        if (dict.lookup ("minimum",       "s", out tmp_string)) key_editor.add_row_from_label (_("Minimum"), 
    tmp_string);
+        if (dict.lookup ("maximum",       "s", out tmp_string)) key_editor.add_row_from_label (_("Maximum"), 
    tmp_string);
+        if (dict.lookup ("default-value", "s", out tmp_string)) key_editor.add_row_from_label (_("Default"), 
    tmp_string);
+
+        if (!dict.lookup ("type-code",    "s", out tmp_string)) assert_not_reached ();
+
+        KeyEditorChild key_editor_child = create_child (key_editor, key);
+        if (has_schema)
+        {
+            Switch custom_value_switch = new Switch ();
+            custom_value_switch.width_request = 100; /* same request than for button_cancel/button_apply on 
scale 1; TODO better */
+            custom_value_switch.halign = Align.END;
+            custom_value_switch.hexpand = true;
+            custom_value_switch.show ();
+            key_editor.add_row_from_widget (_("Use default value"), custom_value_switch, null);
+
+            custom_value_switch.bind_property ("active", key_editor_child, "sensitive", 
BindingFlags.SYNC_CREATE | BindingFlags.INVERT_BOOLEAN);
+
+            GSettingsKey gkey = (GSettingsKey) key;
+            custom_value_switch.set_active (gkey.is_default);
+            custom_value_switch.notify ["active"].connect (() => {
+                    bool is_active = custom_value_switch.get_active ();
+                    key_editor.switch_is_active (is_active);
+                });
+
+            key_editor.response.connect ((dialog, response_id) => {
+                    if (response_id == ResponseType.APPLY)
+                    {
+                        if (!custom_value_switch.active)
+                        {
+                            Variant variant = key_editor_child.get_variant ();
+                            if (key.value != variant)
+                                key.value = variant;
+                        }
+                        else if (!gkey.is_default)
+                            gkey.set_to_default ();
+                    }
+                    dialog.destroy ();
+                });
+        }
+        else
+        {
+            key_editor.response.connect ((dialog, response_id) => {
+                    if (response_id == ResponseType.APPLY)
+                    {
+                        Variant variant = key_editor_child.get_variant ();
+                        if (key.value != variant)
+                            key.value = variant;
+                    }
+                    dialog.destroy ();
+                });
+        }
+        key_editor_child.value_has_changed.connect ((is_valid) => { key_editor.custom_value_is_valid = 
is_valid; });    // TODO not always useful
+        key_editor_child.child_activated.connect (() => {       // TODO "only" used for string-based and 
spin widgets
+                if (key_editor.custom_value_is_valid)
+                    key_editor.response (ResponseType.APPLY);
+            });
+        key_editor.add_row_from_widget (_("Custom value"), key_editor_child, tmp_string);
+
+        key_editor.set_transient_for ((Window) this.get_parent ());
+        key_editor.run ();
+    }
+
+    private static KeyEditorChild create_child (KeyEditor dialog, Key key)
+    {
+        switch (key.type_string)
+        {
+            case "<enum>":
+                return (KeyEditorChild) new KeyEditorChildEnum (key);
+            case "<flags>":
+                return (KeyEditorChild) new KeyEditorChildFlags ((GSettingsKey) key);
+            case "b":
+                return (KeyEditorChild) new KeyEditorChildBool (key.value.get_boolean ());
+            case "y":
+            case "n":
+            case "q":
+            case "i":
+            case "u":
+            case "h":   // TODO "x" and "t" are not working in spinbuttons (double-based)
+                return (KeyEditorChild) new KeyEditorChildNumberInt (key);
+            case "d":
+                return (KeyEditorChild) new KeyEditorChildNumberDouble (key);
+            case "mb":
+                return (KeyEditorChild) new KeyEditorChildNullableBool (key);
+            default:
+                return (KeyEditorChild) new KeyEditorChildDefault (key.type_string, key.value);
+        }
+    }
+
+    private bool on_button_pressed (Widget widget, Gdk.EventButton event)
+    {
+        ListBoxRow list_box_row = (ListBoxRow) widget.get_parent ();
+        key_list_box.select_row (list_box_row);
+        list_box_row.grab_focus ();
+
+        if (event.button == Gdk.BUTTON_SECONDARY)
+        {
+            ClickableListBoxRow row = (ClickableListBoxRow) widget;
+            row.show_right_click_popover (delayed_apply_menu, (int) (event.x - row.get_allocated_width () / 
2.0));
+            rows_possibly_with_popover.append (row);
+        }
+
+        return false;
+    }
+
+    [GtkCallback]
+    private void row_activated_cb (ListBoxRow list_box_row)
+    {
+        search_next_button.set_sensitive (true);        // TODO better, or maybe just hide search_bar 2/2
+
+        ((ClickableListBoxRow) list_box_row.get_child ()).on_row_clicked ();
+    }
+
+    public void invalidate_popovers ()
+    {
+        uint position = 0;
+        ClickableListBoxRow? row = (ClickableListBoxRow?) rows_possibly_with_popover.get_item (0);
+        while (row != null)
+        {
+            row.destroy_popover ();
+            position++;
+            row = (ClickableListBoxRow?) rows_possibly_with_popover.get_item (position);
+        }
+        rows_possibly_with_popover.remove_all ();
+    }
+
+    /*\
+    * * Revealer stuff
+    \*/
+
+    private void set_dconf_key_value (DConfKey key, Variant? new_value)
+    {
+        if (delayed_apply_menu || key.planned_change)
+            revealer.add_delayed_dconf_settings (key, new_value);
+        else if (new_value != null)
+            key.value = new_value;
+        else
+            assert_not_reached ();
+    }
+
+    private void set_glib_key_value (GSettingsKey key, Variant? new_value)
+    {
+        if (delayed_apply_menu || key.planned_change)
+            revealer.add_delayed_glib_settings (key, new_value);
+        else if (new_value != null)
+            key.value = new_value;
+        else
+            key.set_to_default ();
+    }
+
+    /*\
+    * * Action entries
+    \*/
+
+    public void reset (bool recursively)
+    {
+        reset_generic (key_model, recursively);
+        invalidate_popovers ();
+    }
+
+    private void reset_generic (GLib.ListStore? objects, bool recursively)   // TODO notification if nothing 
to reset
+    {
+        if (objects == null)
+            return;
+
+        for (uint position = 0;; position++)
+        {
+            Object? object = ((!) objects).get_object (position);
+            if (object == null)
+                return;
+
+            SettingObject setting_object = (SettingObject) ((!) object);
+            if (setting_object.is_view)
+            {
+                if (recursively)
+                    reset_generic (((Directory) setting_object).key_model, true);
+                continue;
+            }
+            if (!((Key) setting_object).has_schema)
+            {
+                if (!((DConfKey) setting_object).is_ghost)
+                    revealer.add_delayed_dconf_settings ((DConfKey) setting_object, null);
+            }
+            else if (!((GSettingsKey) setting_object).is_default)
+                revealer.add_delayed_glib_settings ((GSettingsKey) setting_object, null);
+        }
+    }
+
+    /*\
+    * * Search box
+    \*/
+
+    public bool show_row_popover ()
+    {
+        ListBoxRow? selected_row = (ListBoxRow) key_list_box.get_selected_row ();
+        if (selected_row == null)
+            return false;
+
+        ClickableListBoxRow row = (ClickableListBoxRow) ((!) selected_row).get_child ();
+        row.show_right_click_popover (delayed_apply_menu);
+        rows_possibly_with_popover.append (row);
+        return true;
+    }
+
+    public string? get_selected_row_text ()
+    {
+        ListBoxRow? selected_row = (ListBoxRow) key_list_box.get_selected_row ();
+        return selected_row == null ? null : ((ClickableListBoxRow) ((!) selected_row).get_child 
()).get_text ();
+    }
+
+    public void discard_row_popover ()
+    {
+        ListBoxRow? selected_row = (ListBoxRow) key_list_box.get_selected_row ();
+        if (selected_row == null)
+            return;
+        ((ClickableListBoxRow) ((!) selected_row).get_child ()).hide_right_click_popover ();
+    }
+
+    [GtkCallback]
+    private void find_next_cb ()
+    {
+        if (!search_bar.get_search_mode ())     // TODO better; switches to next list_box_row when 
keyboard-activating an entry of the popover
+            return;
+
+        TreeIter iter;
+        bool on_first_directory;
+        int position = 0;
+        if (dir_tree_selection.get_selected (null, out iter))
+        {
+            ListBoxRow? selected_row = (ListBoxRow) key_list_box.get_selected_row ();
+            if (selected_row != null)
+                position = ((!) selected_row).get_index () + 1;
+
+            on_first_directory = true;
+        }
+        else if (model.get_iter_first (out iter))
+            on_first_directory = false;
+        else
+            return;     // TODO better
+
+        do
+        {
+            Directory dir = model.get_directory (iter);
+
+            if (!on_first_directory && dir.name.index_of (search_entry.text) >= 0)
+            {
+                select_dir (iter);
+                return;
+            }
+            on_first_directory = false;
+
+            /* Select next key that matches */
+            GLib.ListStore key_model = dir.key_model;
+            while (position < key_model.get_n_items ())
+            {
+                SettingObject object = (SettingObject) key_model.get_object (position);
+                if (object.name.index_of (search_entry.text) >= 0 || 
+                    (!object.is_view && key_matches ((Key) object, search_entry.text)))
+                {
+                    select_dir (iter);
+                    key_list_box.select_row (key_list_box.get_row_at_index (position));
+                    // TODO select key in ListBox
+                    return;
+                }
+                position++;
+            }
+
+            position = 0;
+        }
+        while (get_next_iter (ref iter));
+
+        search_next_button.set_sensitive (false);
+    }
+
+    private void select_dir (TreeIter iter)
+    {
+        dir_tree_view.expand_to_path (model.get_path (iter));
+        dir_tree_selection.select_iter (iter);
+    }
+
+    private bool key_matches (Key key, string text)
+    {
+        /* Check in key's metadata */
+        if (key.has_schema && ((GSettingsKey) key).search_for (text))
+            return true;
+
+        /* Check key value */
+        if (key.value.is_of_type (VariantType.STRING) && key.value.get_string ().index_of (text) >= 0)
+            return true;
+
+        return false;
+    }
+
+    private bool get_next_iter (ref TreeIter iter)
+    {
+        /* Search children next */
+        if (model.iter_has_child (iter))
+        {
+            model.iter_nth_child (out iter, iter, 0);
+            return true;
+        }
+
+        /* Move to the next branch */
+        while (!model.iter_next (ref iter))
+        {
+            /* Otherwise move to the parent and onto the next iter */
+            if (!model.iter_parent (out iter, iter))
+                return false;
+        }
+
+        return true;
+    }
+}
diff --git a/po/POTFILES.in b/po/POTFILES.in
index f303e9d..087382e 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -14,3 +14,5 @@ editor/dconf-window.vala
 editor/key-list-box-row.vala
 [type: gettext/glade]editor/modifications-revealer.ui
 editor/modifications-revealer.vala
+[type: gettext/glade]editor/registry-view.ui
+editor/registry-view.vala
diff --git a/po/POTFILES.skip b/po/POTFILES.skip
index 739e021..12aaa33 100644
--- a/po/POTFILES.skip
+++ b/po/POTFILES.skip
@@ -5,5 +5,6 @@ editor/dconf-view.c
 editor/dconf-window.c
 editor/key-list-box-row.c
 editor/modifications-revealer.c
+editor/registry-view.c
 # Autotools failure
 sub/editor/ca.desrt.dconf-editor.desktop.in


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