[dconf-editor] Use a ListBox.



commit e0a53361b6ad015a2f09f93be99886f5ee9c1cbc
Author: Arnaud Bonatti <arnaud bonatti gmail com>
Date:   Tue Sep 22 18:34:38 2015 +0200

    Use a ListBox.

 editor/Makefile.am                |    4 +-
 editor/dconf-editor.gresource.xml |    2 +
 editor/dconf-editor.ui            |  235 +--------------
 editor/dconf-model.vala           |  339 ++--------------------
 editor/dconf-view.vala            |  590 ++++++++++++++++++++++---------------
 editor/dconf-window.vala          |  301 +++++++------------
 editor/key-editor.ui              |  244 +++++++++++++++
 editor/key-list-box-row.ui        |   46 +++
 8 files changed, 782 insertions(+), 979 deletions(-)
---
diff --git a/editor/Makefile.am b/editor/Makefile.am
index ee3d495..3b903e0 100644
--- a/editor/Makefile.am
+++ b/editor/Makefile.am
@@ -23,7 +23,9 @@ dconf_editor_CFLAGS = \
 resource_data = \
        dconf-editor.gresource.xml \
        dconf-editor-menu.ui \
-       dconf-editor.ui
+       dconf-editor.ui \
+       key-list-box-row.ui \
+       key-editor.ui
 
 resources.c: $(resource_data)
        $(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) --sourcedir=$(srcdir) --target=$@ --generate-source $<
diff --git a/editor/dconf-editor.gresource.xml b/editor/dconf-editor.gresource.xml
index 8f91396..67da824 100644
--- a/editor/dconf-editor.gresource.xml
+++ b/editor/dconf-editor.gresource.xml
@@ -2,6 +2,8 @@
 <gresources>
   <gresource prefix="/ca/desrt/dconf-editor/ui">
     <file preprocess="xml-stripblanks">dconf-editor.ui</file>
+    <file preprocess="xml-stripblanks">key-list-box-row.ui</file>
+    <file preprocess="xml-stripblanks">key-editor.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 bb1698a..7d8d0d8 100644
--- a/editor/dconf-editor.ui
+++ b/editor/dconf-editor.ui
@@ -20,7 +20,6 @@
             <child>
               <object class="GtkScrolledWindow">
                 <property name="visible">True</property>
-                <property name="can_focus">True</property>
                 <property name="hscrollbar_policy">never</property>
                 <property name="width_request">222</property>
                 <child>
@@ -53,241 +52,17 @@
               </packing>
             </child>
             <child>
-              <object class="GtkBox">
-                <property name="orientation">vertical</property>
+              <object class="GtkScrolledWindow">
                 <property name="visible">True</property>
-                <property name="can_focus">False</property>
                 <child>
-                  <object class="GtkGrid" id="key_info_grid">
+                  <object class="GtkListBox" id="key_list_box">
                     <property name="visible">True</property>
-                    <property name="sensitive">False</property>
-                    <property name="can_focus">False</property>
-                    <property name="margin_start">6</property>
-                    <property name="margin_end">6</property>
-                    <property name="margin_top">6</property>
-                    <property name="margin_bottom">6</property>
-                    <property name="row_spacing">6</property>
-                    <property name="column_spacing">6</property>
-                    <child>
-                      <object class="GtkLabel">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="xalign">0</property>
-                        <property name="yalign">0</property>
-                        <property name="label" translatable="yes">Schema:</property>
-                      </object>
-                      <packing>
-                        <property name="left_attach">0</property>
-                        <property name="top_attach">0</property>
-                        <property name="width">1</property>
-                        <property name="height">1</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkLabel">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="xalign">0</property>
-                        <property name="yalign">0</property>
-                        <property name="label" translatable="yes">Summary:</property>
-                      </object>
-                      <packing>
-                        <property name="left_attach">0</property>
-                        <property name="top_attach">1</property>
-                        <property name="width">1</property>
-                        <property name="height">1</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkLabel">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="xalign">0</property>
-                        <property name="yalign">0</property>
-                        <property name="label" translatable="yes">Description:</property>
-                      </object>
-                      <packing>
-                        <property name="left_attach">0</property>
-                        <property name="top_attach">2</property>
-                        <property name="width">1</property>
-                        <property name="height">1</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkLabel">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="xalign">0</property>
-                        <property name="yalign">0</property>
-                        <property name="label" translatable="yes" comments="Translators: as in datatype 
(integer, boolean, string, etc)">Type:</property>
-                      </object>
-                      <packing>
-                        <property name="left_attach">0</property>
-                        <property name="top_attach">3</property>
-                        <property name="width">1</property>
-                        <property name="height">1</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkLabel">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="xalign">0</property>
-                        <property name="yalign">0</property>
-                        <property name="label" translatable="yes">Default:</property>
-                      </object>
-                      <packing>
-                        <property name="left_attach">0</property>
-                        <property name="top_attach">4</property>
-                        <property name="width">1</property>
-                        <property name="height">1</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkLabel" id="schema_label">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="xalign">0</property>
-                        <property name="yalign">0</property>
-                        <property name="selectable">True</property>
-                      </object>
-                      <packing>
-                        <property name="left_attach">1</property>
-                        <property name="top_attach">0</property>
-                        <property name="width">1</property>
-                        <property name="height">1</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkLabel" id="summary_label">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="xalign">0</property>
-                        <property name="yalign">0</property>
-                        <property name="wrap">True</property>
-                        <property name="selectable">True</property>
-                      </object>
-                      <packing>
-                        <property name="left_attach">1</property>
-                        <property name="top_attach">1</property>
-                        <property name="width">1</property>
-                        <property name="height">1</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkLabel" id="description_label">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="xalign">0</property>
-                        <property name="yalign">0</property>
-                        <property name="wrap">True</property>
-                        <property name="selectable">True</property>
-                      </object>
-                      <packing>
-                        <property name="left_attach">1</property>
-                        <property name="top_attach">2</property>
-                        <property name="width">1</property>
-                        <property name="height">1</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkLabel" id="type_label">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="xalign">0</property>
-                        <property name="yalign">0</property>
-                        <property name="selectable">True</property>
-                      </object>
-                      <packing>
-                        <property name="left_attach">1</property>
-                        <property name="top_attach">3</property>
-                        <property name="width">1</property>
-                        <property name="height">1</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkBox">
-                        <property name="orientation">horizontal</property>
-                        <property name="hexpand">True</property>
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="spacing">6</property>
-                        <child>
-                          <object class="GtkLabel" id="default_label">
-                            <property name="visible">True</property>
-                            <property name="can_focus">False</property>
-                            <property name="xalign">0</property>
-                            <property name="yalign">0</property>
-                            <property name="wrap">True</property>
-                            <property name="selectable">True</property>
-                          </object>
-                          <packing>
-                            <property name="expand">True</property>
-                            <property name="fill">True</property>
-                            <property name="position">0</property>
-                          </packing>
-                        </child>
-                        <child>
-                          <object class="GtkButton">
-                            <property name="visible">True</property>
-                            <property name="label" translatable="yes">Set to Default</property>
-                            <property name="can_focus">True</property>
-                            <property name="valign">end</property>
-                            <property name="receives_default">True</property>
-                            <property name="action_name">win.set-default</property>
-                          </object>
-                          <packing>
-                            <property name="expand">False</property>
-                            <property name="fill">True</property>
-                            <property name="position">1</property>
-                          </packing>
-                        </child>
-                      </object>
-                      <packing>
-                        <property name="left_attach">1</property>
-                        <property name="top_attach">4</property>
-                        <property name="width">1</property>
-                        <property name="height">1</property>
-                      </packing>
-                    </child>
+                    <property name="activate-on-single-click">True</property>
+                    <property name="selection-mode">browse</property><!-- permits to not have an item 
selected -->
+                    <signal name="row-activated" handler="row_activated_cb"/>
                   </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">True</property>
-                    <property name="pack_type">end</property>
-                    <property name="position">0</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkSeparator">
-                    <property name="orientation">horizontal</property>
-                    <property name="visible">True</property>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">False</property>
-                    <property name="position">2</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkScrolledWindow" id="key_scrolledwindow">
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <child>
-                      <placeholder/>
-                    </child>
-                  </object>
-                  <packing>
-                    <property name="expand">True</property>
-                    <property name="fill">True</property>
-                    <property name="position">1</property>
-                  </packing>
                 </child>
               </object>
-              <packing>
-                <property name="resize">True</property>
-                <property name="shrink">False</property>
-              </packing>
             </child>
           </object>
           <packing>
diff --git a/editor/dconf-model.vala b/editor/dconf-model.vala
index 21f8af7..ff35303 100644
--- a/editor/dconf-model.vala
+++ b/editor/dconf-model.vala
@@ -23,6 +23,12 @@ public class Key : GLib.Object
 
     public string name;
     public string full_name;
+    public string cool_text_value ()   // TODO better
+    {
+        // TODO number of chars after coma for double
+        // bool is the only type that permits translation; keep strings for translators
+        return type_string == "b" ? (value.get_boolean () ? _("True") : _("False")) : value.print (false);
+    }
 
     public SchemaKey? schema;
 
@@ -31,11 +37,6 @@ public class Key : GLib.Object
         get { return schema != null; }
     }
 
-    public int index
-    {
-        get { return parent.keys.index (this); }
-    }
-
     public string type_string
     {
        private set {}
@@ -132,10 +133,8 @@ public class Key : GLib.Object
     }
 
     public void set_to_default()
+        requires (has_schema)
     {
-        if (!has_schema)
-            return;
-
         value = null;
     }
 
@@ -154,15 +153,13 @@ public class Directory : GLib.Object
 
     public Directory? parent;
 
-    private KeyModel _key_model;
-    public KeyModel key_model
+    private GLib.ListStore _key_model;
+    public GLib.ListStore key_model
     {
         get {
             update_children ();
             if (_key_model == null)
-            {
-                _key_model = new KeyModel (this);
-            }
+                _key_model = new GLib.ListStore (typeof (Key));
             return _key_model;
         }
         private set {}
@@ -182,12 +179,6 @@ public class Directory : GLib.Object
     }
 
     public GLib.HashTable<string, Key> _key_map = new GLib.HashTable<string, Key>(str_hash, str_equal);
-    private GLib.List<Key> _keys = new GLib.List<Key>();
-    public GLib.List<Key> keys
-    {
-        get { update_children(); return _keys; }
-        private set { }
-    }
 
     private bool have_children = false;
 
@@ -220,7 +211,7 @@ public class Directory : GLib.Object
         if (key == null)
         {
             key = new Key (model, this, name, full_name + name);
-            _keys.insert_sorted (key, (a, b) => { return strcmp (((Key) a).name, ((Key) b).name); });
+            key_model.insert_sorted (key, (a, b) => { return strcmp (((Key) a).name, ((Key) b).name); });
             _key_map.insert (name, key);
         }
 
@@ -244,312 +235,18 @@ public class Directory : GLib.Object
         }
     }
 
-    private void update_children()
+    private void update_children ()
     {
-        if (have_children)
+        if (have_children)      // crashes if in the constructor
             return;
         have_children = true;
 
-        string[] items = model.client.list(full_name);
+        string [] items = model.client.list (full_name);
         for (int i = 0; i < items.length; i++)
-        {
-            string item_name = full_name + items[i];
-
-            if (DConf.is_dir(item_name))
-            {
-                string dir_name = items[i][0:-1];
-                get_child(dir_name);
-            }
+            if (DConf.is_dir (full_name + items[i]))
+                get_child (items [i][0:-1]);
             else
-            {
-                get_key(items[i]);
-            }
-        }
-    }
-}
-
-public class KeyModel: GLib.Object, Gtk.TreeModel
-{
-    private Directory directory;
-
-    public KeyModel(Directory directory)
-    {
-        this.directory = directory;
-        foreach (var key in directory.keys)
-            key.value_changed.connect(key_changed_cb); // FIXME: Need to delete this callbacks
-    }
-
-    private void key_changed_cb(Key key)
-    {
-        Gtk.TreeIter iter;
-        if (!get_iter_first(out iter))
-            return;
-
-        do
-        {
-            if(get_key(iter) == key)
-            {
-                row_changed(get_path(iter), iter);
-                return;
-            }
-        } while(iter_next(ref iter));
-    }
-
-    public Gtk.TreeModelFlags get_flags()
-    {
-        return Gtk.TreeModelFlags.LIST_ONLY;
-    }
-
-    public int get_n_columns()
-    {
-        return 3;
-    }
-
-    public Type get_column_type(int index)
-    {
-        if (index == 0)
-            return typeof(Key);
-        else
-            return typeof(string);
-    }
-
-    private void set_iter(ref Gtk.TreeIter iter, Key key)
-    {
-        iter.stamp = 0;
-        iter.user_data = key;
-        iter.user_data2 = key;
-        iter.user_data3 = key;
-    }
-
-    public Key get_key(Gtk.TreeIter iter)
-    {
-        return (Key)iter.user_data;
-    }
-
-    public bool get_iter(out Gtk.TreeIter iter, Gtk.TreePath path)
-    {
-        iter = Gtk.TreeIter();
-
-        if (path.get_depth() != 1)
-            return false;
-
-        return iter_nth_child(out iter, null, path.get_indices()[0]);
-    }
-
-    public Gtk.TreePath? get_path(Gtk.TreeIter iter)
-    {
-        var path = new Gtk.TreePath();
-        path.append_index(get_key(iter).index);
-        return path;
-    }
-
-    public void get_value(Gtk.TreeIter iter, int column, out Value value)
-    {
-        Key key = get_key(iter);
-
-        if (column == 0)
-            value = key;
-        else if (column == 1)
-            value = key.name;
-        else if (column == 2)
-            value = key.value != null ? key.value.print(false) : "";
-        else if (column == 4)
-            value = key.is_default ? Pango.Weight.NORMAL : Pango.Weight.BOLD;
-        else
-            value = 0;
-    }
-
-    public bool iter_next(ref Gtk.TreeIter iter)
-    {
-        int index = get_key(iter).index;
-        if (index >= directory.keys.length() - 1)
-            return false;
-        set_iter(ref iter, directory.keys.nth_data(index+1));
-        return true;
-    }
-
-    public bool iter_children(out Gtk.TreeIter iter, Gtk.TreeIter? parent)
-    {
-        iter = Gtk.TreeIter();
-
-        if (parent != null || directory.keys.length() == 0)
-            return false;
-        set_iter(ref iter, directory.keys.nth_data(0));
-
-        return true;
-    }
-
-    public bool iter_has_child(Gtk.TreeIter iter)
-    {
-        return false;
-    }
-
-    public int iter_n_children(Gtk.TreeIter? iter)
-    {
-        if (iter == null)
-            return (int)directory.keys.length();
-        else
-            return 0;
-    }
-
-    public bool iter_nth_child(out Gtk.TreeIter iter, Gtk.TreeIter? parent, int n)
-    {
-        iter = Gtk.TreeIter();
-
-        if (parent != null)
-            return false;
-
-        if (n >= directory.keys.length())
-            return false;
-        set_iter(ref iter, directory.keys.nth_data(n));
-        return true;
-    }
-
-    public bool iter_parent(out Gtk.TreeIter iter, Gtk.TreeIter child)
-    {
-        iter = Gtk.TreeIter();
-        return false;
-    }
-
-    public void ref_node(Gtk.TreeIter iter)
-    {
-        get_key(iter).ref();
-    }
-
-    public void unref_node(Gtk.TreeIter iter)
-    {
-        get_key(iter).unref();
-    }
-}
-
-public class EnumModel: GLib.Object, Gtk.TreeModel
-{
-    private SchemaEnum schema_enum;
-
-    public EnumModel(SchemaEnum schema_enum)
-    {
-        this.schema_enum = schema_enum;
-    }
-
-    public Gtk.TreeModelFlags get_flags()
-    {
-        return Gtk.TreeModelFlags.LIST_ONLY;
-    }
-
-    public int get_n_columns()
-    {
-        return 2;
-    }
-
-    public Type get_column_type(int index)
-    {
-        if (index == 0)
-            return typeof(string);
-        else
-            return typeof(int);
-    }
-
-    private void set_iter(ref Gtk.TreeIter iter, SchemaValue value)
-    {
-        iter.stamp = 0;
-        iter.user_data = value;
-        iter.user_data2 = value;
-        iter.user_data3 = value;
-    }
-
-    public SchemaValue get_enum_value(Gtk.TreeIter iter)
-    {
-        return (SchemaValue)iter.user_data;
-    }
-
-    public bool get_iter(out Gtk.TreeIter iter, Gtk.TreePath path)
-    {
-        iter = Gtk.TreeIter();
-
-        if (path.get_depth() != 1)
-            return false;
-
-        return iter_nth_child(out iter, null, path.get_indices()[0]);
-    }
-
-    public Gtk.TreePath? get_path(Gtk.TreeIter iter)
-    {
-        var path = new Gtk.TreePath();
-        path.append_index((int)get_enum_value(iter).index);
-        return path;
-    }
-
-    public void get_value(Gtk.TreeIter iter, int column, out Value value)
-    {
-        if (column == 0)
-            value = get_enum_value(iter).nick;
-        else if (column == 1)
-            value = get_enum_value(iter).value;
-        else
-            value = 0;
-    }
-
-    public bool iter_next(ref Gtk.TreeIter iter)
-    {
-        uint index = get_enum_value(iter).index;
-        if (index >= schema_enum.values.length () - 1)
-            return false;
-        set_iter(ref iter, schema_enum.values.nth_data(index + 1));
-        return true;
-    }
-
-    public bool iter_children(out Gtk.TreeIter iter, Gtk.TreeIter? parent)
-    {
-        iter = Gtk.TreeIter();
-
-        if (parent != null || schema_enum.values.length() == 0)
-            return false;
-
-        set_iter(ref iter, schema_enum.values.nth_data(0));
-
-        return true;
-    }
-
-    public bool iter_has_child(Gtk.TreeIter iter)
-    {
-        return false;
-    }
-
-    public int iter_n_children(Gtk.TreeIter? iter)
-    {
-        if (iter == null)
-            return (int) schema_enum.values.length();
-        else
-            return 0;
-    }
-
-    public bool iter_nth_child(out Gtk.TreeIter iter, Gtk.TreeIter? parent, int n)
-    {
-        iter = Gtk.TreeIter();
-
-        if (parent != null)
-            return false;
-
-        if (n >= schema_enum.values.length())
-            return false;
-        set_iter(ref iter, schema_enum.values.nth_data(n));
-        return true;
-    }
-
-    public bool iter_parent(out Gtk.TreeIter iter, Gtk.TreeIter child)
-    {
-        iter = Gtk.TreeIter();
-        return false;
-    }
-
-    public void ref_node(Gtk.TreeIter iter)
-    {
-        get_enum_value(iter).ref();
-    }
-
-    public void unref_node(Gtk.TreeIter iter)
-    {
-        get_enum_value(iter).unref();
+                get_key (items [i]);
     }
 }
 
@@ -564,7 +261,9 @@ public class SettingsModel: GLib.Object, Gtk.TreeModel
 
     void watch_func (DConf.Client client, string path, string[] items, string? tag) {
         foreach (var item in items)
+        {   // don't remove that!
             item_changed (path + item);
+        }
     }
 
     public SettingsModel()
diff --git a/editor/dconf-view.vala b/editor/dconf-view.vala
index 839961a..d059d0e 100644
--- a/editor/dconf-view.vala
+++ b/editor/dconf-view.vala
@@ -15,52 +15,75 @@
   along with Dconf Editor.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-private class KeyValueRenderer: Gtk.CellRenderer
+using Gtk;
+
+[GtkTemplate (ui = "/ca/desrt/dconf-editor/ui/key-editor.ui")]
+private class KeyEditor : Dialog
 {
-    private DConfKeyView view;
-    private Gtk.CellRendererText text_renderer;
-    private Gtk.CellRendererSpin spin_renderer;
-    private Gtk.CellRendererToggle toggle_renderer;
-    private Gtk.CellRendererCombo combo_renderer;
-
-    private Key _key;
-    public Key key
+    [GtkChild] private Label schema_label;
+    [GtkChild] private Label summary_label;
+    [GtkChild] private Label description_label;
+    [GtkChild] private Label type_label;
+    [GtkChild] private Label default_label;
+
+    [GtkChild] private Button button_apply;
+    [GtkChild] private Switch custom_value_switch;
+    [GtkChild] private Grid custom_value_grid;
+
+    private Key key;
+    private bool custom_value_is_valid = true;
+
+    public KeyEditor (Key _key)
+        requires (_key.has_schema)
     {
-        get { return _key; }
-        set
-        {
-            _key = value;
+        Object (use_header_bar: Gtk.Settings.get_default ().gtk_dialogs_use_header ? 1 : 0);
 
-            if (key.has_schema && key.schema.choices != null)
-            {
-                combo_renderer.text = key.value.print(false);
-                var model = new Gtk.ListStore(2, typeof(string), typeof(string));
-                foreach (var choice in key.schema.choices)
-                {
-                    Gtk.TreeIter iter;
-                    model.append(out iter);
-                    model.set(iter, 0, choice.name, 1, choice.value.print(false), -1);
-                }
-                combo_renderer.model = model;
-                mode = Gtk.CellRendererMode.EDITABLE;
-                return;
-            }
+        this.key = _key;
 
-            switch (key.type_string)
-            {
+        // infos
+        this.title = key.name;
+        if (this.use_header_bar == 1)        // TODO else..?
+            ((HeaderBar) this.get_header_bar ()).subtitle = key.parent.full_name;       // TODO 
get_header_bar() is [transfer none]
+
+        string? gettext_domain = key.schema.gettext_domain;
+
+        string summary = key.schema.summary ?? "";
+        if (gettext_domain != null && summary != "")
+            summary = dgettext (gettext_domain, summary);
+
+        string description = key.schema.description ?? "";
+        if (gettext_domain != null && description != "")
+            description = dgettext (gettext_domain, description);
+
+        schema_label.set_text (key.schema.schema.id);
+        summary_label.set_text (summary.strip ());
+        description_label.set_text (description.strip ());
+        type_label.set_text (key_to_description ());
+        default_label.set_text (key.schema.default_value.print (false));
+
+        // widgets creation
+
+        custom_value_switch.set_active (key.is_default);
+        custom_value_switch.notify["active"].connect (() => { button_apply.set_sensitive 
(custom_value_switch.get_active () ? true : custom_value_is_valid); });
+
+        custom_value_grid.add (create_child ());
+
+        this.response.connect (response_cb);
+    }
+
+    private KeyEditorChild create_child ()
+    {
+        if (key.schema.choices != null)
+            return new KeyEditorChildChoices (key);
+
+        switch (key.type_string)
+        {
             case "<enum>":
-                combo_renderer.text = key.value.get_string();
-                combo_renderer.model = new 
EnumModel(key.schema.schema.list.enums.lookup(key.schema.enum_name));
-                mode = Gtk.CellRendererMode.EDITABLE;
-                break;
+                return new KeyEditorChildEnum (key);
             case "b":
-                toggle_renderer.active = key.value.get_boolean();
-                mode = Gtk.CellRendererMode.ACTIVATABLE;
-                break;
+                return new KeyEditorChildBool (key.value.get_boolean ());
             case "s":
-                text_renderer.text = key.value.get_string();
-                mode = Gtk.CellRendererMode.EDITABLE;
-                break;
+                return new KeyEditorChildString (key.value.get_string ());
             case "y":
             case "n":
             case "q":
@@ -69,101 +92,18 @@ private class KeyValueRenderer: Gtk.CellRenderer
             case "x":
             case "t":
             case "d":
-                spin_renderer.text = key.value.print(false);
-                var v = get_variant_as_double(key.value);
-                double min = 0.0, max = 0.0;
-                if (key.has_schema && key.schema.range != null)
-                {
-                    min = get_variant_as_double(key.schema.range.min);
-                    max = get_variant_as_double(key.schema.range.max);
-                }
-                else
-                {
-                    min = get_variant_as_double(key.get_min());
-                    max = get_variant_as_double(key.get_max());
-                }
-                spin_renderer.adjustment = new Gtk.Adjustment(v, min, max, 1, 0, 0);
-                spin_renderer.digits = 0;
-                if (key.type_string == "d")
-                {
-                    spin_renderer.digits = 20;
-                }
-                mode = Gtk.CellRendererMode.EDITABLE;
-                break;
+                return new KeyEditorChildNumber (key);
             default:
-                text_renderer.text = key.value.print(false);
-                mode = Gtk.CellRendererMode.EDITABLE;
-                break;
-            }
-        }
-    }
-
-    private static double get_variant_as_double(Variant value)
-    {
-        if (value == null)
-            return 0.0;
-
-        switch (value.classify ())
-        {
-        case Variant.Class.BYTE:
-            return (double)value.get_byte();
-        case Variant.Class.INT16:
-            return (double)value.get_int16();
-        case Variant.Class.UINT16:
-            return (double)value.get_uint16();
-        case Variant.Class.INT32:
-            return (double)value.get_int32();
-        case Variant.Class.UINT32:
-            return (double)value.get_uint32();
-        case Variant.Class.INT64:
-            return (double)value.get_int64();
-        case Variant.Class.UINT64:
-            return (double)value.get_uint64();
-        case Variant.Class.DOUBLE:
-            return value.get_double();
-        default:
-            return 0.0;
+                KeyEditorChildDefault key_editor_child_default = new KeyEditorChildDefault (key.type_string, 
key.value);
+                key_editor_child_default.is_valid.connect ((is_valid) => { custom_value_is_valid = is_valid; 
button_apply.set_sensitive (is_valid); });
+                return key_editor_child_default;
         }
     }
 
-    public KeyValueRenderer(DConfKeyView view)
+    private string key_to_description ()
     {
-        this.view = view;
-
-        text_renderer = new Gtk.CellRendererText();
-        text_renderer.editable = true;
-        text_renderer.edited.connect(text_edited_cb);
-
-        spin_renderer = new Gtk.CellRendererSpin();
-        spin_renderer.editable = true;
-        spin_renderer.edited.connect(spin_edited_cb);
-
-        toggle_renderer = new Gtk.CellRendererToggle();
-        toggle_renderer.xalign = 0f;
-        toggle_renderer.activatable = true;
-        toggle_renderer.toggled.connect(toggle_cb);
-
-        combo_renderer = new Gtk.CellRendererCombo();
-        combo_renderer.has_entry = false;
-        combo_renderer.text_column = 0;
-        combo_renderer.editable = true;
-        combo_renderer.edited.connect(text_edited_cb);
-    }
-
-    private Gtk.CellRenderer renderer
-    {
-        set {}
-        get
+        switch (key.type_string)
         {
-            if (key.has_schema && key.schema.choices != null)
-                return combo_renderer;
-
-            switch (key.type_string)
-            {
-            case "<enum>":
-                return combo_renderer;
-            case "b":
-                return toggle_renderer;
             case "y":
             case "n":
             case "q":
@@ -171,166 +111,342 @@ private class KeyValueRenderer: Gtk.CellRenderer
             case "u":
             case "x":
             case "t":
+                Variant min, max;
+                if (key.schema.range != null)
+                {
+                    min = key.schema.range.min;
+                    max = key.schema.range.max;
+                }
+                else
+                {
+                    min = key.get_min ();
+                    max = key.get_max ();
+                }
+                return _("Integer [%s..%s]").printf (min.print (false), max.print (false));
             case "d":
-                return spin_renderer;
-            default:
+                Variant min, max;
+                if (key.schema.range != null)
+                {
+                    min = key.schema.range.min;
+                    max = key.schema.range.max;
+                }
+                else
+                {
+                    min = key.get_min ();
+                    max = key.get_max ();
+                }
+                return _("Double [%s..%s]").printf (min.print (false), max.print (false));
+            case "b":
+                return _("Boolean");
             case "s":
-                return text_renderer;
-            }
+                return _("String");
+            case "<enum>":
+                return _("Enumeration");
+            default:
+                return key.schema.type;
         }
     }
 
-    public override void get_size(Gtk.Widget     widget,
-                                  Gdk.Rectangle? cell_area,
-                                  out int        x_offset,
-                                  out int        y_offset,
-                                  out int        width,
-                                  out int        height)
+    private void response_cb (Dialog dialog, int response_id)
     {
-        renderer.get_size(widget, cell_area, out x_offset, out y_offset, out width, out height);
+        if (response_id == ResponseType.APPLY)
+        {
+            if (!custom_value_switch.active)
+            {
+                Variant variant = ((KeyEditorChild) custom_value_grid.get_child_at (0, 0)).get_variant ();
+                if (key.is_default || key.value != variant)
+                    key.value = variant;
+            }
+            else if (!key.is_default)
+                key.set_to_default ();
+        }
+        this.destroy ();
     }
+}
 
-    public override void get_preferred_width(Gtk.Widget widget,
-                                             out int    minimum_size,
-                                             out int    natural_size)
+public interface KeyEditorChild : Widget
+{
+    public abstract Variant get_variant ();
+}
+
+private class KeyEditorChildMulti : Grid, KeyEditorChild
+{
+    private static const string ACTION_NAME = "key_value";
+    private static const string GROUP_PREFIX = "bool_switch";
+
+    private SimpleAction action;
+    private VariantType variant_type;
+
+    private Grid grid;
+    private MenuButton button;
+    private Popover popover;
+
+    public KeyEditorChildMulti ()
     {
-        renderer.get_preferred_width(widget, out minimum_size, out natural_size);
-    }
+        this.visible = true;
+        this.hexpand = true;
+
+        Label label = new Label (_("Custom Value"));
+        label.visible = true;
+        label.halign = Align.START;
+        label.hexpand = true;
+        this.attach (label, 0, 0, 1, 1);
+
+        button = new MenuButton ();
+        button.visible = true;
+        button.use_popover = true;
+        button.halign = Align.END;
+        button.width_request = 100;
+        this.attach (button, 1, 0, 1, 1);
+
+        popover = new Popover (button);
+        button.set_popover (popover);
 
-    public override void get_preferred_height_for_width(Gtk.Widget widget,
-                                                        int        width,
-                                                        out int    minimum_height,
-                                                        out int    natural_height)
+        grid = new Grid ();
+        grid.orientation = Orientation.VERTICAL;
+        grid.visible = true;
+        grid.row_homogeneous = true;
+        // grid.width_request = 100;
+        popover.add (grid);
+    }
+    protected void init (VariantType _type, Variant initial_value)
     {
-        renderer.get_preferred_height_for_width(widget, width, out minimum_height, out natural_height);
+        variant_type = _type;
+        set_text (initial_value);
+
+        action = new SimpleAction.stateful (ACTION_NAME, variant_type, initial_value);
+        SimpleActionGroup group = new SimpleActionGroup ();
+        ((ActionMap) group).add_action (action);
+        grid.insert_action_group (GROUP_PREFIX, group);
+
+        group.action_state_changed [ACTION_NAME].connect ((unknown_string, variant) => {
+                set_text (variant);
+                popover.closed ();
+            });
     }
 
-    public override void get_preferred_height(Gtk.Widget widget,
-                                              out int    minimum_size,
-                                              out int    natural_size)
+    private void set_text (Variant variant)
     {
-        renderer.get_preferred_height(widget, out minimum_size, out natural_size);
+        button.label = variant_type == VariantType.STRING ? variant.get_string () : variant.print (false);
     }
 
-    public override void get_preferred_width_for_height(Gtk.Widget widget,
-                                                        int        height,
-                                                        out int    minimum_width,
-                                                        out int    natural_width)
+    protected void add_model_button (string text, Variant variant)
     {
-        renderer.get_preferred_width_for_height(widget, height, out minimum_width, out natural_width);
+        ModelButton button = new ModelButton ();
+        button.visible = true;
+        button.text = text;
+        button.action_name = GROUP_PREFIX + "." + ACTION_NAME;
+        button.action_target = variant;
+        grid.add (button);
     }
 
-    public override void render(Cairo.Context context,
-                                Gtk.Widget    widget,
-                                Gdk.Rectangle background_area,
-                                Gdk.Rectangle cell_area,
-                                Gtk.CellRendererState flags)
+    public Variant get_variant ()
     {
-        renderer.render(context, widget, background_area, cell_area, flags);
+        return action.get_state ();
     }
+}
 
-    public override bool activate(Gdk.Event event,
-                                  Gtk.Widget widget,
-                                  string path,
-                                  Gdk.Rectangle background_area,
-                                  Gdk.Rectangle cell_area,
-                                  Gtk.CellRendererState flags)
+private class KeyEditorChildChoices : KeyEditorChildMulti
+{
+    public KeyEditorChildChoices (Key key)
     {
-        return renderer.activate(event, widget, path, background_area, cell_area, flags);
+        init (VariantType.ANY, key.value);
+
+        foreach (SchemaChoice choice in key.schema.choices)
+            add_model_button (choice.name, choice.value);
     }
+}
 
-    public override unowned Gtk.CellEditable start_editing(Gdk.Event event,
-                                                           Gtk.Widget widget,
-                                                           string path,
-                                                           Gdk.Rectangle background_area,
-                                                           Gdk.Rectangle cell_area,
-                                                           Gtk.CellRendererState flags)
+private class KeyEditorChildEnum : KeyEditorChildMulti
+{
+    public KeyEditorChildEnum (Key key)
     {
-        return renderer.start_editing(event, widget, path, background_area, cell_area, flags);
+        init (VariantType.STRING, key.value);
+
+        SchemaEnum schema_enum = key.schema.schema.list.enums.lookup (key.schema.enum_name);
+        if (schema_enum.values.length () <= 0)
+            assert_not_reached ();  // TODO special case 0?
+//        else if (schema_enum.values.length () == 1)
+//            assert_not_reached ();  // TODO
+
+        for (uint index = 0; index < schema_enum.values.length (); index++)
+        {
+            string nick = schema_enum.values.nth_data (index).nick;  // value.get_string ()); ? 
key.value.get_string () ? key.value.print (false) ? nick ?
+            add_model_button (nick, new Variant.string (nick));
+        }
     }
+}
 
-    private Key get_key_from_path(string path)
+private class KeyEditorChildBool : Grid, KeyEditorChild // might be managed by action, but can't find a way 
to ensure one-and-only-one button is active
+{
+    private ToggleButton button_true;
+
+    public KeyEditorChildBool (bool initial_value)
     {
-        Gtk.TreeIter iter;
-        view.model.get_iter_from_string(out iter, path);
+        this.visible = true;
+        this.hexpand = true;
+
+        Label label = new Label (_("Custom Value"));
+        label.visible = true;
+        label.halign = Align.START;
+        label.hexpand = true;
+        this.attach (label, 0, 0, 1, 1);
+
+        Grid grid = new Grid ();
+        grid.visible = true;
+        grid.halign = Align.END;
+        grid.column_homogeneous = true;
+        grid.width_request = 100;
+        ((StyleContext) grid.get_style_context ()).add_class ("linked");
+        this.attach (grid, 1, 0, 1, 1);
 
-        Key key;
-        view.model.get(iter, 0, out key, -1);
+        ToggleButton button_false = new ToggleButton ();
+        button_false.visible = true;
+        button_false.label = _("False");
+        grid.attach (button_false, 0, 0, 1, 1);
 
-        return key;
+        button_true = new ToggleButton ();
+        button_true.visible = true;
+        button_true.label = _("True");
+        grid.attach (button_true, 1, 0, 1, 1);
+
+        button_true.active = initial_value;
+        button_true.bind_property ("active", button_false, "active", 
BindingFlags.INVERT_BOOLEAN|BindingFlags.SYNC_CREATE|BindingFlags.BIDIRECTIONAL);
     }
 
-    private void toggle_cb(Gtk.CellRendererToggle renderer, string path)
+    public Variant get_variant ()
     {
-        var key = get_key_from_path(path);
-        key.value = new Variant.boolean(!key.value.get_boolean());
+        return new Variant.boolean (button_true.active);
     }
+}
+
+private class KeyEditorChildNumber : Grid, KeyEditorChild
+{
+    private SpinButton spin;
+    private string key_type;
 
-    private void text_edited_cb(Gtk.CellRendererText renderer, string path, string text)
+    public KeyEditorChildNumber (Key key)
     {
-        var key = get_key_from_path(path);
-        if (key.type_string == "s" || key.type_string == "<enum>")
+        this.key_type = key.type_string;
+
+        this.visible = true;
+        this.hexpand = true;
+
+        Label label = new Label (_("Custom Value"));
+        label.visible = true;
+        label.halign = Align.START;
+        label.hexpand = true;
+        this.attach (label, 0, 0, 1, 1);
+
+        bool has_range = /* key.has_schema && */ key.schema.range != null;
+        double min = get_variant_as_double ((has_range && key.schema.range.min != null) ? 
key.schema.range.min : key.get_min ());
+        double max = get_variant_as_double ((has_range && key.schema.range.max != null) ? 
key.schema.range.max : key.get_max ());
+
+        if (key.type_string == "d")
         {
-            key.value = new Variant.string(text);
+            Adjustment adjustment = new Adjustment (key.value.get_double (), min, max, 0.01, 0.1, 0.0);
+            spin = new SpinButton (adjustment, 0.01, 2);
         }
         else
         {
-            try
-            {
-                var value = Variant.parse(new VariantType(key.type_string), text);
-                key.value = value;
-            }
-            catch (VariantParseError e)
-            {
-                var dialog = new Gtk.MessageDialog(null, Gtk.DialogFlags.MODAL, Gtk.MessageType.WARNING, 
Gtk.ButtonsType.OK, _("Error setting value: %s"), e.message);
-                dialog.run();
-                dialog.destroy();
-            }
+            Adjustment adjustment = new Adjustment (get_variant_as_double (key.value), min, max, 1.0, 5.0, 
0.0);
+            spin = new SpinButton (adjustment, 1.0, 0);
         }
+
+        spin.visible = true;
+        spin.update_policy = SpinButtonUpdatePolicy.IF_VALID;
+        spin.snap_to_ticks = true;
+        spin.input_purpose = InputPurpose.NUMBER;   // TODO spin.input_purpose = InputPurpose.DIGITS & 
spin.numeric = true; (no “e”) if not double?
+        spin.width_chars = 30;
+        this.attach (spin, 1, 0, 1, 1);
     }
 
-    private void spin_edited_cb(Gtk.CellRendererText renderer, string path, string text)
+    private static double get_variant_as_double (Variant variant)
+        requires (variant != null)      // TODO is that realllly useful? it shouldn't...
     {
-        var key = get_key_from_path(path);
-        switch (key.type_string)
+        switch (variant.classify ())
         {
-        case "y":
-            key.value = new Variant.byte((uchar)int.parse(text));
-            break;
-        case "n":
-            key.value = new Variant.int16((int16)int.parse(text));
-            break;
-        case "q":
-            key.value = new Variant.uint16((uint16)int.parse(text));
-            break;
-        case "i":
-            key.value = new Variant.int32(int.parse(text));
-            break;
-        case "u":
-            key.value = new Variant.uint32(int.parse(text));
-            break;
-        case "x":
-            key.value = new Variant.int64(int.parse(text));
-            break;
-        case "t":
-            key.value = new Variant.uint64(int.parse(text));
-            break;
-        case "d":
-            key.value = new Variant.double(double.parse(text));
-            break;
+            case Variant.Class.BYTE:    return (double) variant.get_byte ();
+            case Variant.Class.INT16:   return (double) variant.get_int16 ();
+            case Variant.Class.UINT16:  return (double) variant.get_uint16 ();
+            case Variant.Class.INT32:   return (double) variant.get_int32 ();
+            case Variant.Class.UINT32:  return (double) variant.get_uint32 ();
+            case Variant.Class.INT64:   return (double) variant.get_int64 ();
+            case Variant.Class.UINT64:  return (double) variant.get_uint64 ();
+            case Variant.Class.DOUBLE:  return variant.get_double ();
+            default:                    assert_not_reached ();
+        }
+    }
+
+    public Variant get_variant ()
+    {
+        switch (key_type)
+        {
+            case "y": return new Variant.byte   ((uchar) spin.get_value ());
+            case "n": return new Variant.int16  ((int16) spin.get_value ());
+            case "q": return new Variant.uint16 ((uint16) spin.get_value ());
+            case "i": return new Variant.int32  ((int) spin.get_value ());
+            case "u": return new Variant.uint32 ((int) spin.get_value ());
+            case "x": return new Variant.int64  ((int) spin.get_value ());
+            case "t": return new Variant.uint64 ((int) spin.get_value ());
+            case "d": return new Variant.double (spin.get_value ());
+            default : assert_not_reached ();
         }
     }
 }
 
-public class DConfKeyView : Gtk.TreeView
+private class KeyEditorChildString : Entry, KeyEditorChild
 {
-    public DConfKeyView()
+    public KeyEditorChildString (string _text)
+    {
+        this.visible = true;
+        this.hexpand = true;
+        this.text = _text;
+    }
+
+    public Variant get_variant ()
+    {
+        return new Variant.string (this.text);
+    }
+}
+
+private class KeyEditorChildDefault : Entry, KeyEditorChild
+{
+    public signal void is_valid (bool is_valid);
+
+    private string variant_type;
+    private Variant variant;
+
+    public KeyEditorChildDefault (string type, Variant initial_value)
+    {
+        this.variant_type = type;
+        this.variant = initial_value;
+
+        this.visible = true;
+        this.hexpand = true;
+        this.text = initial_value.print (false);
+
+        this.buffer.deleted_text.connect (test_value);
+        this.buffer.inserted_text.connect (test_value);
+        test_value ();
+    }
+
+    private void test_value ()
+    {
+        try
+        {
+            Variant? tmp_variant = Variant.parse (new VariantType (variant_type), this.text);
+            variant = tmp_variant;
+            is_valid (true);
+        }
+        catch (VariantParseError e)
+        {
+            is_valid (false);
+        }
+    }
+
+    public Variant get_variant ()
     {
-        /* Translators: this is the column header label in the main view */
-        var column = new Gtk.TreeViewColumn.with_attributes(_("Name"), new Gtk.CellRendererText(), "text", 
1, "weight", 4, null);
-        /*column.set_sort_column_id(1);*/
-        append_column(column);
-        /* Translators: this is the column header label in the main view */
-        insert_column_with_attributes(-1, _("Value"), new KeyValueRenderer(this), "key", 0, null);
+        return variant;
     }
 }
diff --git a/editor/dconf-window.vala b/editor/dconf-window.vala
index 36c44e9..b211ec5 100644
--- a/editor/dconf-window.vala
+++ b/editor/dconf-window.vala
@@ -23,49 +23,14 @@ class DConfWindow : ApplicationWindow
     private SettingsModel model;
     [GtkChild] private TreeView dir_tree_view;
     [GtkChild] private TreeSelection dir_tree_selection;
+    [GtkChild] private ListBox key_list_box;
 
     [GtkChild] private Box search_box;
     [GtkChild] private Entry search_entry;
     [GtkChild] private Label search_label;
 
-    private TreeView key_tree_view;
-    [GtkChild]
-    private ScrolledWindow key_scrolledwindow;  // TODO used only for adding key_tree_view, a pseudo-TreeView
-
-    [GtkChild]
-    private Grid key_info_grid;
-    [GtkChild]
-    private Label schema_label;
-    [GtkChild]
-    private Label summary_label;
-    [GtkChild]
-    private Label description_label;
-    [GtkChild]
-    private Label type_label;
-    [GtkChild]
-    private Label default_label;
-
-    private Key? selected_key;
-
-    private const GLib.ActionEntry[] window_actions =
-    {
-        { "set-default", set_default_cb }
-    };
-    private SimpleAction set_default_action;
-
     public DConfWindow ()
     {
-        add_action_entries (window_actions, this);
-        set_default_action = (SimpleAction) lookup_action ("set-default");
-        set_default_action.set_enabled (false);
-
-        /* key tree */
-        key_tree_view = new DConfKeyView ();
-        key_tree_view.show ();
-        key_tree_view.get_selection ().changed.connect (key_selected_cb);
-        key_scrolledwindow.add (key_tree_view);
-
-        /* dir tree */
         model = new SettingsModel ();
         dir_tree_view.set_model (model);
 
@@ -81,140 +46,36 @@ class DConfWindow : ApplicationWindow
     [GtkCallback]
     private void dir_selected_cb ()
     {
-        KeyModel? key_model = null;
+        GLib.ListStore? key_model = null;
 
         TreeIter iter;
         if (dir_tree_selection.get_selected (null, out iter))
             key_model = model.get_directory (iter).key_model;
 
-        key_tree_view.set_model (key_model);
-
-        /* Always select something */
-        if (key_model != null && key_model.get_iter_first (out iter))
-            key_tree_view.get_selection ().select_iter (iter);
+        key_list_box.bind_model (key_model, new_list_box_row);
     }
 
     /*\
-    * * Key TreeView & informations
+    * * Key ListBox
     \*/
 
-    private string key_to_description (Key key)
+    private Widget new_list_box_row (Object item)
     {
-        switch (key.type_string)
+        Key key = (Key) item;
+        if (key.has_schema)
         {
-        case "y":
-        case "n":
-        case "q":
-        case "i":
-        case "u":
-        case "x":
-        case "t":
-            Variant min, max;
-            if (key.schema.range != null)
-            {
-                min = key.schema.range.min;
-                max = key.schema.range.max;
-            }
-            else
-            {
-                min = key.get_min ();
-                max = key.get_max ();
-            }
-            return _("Integer [%s..%s]").printf (min.print (false), max.print (false));
-        case "d":
-            Variant min, max;
-            if (key.schema.range != null)
-            {
-                min = key.schema.range.min;
-                max = key.schema.range.max;
-            }
-            else
-            {
-                min = key.get_min ();
-                max = key.get_max ();
-            }
-            return _("Double [%s..%s]").printf (min.print (false), max.print (false));
-        case "b":
-            return _("Boolean");
-        case "s":
-            return _("String");
-        case "<enum>":
-            return _("Enumeration");
-        default:
-            return key.schema.type;
-        }
-    }
-
-    private void key_selected_cb ()
-    {
-        if (selected_key != null)
-            selected_key.value_changed.disconnect (key_changed_cb);
-
-        TreeIter iter;
-        TreeModel model;
-        if (key_tree_view.get_selection ().get_selected (out model, out iter))
-        {
-            var key_model = (KeyModel) model;
-            selected_key = key_model.get_key (iter);
+            KeyListBoxRowEditable key_list_box_row = new KeyListBoxRowEditable (key);
+            key.value_changed.connect (() => { key_list_box_row.update (); });
+            return key_list_box_row;
         }
         else
-            selected_key = null;
-
-        if (selected_key != null)
-            selected_key.value_changed.connect (key_changed_cb);
-
-        key_info_grid.sensitive = selected_key != null;
-        set_default_action.set_enabled (selected_key != null && !selected_key.is_default);
-
-        string schema_name = "", summary = "", description = "", type = "", default_value = "";
-
-        if (selected_key != null)
-        {
-            if (selected_key.schema != null)
-            {
-                var gettext_domain = selected_key.schema.gettext_domain;
-                schema_name = selected_key.schema.schema.id;
-
-                if (selected_key.schema.summary != null)
-                    summary = selected_key.schema.summary;
-                if (gettext_domain != null && summary != "")
-                    summary = dgettext (gettext_domain, summary);
-
-                if (selected_key.schema.description != null)
-                    description = selected_key.schema.description;
-                if (gettext_domain != null && description != "")
-                    description = dgettext (gettext_domain, description);
-
-                type = key_to_description (selected_key);
-                default_value = selected_key.schema.default_value.print (false);
-            }
-            else
-            {
-                schema_name = _("No schema");
-            }
-        }
-
-        schema_label.set_text (schema_name);
-        summary_label.set_text (summary.strip ());
-        description_label.set_text (description.strip ());
-        type_label.set_text (type);
-        default_label.set_text (default_value);
-    }
-
-    /*\
-    * * Set_default button
-    \*/
-
-    private void key_changed_cb (Key key)   /* TODO reuse */
-    {
-        set_default_action.set_enabled (selected_key != null && !selected_key.is_default);
+            return new KeyListBoxRowNonEditable (key.name, key.cool_text_value ());
     }
 
-    private void set_default_cb ()
+    [GtkCallback]
+    private void row_activated_cb (ListBoxRow list_box_row)
     {
-        if (selected_key == null)
-            return;
-        selected_key.set_to_default ();
+        ((KeyListBoxRow) list_box_row.get_child ()).show_dialog (this);
     }
 
     /*\
@@ -249,66 +110,57 @@ class DConfWindow : ApplicationWindow
     {
         search_label.label = "";
 
-        /* Get the current position in the tree */
         TreeIter iter;
-        TreeIter key_iter = TreeIter ();
-        bool have_key_iter = false;
+        int position = 0;
         if (dir_tree_selection.get_selected (null, out iter))
         {
-            if (key_tree_view.get_selection ().get_selected (null, out key_iter))
-            {
-                var dir = model.get_directory (iter);
-                if (dir.key_model.iter_next (ref key_iter))
-                    have_key_iter = true;
-                else
-                    get_next_iter (ref iter);
-            }
+            ListBoxRow? selected_row = (ListBoxRow) key_list_box.get_selected_row ();
+            if (selected_row != null)
+                position = selected_row.get_index () + 1;
         }
-        else if (!model.get_iter_first (out iter))
-            return;
+        else if (!model.get_iter_first (out iter))      // TODO doesn't that reset iter?
+            return;     // TODO better
 
         bool on_first_directory = true;
         do
         {
-            /* Select next directory that matches */
             Directory dir = model.get_directory (iter);
-            if (!have_key_iter)
+
+            if (!on_first_directory && dir.name.index_of (search_entry.text) >= 0)
             {
-                have_key_iter = dir.key_model.get_iter_first (out key_iter);
-                if (!on_first_directory && dir.name.index_of (search_entry.text) >= 0)
-                {
-                    dir_tree_view.expand_to_path (model.get_path (iter));
-                    dir_tree_selection.select_iter (iter);
-                    dir_tree_view.scroll_to_cell (model.get_path (iter), null, false, 0, 0);
-                    return;
-                }
+                select_dir (iter);
+                return;
             }
             on_first_directory = false;
 
             /* Select next key that matches */
-            if (have_key_iter)
+            GLib.ListStore key_model = dir.key_model;
+            while (position < key_model.get_n_items ())
             {
-                do
+                Key key = (Key) key_model.get_object (position);
+                if (key_matches (key, search_entry.text))
                 {
-                    var key = dir.key_model.get_key (key_iter);
-                    if (key_matches (key, search_entry.text))
-                    {
-                        dir_tree_view.expand_to_path (model.get_path (iter));
-                        dir_tree_selection.select_iter (iter);
-                        dir_tree_view.scroll_to_cell (model.get_path (iter), null, false, 0, 0);
-                        key_tree_view.get_selection ().select_iter (key_iter);
-                        key_tree_view.scroll_to_cell (dir.key_model.get_path (key_iter), null, false, 0, 0);
-                        return;
-                    }
-                } while (dir.key_model.iter_next (ref key_iter));
+                    select_dir (iter);
+                    key_list_box.select_row (key_list_box.get_row_at_index (position));
+                    return;
+                }
+                position++;
             }
-            have_key_iter = false;
+
+            position = 0;
         }
         while (get_next_iter (ref iter));
 
         search_label.label = _("Not found");
     }
 
+    private void select_dir (TreeIter iter)
+    {
+        dir_tree_view.expand_to_path (model.get_path (iter));
+        dir_tree_selection.select_iter (iter);
+        dir_tree_view.scroll_to_cell (model.get_path (iter), null, false, 0, 0);
+    }
+
     private bool key_matches (Key key, string text)
     {
         /* Check key name */
@@ -316,7 +168,7 @@ class DConfWindow : ApplicationWindow
             return true;
 
         /* Check key schema (description) */
-        if (key.schema != null)
+        if (key.has_schema)
         {
             if (key.schema.summary != null && key.schema.summary.index_of (text) >= 0)
                 return true;
@@ -351,3 +203,70 @@ class DConfWindow : ApplicationWindow
         return true;
     }
 }
+
+[GtkTemplate (ui = "/ca/desrt/dconf-editor/ui/key-list-box-row.ui")]
+private abstract class KeyListBoxRow : Grid
+{
+    [GtkChild] protected Label key_name_label;
+    [GtkChild] protected Label key_value_label;
+    [GtkChild] protected Label key_info_label;
+
+    public abstract void show_dialog (ApplicationWindow window);
+}
+
+private class KeyListBoxRowNonEditable : KeyListBoxRow
+{
+    public KeyListBoxRowNonEditable (string key_name, string key_value)
+    {
+        key_name_label.label = key_name;
+        key_value_label.label = key_value;
+        key_info_label.set_markup ("<i>" + _("No Schema") + "</i>");
+    }
+
+    public override void show_dialog (ApplicationWindow window)
+    {
+        MessageDialog dialog = new MessageDialog (window, DialogFlags.MODAL, MessageType.WARNING, 
ButtonsType.OK, _("No Schema, cannot edit value."));  // TODO with or without punctuation?        // TODO 
insert key name/path/..?
+        dialog.run ();
+        dialog.destroy ();
+    }
+}
+
+private class KeyListBoxRowEditable : KeyListBoxRow
+{
+    public Key key { get; private set; }
+
+    private Pango.AttrList attr_list = new Pango.AttrList ();
+
+    public KeyListBoxRowEditable (Key _key)
+    {
+        this.key = _key;
+        key_value_label.set_attributes (attr_list);
+        update ();      // sets key_name_label attributes and key_value_label label
+        key_name_label.label = key.name;
+
+        string? summary = key.schema.summary;
+        if (summary == null || summary == "")
+            return;
+
+        string? gettext_domain = key.schema.gettext_domain;
+        if (gettext_domain != null)
+            summary = dgettext (gettext_domain, summary);
+        key_info_label.label = summary.strip ();
+    }
+
+    public void update ()
+    {
+        attr_list.change (Pango.attr_weight_new (key.is_default ? Pango.Weight.NORMAL : Pango.Weight.BOLD)); 
   // TODO good?
+        key_name_label.set_attributes (attr_list);
+        // TODO key_info_label.set_attributes (attr_list); ?
+
+        key_value_label.label = key.cool_text_value ();
+    }
+
+    public override void show_dialog (ApplicationWindow window)
+    {
+        KeyEditor key_editor = new KeyEditor (key);
+        key_editor.set_transient_for (window);
+        key_editor.run ();
+    }
+}
diff --git a/editor/key-editor.ui b/editor/key-editor.ui
new file mode 100644
index 0000000..3401669
--- /dev/null
+++ b/editor/key-editor.ui
@@ -0,0 +1,244 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <!-- interface-requires gtk+ 3.0 -->
+  <template class="KeyEditor" parent="GtkDialog">
+    <property name="visible">False</property>
+    <property name="modal">True</property>
+    <property name="default-height">1</property><!-- TODO bug of GtkDialog, that reserves space for bottom 
buttons -->
+    <property name="default-width">600</property>
+    <property name="width-request">600</property>
+    <property name="resizable">False</property>
+    <property name="title" translatable="yes">Key Editor</property>
+    <child type="action">
+      <object class="GtkButton" id="button-cancel">
+        <property name="visible">True</property>
+        <property name="label" translatable="yes">Cancel</property><!-- TODO _Cancel? -->
+        <property name="width-request">100</property><!-- button_apply is in the same horizontal 
GtkSizeGroup; same width request for custom_value_switch -->
+      </object>
+    </child>
+    <child type="action">
+      <object class="GtkButton" id="button_apply">
+        <property name="visible">True</property>
+        <property name="label" translatable="yes">Apply</property><!-- TODO _Apply? -->
+        <property name="can-default">True</property>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="cancel">button-cancel</action-widget>
+      <action-widget response="apply" default="true">button_apply</action-widget>
+    </action-widgets>
+    <child internal-child="vbox">
+      <object class="GtkBox">
+        <property name="margin">6</property><!-- TODO test -->
+        <child>
+          <object class="GtkGrid">
+            <property name="visible">True</property>
+            <property name="row-spacing">6</property>
+            <property name="column-spacing">6</property>
+            <child>
+              <object class="GtkLabel">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="yalign">0</property>
+                <property name="label" translatable="yes">Schema:</property>
+              </object>
+              <packing>
+                <property name="left-attach">0</property>
+                <property name="top-attach">0</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="yalign">0</property>
+                <property name="label" translatable="yes">Summary:</property>
+              </object>
+              <packing>
+                <property name="left-attach">0</property>
+                <property name="top-attach">1</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="yalign">0</property>
+                <property name="label" translatable="yes">Description:</property>
+              </object>
+              <packing>
+                <property name="left-attach">0</property>
+                <property name="top-attach">2</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="yalign">0</property>
+                <property name="label" translatable="yes" comments="Translators: as in datatype (integer, 
boolean, string, etc)">Type:</property>
+              </object>
+              <packing>
+                <property name="left-attach">0</property>
+                <property name="top-attach">3</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="yalign">0</property>
+                <property name="label" translatable="yes">Default:</property>
+              </object>
+              <packing>
+                <property name="left-attach">0</property>
+                <property name="top-attach">4</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="schema_label">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="yalign">0</property>
+                <property name="wrap">True</property>
+                <property name="selectable">True</property>
+                <property name="can-focus">False</property>
+<!--                <property name="hexpand">True</property> -->
+                <property name="max-width-chars">42</property>
+                <property name="width-chars">42</property>
+              </object>
+              <packing>
+                <property name="left-attach">1</property>
+                <property name="top-attach">0</property>
+                <property name="width">2</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="summary_label">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="yalign">0</property>
+                <property name="wrap">True</property>
+                <property name="selectable">True</property>
+                <property name="can-focus">False</property>
+<!--                <property name="hexpand">True</property> -->
+                <property name="max-width-chars">42</property>
+                <property name="width-chars">42</property>
+              </object>
+              <packing>
+                <property name="left-attach">1</property>
+                <property name="top-attach">1</property>
+                <property name="width">2</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="description_label">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="yalign">0</property>
+                <property name="wrap">True</property>
+                <property name="selectable">True</property>
+                <property name="can-focus">False</property>
+<!--                <property name="hexpand">True</property> -->
+                <property name="max-width-chars">42</property>
+                <property name="width-chars">42</property>
+              </object>
+              <packing>
+                <property name="left-attach">1</property>
+                <property name="top-attach">2</property>
+                <property name="width">2</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="type_label">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="yalign">0</property>
+                <property name="wrap">True</property>
+                <property name="selectable">True</property>
+                <property name="can-focus">False</property>
+<!--                <property name="hexpand">True</property> -->
+                <property name="max-width-chars">42</property>
+                <property name="width-chars">42</property>
+              </object>
+              <packing>
+                <property name="left-attach">1</property>
+                <property name="top-attach">3</property>
+                <property name="width">2</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="default_label">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="yalign">0</property>
+                <property name="wrap">True</property>
+                <property name="selectable">True</property>
+                <property name="can-focus">False</property>
+                <property name="hexpand">True</property>
+                <!--<property name="max-width-chars">42</property>
+                <property name="width-chars">42</property> -->
+              </object>
+              <packing>
+                <property name="left-attach">1</property>
+                <property name="top-attach">4</property>
+                <property name="width">2</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="yalign">0</property>
+                <property name="label" translatable="yes">Use default value</property>
+                <property name="valign">baseline</property>
+              </object>
+              <packing>
+                <property name="left-attach">0</property>
+                <property name="top-attach">5</property>
+                <property name="width">2</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkSwitch" id="custom_value_switch">
+                <property name="visible">True</property>
+                <property name="width-request">100</property><!-- same request than for 
button_cancel/button_apply -->
+                <property name="halign">end</property>
+              </object>
+              <packing>
+                <property name="left-attach">2</property>
+                <property name="top-attach">5</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+          </object>
+        </child>
+        <child>
+          <object class="GtkGrid" id="custom_value_grid">
+            <property name="visible">True</property>
+            <property name="hexpand">True</property>
+            <property name="margin-top">6</property><!-- TODO better -->
+            <property name="sensitive" bind-source="custom_value_switch" bind-property="active" 
bind-flags="sync-create|invert-boolean"/>
+          </object>
+        </child>
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/editor/key-list-box-row.ui b/editor/key-list-box-row.ui
new file mode 100644
index 0000000..45fd9bf
--- /dev/null
+++ b/editor/key-list-box-row.ui
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <!-- interface-requires gtk+ 3.0 -->
+  <template class="KeyListBoxRow" parent="GtkGrid">
+    <property name="visible">True</property>
+    <property name="orientation">horizontal</property>
+    <property name="height-request">42</property>
+    <property name="margin-start">10</property><!-- looks cool -->
+    <property name="column-spacing">6</property>
+    <property name="margin-end">6</property><!-- same as column_spacing -->
+    <child>
+      <object class="GtkLabel" id="key_name_label">
+        <property name="visible">True</property>
+        <property name="xalign">0</property>
+        <property name="vexpand">True</property>
+        <property name="width-request">222</property>
+        <property name="wrap">True</property>
+        <property name="wrap-mode">PANGO_WRAP_WORD_CHAR</property>
+        <property name="halign">start</property>
+        <property name="single-line-mode">True</property>
+      </object>
+    </child>
+    <child>
+      <object class="GtkLabel" id="key_value_label">
+        <property name="visible">True</property>
+        <property name="xalign">0</property>
+        <property name="vexpand">True</property>
+        <property name="width-request">166</property>
+        <property name="wrap">True</property>
+        <property name="wrap-mode">PANGO_WRAP_WORD_CHAR</property>
+        <property name="halign">start</property>
+        <property name="single-line-mode">True</property>
+      </object>
+    </child>
+    <child>
+      <object class="GtkLabel" id="key_info_label">
+        <property name="visible">True</property>
+        <property name="expand">True</property>
+        <property name="wrap">False</property>
+        <property name="halign">start</property>
+        <property name="single-line-mode">True</property>
+        <property name="ellipsize">end</property>
+      </object>
+    </child>
+  </template>
+</interface>


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