[dconf-editor] Relook Bookmarks popover.



commit a920fbb2b80501d80880f82e0ef7fbc0aa571d25
Author: Arnaud Bonatti <arnaud bonatti gmail com>
Date:   Fri Oct 5 13:04:19 2018 +0200

    Relook Bookmarks popover.

 editor/bookmark.ui                                 |  31 +-
 editor/bookmarks.ui                                | 297 +++++++---
 editor/bookmarks.vala                              | 643 ++++++++++++++++++---
 editor/ca.desrt.dconf-editor.gschema.xml           |  10 +-
 editor/dconf-editor.css                            |  78 ++-
 editor/dconf-model.vala                            |  14 +-
 editor/dconf-window.vala                           |  60 +-
 .../ca.desrt.dconf-editor.big-rows-symbolic.svg    |  56 ++
 .../ca.desrt.dconf-editor.small-rows-symbolic.svg  |  84 +++
 editor/pathwidget.vala                             |  10 +-
 10 files changed, 1047 insertions(+), 236 deletions(-)
---
diff --git a/editor/bookmark.ui b/editor/bookmark.ui
index 3c89ae7..1236076 100644
--- a/editor/bookmark.ui
+++ b/editor/bookmark.ui
@@ -3,11 +3,10 @@
   <!-- interface-requires gtk+ 3.0 -->
   <template class="Bookmark" parent="GtkListBoxRow">
     <child>
-      <object class="GtkGrid" id="main_grid">
+      <object class="GtkGrid"> <!-- TODO remove? -->
         <property name="visible">True</property>
         <property name="orientation">horizontal</property>
-        <property name="column-spacing">2</property>
-        <property name="margin-start">8</property>
+        <property name="column-spacing">0</property>
         <style>
           <class name="bookmark"/>
         </style>
@@ -21,32 +20,6 @@
             <property name="ellipsize">PANGO_ELLIPSIZE_START</property>
           </object>
         </child>
-        <child>
-          <object class="GtkButton" id="destroy_button">
-            <property name="visible">True</property>
-            <property name="margin">2</property>
-            <property name="valign">center</property>
-            <property name="vexpand">True</property>
-            <style>
-              <class name="image-button"/>
-              <class name="circular"/>
-              <class name="flat"/>
-            </style>
-            <child internal-child="accessible">
-              <object class="AtkObject">
-                <property name="AtkObject::accessible-name" translatable="yes">Remove</property>
-                <property name="AtkObject::accessible-description" translatable="yes">Remove this 
bookmark</property>
-              </object>
-            </child>
-            <child>
-              <object class="GtkImage">
-                <property name="visible">True</property>
-                <property name="icon-size">1</property>
-                <property name="icon-name">window-close-symbolic</property>
-              </object>
-            </child>
-          </object>
-        </child>
       </object>
     </child>
   </template>
diff --git a/editor/bookmarks.ui b/editor/bookmarks.ui
index 7440647..bab9f8e 100644
--- a/editor/bookmarks.ui
+++ b/editor/bookmarks.ui
@@ -1,106 +1,265 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <interface domain="dconf-editor">
   <!-- interface-requires gtk+ 3.0 -->
+  <object class="GtkImage" id="big_rows_icon">
+    <property name="visible">True</property>
+    <property name="icon-name">ca.desrt.dconf-editor.big-rows-symbolic</property>
+    <property name="icon-size">1</property>
+  </object>
+  <object class="GtkImage" id="small_rows_icon">
+    <property name="visible">True</property>
+    <property name="icon-name">ca.desrt.dconf-editor.small-rows-symbolic</property>
+    <property name="icon-size">1</property>
+  </object>
   <object class="GtkPopover" id="bookmarks_popover">
     <property name="width-request">350</property>
     <property name="height-request">300</property>
+    <signal name="key-press-event" handler="on_key_press_event"/>
     <style>
       <class name="bookmarks"/>
     </style>
     <child>
       <object class="GtkGrid">
         <property name="visible">True</property>
-        <property name="column-spacing">12</property>
-        <property name="row-spacing">0</property>
+        <property name="row-spacing">6</property>
         <property name="margin">4</property>
+        <property name="orientation">vertical</property>
         <child>
-          <object class="GtkLabel" id="switch_label">
-            <property name="visible">True</property>
-            <property name="margin-start">6</property>
-            <property name="halign">start</property>
-          </object>
-          <packing>
-            <property name="left-attach">0</property>
-            <property name="top-attach">0</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkSwitch" id="bookmarked_switch">
+          <object class="GtkStack" id="edit_mode_stack">
             <property name="visible">True</property>
-            <property name="halign">end</property>
-            <property name="action-name">ui.empty</property>
-            <property name="action-target">('',byte 255)</property>
-            <child internal-child="accessible">
-              <object class="AtkObject">
-                <property name="AtkObject::accessible-name" translatable="yes">Location bookmarked</property>
-                <property name="AtkObject::accessible-description" translatable="yes">Toggle to bookmark 
this location</property>
+            <child>
+              <object class="GtkGrid">
+                <property name="visible">True</property>
+                <property name="valign">center</property>
+                <property name="orientation">horizontal</property>
+                <property name="column-spacing">12</property>
+                <child>
+                  <object class="GtkLabel" id="switch_label">
+                    <property name="visible">True</property>
+                    <property name="margin-start">6</property>
+                    <property name="hexpand">True</property>
+                    <property name="halign">start</property>
+                  </object>
+                </child>
+                <child>
+                  <object class="GtkSwitch" id="bookmarked_switch">
+                    <property name="visible">True</property>
+                    <property name="halign">end</property>
+                    <property name="action-name">ui.empty</property>
+                    <property name="action-target">('',byte 255)</property>
+                    <child internal-child="accessible">
+                      <object class="AtkObject">
+                        <property name="AtkObject::accessible-name" translatable="yes">Location 
bookmarked</property>
+                        <property name="AtkObject::accessible-description" translatable="yes">Toggle to 
bookmark this location</property>
+                      </object>
+                    </child>
+                  </object>
+                </child>
               </object>
+              <packing>
+                <property name="name">edit-mode-off</property>
+              </packing>
             </child>
-          </object>
-          <packing>
-            <property name="left-attach">1</property>
-            <property name="top-attach">0</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkScrolledWindow">
-            <property name="visible">True</property>
-            <property name="expand">True</property>
-            <property name="window-placement">top-right</property>
-            <property name="hscrollbar-policy">never</property>
-            <property name="shadow-type">etched-in</property>
-            <property name="max-content-height">300</property>
-            <property name="propagate-natural-width">True</property>
-            <property name="propagate-natural-height">True</property>
-            <style>
-              <class name="margin-top-6px"/>
-            </style>
             <child>
-              <object class="GtkListBox" id="bookmarks_list_box">
+              <object class="GtkGrid">
                 <property name="visible">True</property>
-                <property name="activate-on-single-click">True</property>
-                <child type="placeholder">
-                  <object class="RegistryPlaceholder">
-                    <property name="label" translatable="yes">Bookmarks will
-be added here</property> <!-- line wrap wanted -->
-                    <property name="icon-name">starred-symbolic</property> <!-- or starred-symbolic? or 
dconf-editor-symbolic? -->
-                    <property name="big">False</property>
+                <property name="hexpand">True</property>
+                <property name="valign">center</property>
+                <property name="orientation">horizontal</property>
+                <property name="column-spacing">3</property>
+                <child>
+                  <object class="GtkButton" id="leave_edit_mode_button">
+                    <property name="visible">True</property>
+                    <property name="action-name">bookmarks.leave-edit-mode</property>
+                    <style>
+                      <class name="image-button"/>
+                      <class name="flat"/>
+                    </style>
+                    <child>
+                      <object class="GtkImage">
+                        <property name="visible">True</property>
+                        <property name="icon-name">object-select-symbolic</property>
+                        <property name="icon-size">1</property>
+                      </object>
+                    </child>
                   </object>
                 </child>
+                <child>
+                  <object class="GtkSeparator">
+                    <property name="visible">True</property>
+                    <property name="orientation">vertical</property>
+                  </object>
+                </child>
+                <child>
+                  <object class="GtkButton" id="rows_size_button">
+                    <property name="visible">True</property>
+                    <property name="hexpand">True</property>
+                    <property name="halign">start</property>
+                    <property name="action-name">bookmarks.set-small-rows</property>
+                    <style>
+                      <class name="image-button"/>
+                    </style>
+                  </object>
+                </child>
+                <child>
+                  <object class="GtkBox">
+                    <property name="visible">True</property>
+                    <property name="halign">end</property>
+                    <property name="margin-end">3</property> <!-- grid has already 3 as column spacing -->
+                    <style>
+                      <class name="linked"/>
+                    </style>
+                    <child>
+                      <object class="GtkButton">
+                        <property name="visible">True</property>
+                        <property name="action-name">bookmarks.move-top</property>
+                        <style>
+                          <class name="image-button"/>
+                        </style>
+                        <child>
+                          <object class="GtkImage">
+                            <property name="visible">True</property>
+                            <property name="icon-name">go-top-symbolic</property>
+                            <property name="icon-size">1</property>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkButton">
+                        <property name="visible">True</property>
+                        <property name="action-name">bookmarks.move-up</property>
+                        <style>
+                          <class name="image-button"/>
+                        </style>
+                        <child>
+                          <object class="GtkImage">
+                            <property name="visible">True</property>
+                            <property name="icon-name">go-up-symbolic</property>
+                            <property name="icon-size">1</property>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkButton">
+                        <property name="visible">True</property>
+                        <property name="action-name">bookmarks.move-down</property>
+                        <style>
+                          <class name="image-button"/>
+                        </style>
+                        <child>
+                          <object class="GtkImage">
+                            <property name="visible">True</property>
+                            <property name="icon-name">go-down-symbolic</property>
+                            <property name="icon-size">1</property>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkButton">
+                        <property name="visible">True</property>
+                        <property name="action-name">bookmarks.move-bottom</property>
+                        <style>
+                          <class name="image-button"/>
+                        </style>
+                        <child>
+                          <object class="GtkImage">
+                            <property name="visible">True</property>
+                            <property name="icon-name">go-bottom-symbolic</property>
+                            <property name="icon-size">1</property>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+                <child>
+                  <object class="GtkButton">
+                    <property name="visible">True</property>
+                    <property name="halign">end</property>
+                    <property name="action-name">bookmarks.trash-bookmark</property>
+                    <style>
+                      <class name="image-button"/>
+                    </style>
+                    <child>
+                      <object class="GtkImage">
+                        <property name="visible">True</property>
+                        <property name="icon-name">user-trash-symbolic</property>
+                        <property name="icon-size">1</property>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="name">edit-mode-on</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel">
+                <property name="visible">True</property>
+                <property name="halign">center</property>
+                <property name="label" translatable="yes">The bookmarks list is not editable.</property>
+                <style>
+                  <class name="italic-label"/>
+                </style>
               </object>
+              <packing>
+                <property name="name">edit-mode-disabled</property>
+              </packing>
             </child>
           </object>
-          <packing>
-            <property name="left-attach">0</property>
-            <property name="top-attach">1</property>
-            <property name="width">2</property>
-            <property name="height">1</property>
-          </packing>
         </child>
         <child>
-          <object class="GtkRevealer" id="bookmarks_editable_revealer">
+          <object class="GtkOverlay">
             <property name="visible">True</property>
-            <property name="transition-type">slide-down</property>
-            <property name="transition-duration">300</property>
-            <property name="reveal-child">False</property>
+            <property name="expand">True</property>
+            <property name="valign">fill</property>
             <child>
-              <object class="GtkLabel">
+              <object class="GtkScrolledWindow" id="scrolled">
                 <property name="visible">True</property>
-                <property name="hexpand">True</property>
-                <property name="label" translatable="yes">The bookmarks list is not editable.</property>
+                <property name="expand">True</property>
+                <!-- property name="window-placement">top-right</property -->
+                <property name="hscrollbar-policy">never</property>
+                <property name="shadow-type">etched-in</property>
+                <property name="max-content-height">300</property>
+                <property name="propagate-natural-width">True</property>
+                <property name="propagate-natural-height">True</property>
+                <child>
+                  <object class="GtkListBox" id="bookmarks_list_box">
+                    <property name="visible">True</property>
+                    <signal name="selected-rows-changed" handler="on_selection_changed"/>
+                    <style>
+                      <class name="padding-bottom"/>
+                    </style>
+                    <child type="placeholder">
+                      <object class="RegistryPlaceholder">
+                        <property name="label" translatable="yes">Bookmarks will&#xA;be added here</property>
+                        <property name="icon-name">starred-symbolic</property> <!-- or starred-symbolic? or 
dconf-editor-symbolic? -->
+                        <property name="big">False</property>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+            <child type="overlay">
+              <object class="GtkButton" id="enter_edit_mode_button">
+                <property name="visible">True</property>
+                <property name="halign">center</property>
+                <property name="valign">end</property>
+                <property name="width-request">200</property>
+                <property name="action-name">bookmarks.enter-edit-mode</property>
+                <property name="label" translatable="yes">Edit bookmarks list</property>
                 <style>
-                  <class name="italic-label"/>
-                  <class name="margin-top-6px"/>
+                  <class name="circular"/>
+                  <class name="edit-bookmarks-list"/>
                 </style>
               </object>
             </child>
           </object>
-          <packing>
-            <property name="left-attach">0</property>
-            <property name="top-attach">2</property>
-            <property name="width">2</property>
-            <property name="height">1</property>
-          </packing>
         </child>
       </object>
     </child>
diff --git a/editor/bookmarks.vala b/editor/bookmarks.vala
index 8091eb5..20a5ceb 100644
--- a/editor/bookmarks.vala
+++ b/editor/bookmarks.vala
@@ -17,16 +17,36 @@
 
 using Gtk;
 
+internal enum BookmarkIcon {
+    VALID_FOLDER,
+    SEARCH,       /* TODO valid and invalid search; broken thing also, etc. */
+    DCONF_OBJECT,
+    KEY_DEFAULTS,
+    EDITED_VALUE,
+
+    /* same icon */
+    EMPTY_FOLDER,
+    EMPTY_OBJECT;
+}
+
 [GtkTemplate (ui = "/ca/desrt/dconf-editor/ui/bookmarks.ui")]
 private class Bookmarks : MenuButton
 {
     [GtkChild] private ListBox bookmarks_list_box;
+    [GtkChild] private ScrolledWindow scrolled;
     [GtkChild] private Popover bookmarks_popover;
 
     [GtkChild] private Image bookmarks_icon;
     [GtkChild] private Switch bookmarked_switch;
     [GtkChild] private Label switch_label;
-    [GtkChild] private Revealer bookmarks_editable_revealer;
+
+    [GtkChild] private Stack edit_mode_stack;
+    [GtkChild] private Button rows_size_button;
+    [GtkChild] private Image big_rows_icon;
+    [GtkChild] private Image small_rows_icon;
+
+    [GtkChild] private Button enter_edit_mode_button;
+    [GtkChild] private Button leave_edit_mode_button;
 
     private string   current_path = "/";
     private ViewType current_type = ViewType.FOLDER;
@@ -34,9 +54,13 @@ private class Bookmarks : MenuButton
     private string schema_id = "ca.desrt.dconf-editor.Bookmarks";   // TODO move in a library
     public string schema_path { private get; internal construct; }
     private GLib.Settings settings;
+    ulong bookmarks_changed_handler = 0;
 
     private HashTable<string, Bookmark> bookmarks_hashtable = new HashTable<string, Bookmark> (str_hash, 
str_equal);
     private Bookmark? last_row = null;
+    private uint n_bookmarks = 0;
+
+    internal signal void update_bookmarks_icons (Variant bookmarks_variant);
 
     construct
     {
@@ -45,10 +69,9 @@ private class Bookmarks : MenuButton
         install_action_entries ();
 
         settings = new GLib.Settings.with_path (schema_id, schema_path);
+        set_css_classes ();
 
-        enable_remove = settings.is_writable ("bookmarks");
-
-        ulong bookmarks_changed_handler = settings.changed ["bookmarks"].connect (on_bookmarks_changed);
+        bookmarks_changed_handler = settings.changed ["bookmarks"].connect (on_bookmarks_changed);
         update_bookmarks (settings.get_value ("bookmarks"));
 
         ulong bookmarks_writable_handler = settings.writable_changed ["bookmarks"].connect 
(set_switch_sensitivity);
@@ -57,12 +80,34 @@ private class Bookmarks : MenuButton
         ulong clicked_handler = clicked.connect (() => { if (active) bookmarked_switch.grab_focus (); });
 
         destroy.connect (() => {
+                settings.disconnect (small_bookmarks_rows_handler);
                 settings.disconnect (bookmarks_changed_handler);
                 settings.disconnect (bookmarks_writable_handler);
                 disconnect (clicked_handler);
             });
     }
 
+    private ulong small_bookmarks_rows_handler = 0;
+    private bool has_small_bookmarks_rows_class = false;
+    private void set_css_classes ()
+    {
+        StyleContext context = bookmarks_popover.get_style_context ();
+        small_bookmarks_rows_handler = settings.changed ["small-bookmarks-rows"].connect (() => {
+                bool small_bookmarks_rows = settings.get_boolean ("small-bookmarks-rows");
+                if (small_bookmarks_rows)
+                {
+                    if (!has_small_bookmarks_rows_class) context.add_class ("small-bookmarks-rows");
+                }
+                else if (has_small_bookmarks_rows_class) context.remove_class ("small-bookmarks-rows");
+                has_small_bookmarks_rows_class = small_bookmarks_rows;
+                update_rows_size_button_icon (small_bookmarks_rows);
+            });
+        has_small_bookmarks_rows_class = settings.get_boolean ("small-bookmarks-rows");
+        if (has_small_bookmarks_rows_class)
+            context.add_class ("small-bookmarks-rows");
+        update_rows_size_button_icon (has_small_bookmarks_rows_class);
+    }
+
     private void on_bookmarks_changed (GLib.Settings _settings, string key)
     {
         Variant bookmarks_variant = _settings.get_value ("bookmarks");
@@ -71,14 +116,66 @@ private class Bookmarks : MenuButton
         set_switch_sensitivity ();
     }
 
-    bool enable_remove = true;
     private void set_switch_sensitivity ()
     {
-        enable_remove = settings.is_writable ("bookmarks");
-        switch_label.set_sensitive (enable_remove);
-        bookmarked_switch.set_sensitive (enable_remove);
-        bookmarks_editable_revealer.set_reveal_child (!enable_remove);
-        bookmarks_list_box.@foreach ((widget) => ((Bookmark) widget).set_enable_remove (enable_remove));
+        if (settings.is_writable ("bookmarks"))
+        {
+            string? visible_child_name = edit_mode_stack.get_visible_child_name (); // do it like that
+            if (visible_child_name != null && (!) visible_child_name == "edit-mode-disabled")
+                edit_mode_stack.set_visible_child_name ("edit-mode-off");
+        }
+        else
+        {
+            edit_mode_stack.set_visible_child_name ("edit-mode-disabled");
+            bookmarks_list_box.grab_focus ();
+        }
+    }
+
+    /*\
+    * * Callbacks
+    \*/
+
+    [GtkCallback]
+    private bool on_key_press_event (Widget widget, Gdk.EventKey event)
+    {
+        uint keyval = event.keyval;
+        string name = (!) (Gdk.keyval_name (keyval) ?? "");
+
+        string? visible_child_name = edit_mode_stack.get_visible_child_name ();
+        bool edit_mode_on = visible_child_name != null && (!) visible_child_name == "edit-mode-on";
+
+        if ((event.state & Gdk.ModifierType.CONTROL_MASK) != 0)
+        {
+            if (edit_mode_on)
+            {
+                if (name == "a")
+                {
+                    bookmarks_list_box.select_all ();
+                    return true;
+                }
+                if (name == "A")
+                {
+                    bookmarks_list_box.unselect_all ();
+                    return true;
+                }
+            }
+        }
+
+        if (keyval == Gdk.Key.Escape && edit_mode_on)
+        {
+            leave_edit_mode ();
+            return true;
+        }
+        return false;
+    }
+
+    [GtkCallback]
+    private void on_selection_changed ()
+    {
+        string? visible_child_name = edit_mode_stack.get_visible_child_name ();         // TODO edit_mode_on 
private boolean
+        if (visible_child_name == null || (!) visible_child_name == "edit-mode-off")
+            return;
+        update_actions ();
     }
 
     /*\
@@ -112,7 +209,9 @@ private class Bookmarks : MenuButton
     }
 
     // keyboard call
+
     internal void down_pressed ()
+        requires (active)
     {
         ListBoxRow? row = bookmarks_list_box.get_selected_row ();
         if (row == null)
@@ -126,6 +225,7 @@ private class Bookmarks : MenuButton
         ((!) row).grab_focus ();
     }
     internal void up_pressed ()
+        requires (active)
     {
         ListBoxRow? row = bookmarks_list_box.get_selected_row ();
         if (row == null)
@@ -158,7 +258,7 @@ private class Bookmarks : MenuButton
         remove_bookmark (settings, current_path, current_type);
     }
 
-    internal void update_bookmark_icon (string bookmark, bool bookmark_exists, bool bookmark_has_schema, 
bool bookmark_is_default)
+    internal void update_bookmark_icon (string bookmark, BookmarkIcon icon)
     {
         Bookmark? bookmark_row = bookmarks_hashtable.lookup (bookmark);
         if (bookmark_row == null)
@@ -166,44 +266,331 @@ private class Bookmarks : MenuButton
         Widget? bookmark_grid = ((!) bookmark_row).get_child ();
         if (bookmark_grid == null)
             assert_not_reached ();
-        _update_bookmark_icon (((!) bookmark_grid).get_style_context (), bookmark_exists, 
bookmark_has_schema, bookmark_is_default);
+        _update_bookmark_icon (((!) bookmark_grid).get_style_context (), icon);
     }
-    private static inline void _update_bookmark_icon (StyleContext context, bool bookmark_exists, bool 
bookmark_has_schema, bool bookmark_is_default)
+    private static inline void _update_bookmark_icon (StyleContext context, BookmarkIcon icon)
     {
-        context.add_class ("key");
-        if (!bookmark_exists)
-        {
-            context.add_class ("dconf-key");
-            context.add_class ("erase");
-            return;
-        }
-        if (!bookmark_has_schema)
+        switch (icon)
         {
-            context.add_class ("dconf-key");
-            return;
+            case BookmarkIcon.VALID_FOLDER: context.add_class ("folder");
+                return;
+            case BookmarkIcon.EMPTY_FOLDER: context.add_class ("folder");
+                                            context.add_class ("erase");
+                return;
+            case BookmarkIcon.SEARCH:       context.add_class ("search");
+                return;
+            case BookmarkIcon.EMPTY_OBJECT: context.add_class ("key");
+                                            context.add_class ("dconf-key");
+                                            context.add_class ("erase");
+                return;
+            case BookmarkIcon.DCONF_OBJECT: context.add_class ("key");
+                                            context.add_class ("dconf-key");
+                return;
+            case BookmarkIcon.KEY_DEFAULTS: context.add_class ("key");
+                                            context.add_class ("gsettings-key");
+                return;
+            case BookmarkIcon.EDITED_VALUE: context.add_class ("key");
+                                            context.add_class ("gsettings-key");
+                                            context.add_class ("edited");
+                return;
+            default: assert_not_reached ();
         }
-        context.add_class ("gsettings-key");
-        if (!bookmark_is_default)
-            context.add_class ("edited");
     }
 
     /*\
     * * Action entries
     \*/
 
+    bool actions_init_done = false;
+    private SimpleAction move_top_action;
+    private SimpleAction move_up_action;
+    private SimpleAction move_down_action;
+    private SimpleAction move_bottom_action;
+    private SimpleAction trash_bookmark_action;
+
+    private void update_actions ()
+        requires (actions_init_done)
+    {
+        List<weak ListBoxRow> selected_rows = bookmarks_list_box.get_selected_rows ();
+        uint n_selected_rows = selected_rows.length ();
+
+        bool has_selected_items = n_selected_rows > 0;
+        bool has_one_selected_item = n_selected_rows == 1;
+
+        bool enable_move_top_action     = has_one_selected_item;    // TODO has_selected_items;
+        bool enable_move_up_action      = has_one_selected_item;
+        bool enable_move_down_action    = has_one_selected_item;
+        bool enable_move_bottom_action  = has_one_selected_item;    // TODO has_selected_items;
+
+        if (has_one_selected_item)
+        {
+            int index = selected_rows.nth_data (0).get_index ();
+            if (index == 0)
+            {
+                enable_move_top_action = false;
+                enable_move_up_action = false;
+            }
+            if (bookmarks_list_box.get_row_at_index (index + 1) == null)
+            {
+                enable_move_down_action = false;
+                enable_move_bottom_action = false;
+            }
+        }
+
+               move_up_action.set_enabled (enable_move_up_action);
+              move_top_action.set_enabled (enable_move_top_action);
+             move_down_action.set_enabled (enable_move_down_action);
+           move_bottom_action.set_enabled (enable_move_bottom_action);
+        trash_bookmark_action.set_enabled (has_selected_items);
+    }
+
     private void install_action_entries ()
     {
         SimpleActionGroup action_group = new SimpleActionGroup ();
         action_group.add_action_entries (action_entries, this);
         insert_action_group ("bookmarks", action_group);
+
+        move_top_action         = (SimpleAction) action_group.lookup_action ("move-top");
+        move_up_action          = (SimpleAction) action_group.lookup_action ("move-up");
+        move_down_action        = (SimpleAction) action_group.lookup_action ("move-down");
+        move_bottom_action      = (SimpleAction) action_group.lookup_action ("move-bottom");
+        trash_bookmark_action   = (SimpleAction) action_group.lookup_action ("trash-bookmark");
+        actions_init_done = true;
     }
 
     private const GLib.ActionEntry [] action_entries =
     {
-        {   "bookmark",   bookmark, "(sy)" },
-        { "unbookmark", unbookmark, "(sy)" }
+        { "enter-edit-mode", enter_edit_mode },
+        { "leave-edit-mode", leave_edit_mode },
+
+        { "trash-bookmark", trash_bookmark },
+        { "set-small-rows", set_small_rows },
+
+        { "move-top",    move_top    },
+        { "move-up",     move_up     },
+        { "move-down",   move_down   },
+        { "move-bottom", move_bottom },
+
+        {   "bookmark",    bookmark, "(sy)" },
+        { "unbookmark",  unbookmark, "(sy)" }
     };
 
+    private void enter_edit_mode (/* SimpleAction action, Variant? variant */)
+    {
+        enter_edit_mode_button.hide ();
+        bookmarks_popover.get_style_context ().add_class ("edit-mode");
+        update_actions ();
+
+        edit_mode_stack.set_visible_child_name ("edit-mode-on");
+        leave_edit_mode_button.grab_focus ();
+
+        bookmarks_list_box.@foreach ((widget) => { ((Bookmark) widget).set_actionable (false); });
+        bookmarks_list_box.set_activate_on_single_click (false);
+        bookmarks_list_box.set_selection_mode (SelectionMode.MULTIPLE);
+    }
+
+    private void leave_edit_mode (/* used both as action and method */)
+    {
+        ListBoxRow? row = (ListBoxRow?) bookmarks_list_box.get_focus_child ();  // broken, the child needs 
to have the global focus...
+        bool give_focus_to_switch = row == null;
+        if (give_focus_to_switch)
+        {
+            List<weak ListBoxRow> selected_rows = bookmarks_list_box.get_selected_rows ();
+            row = selected_rows.nth_data (0);
+        }
+
+        bookmarks_list_box.@foreach ((widget) => { ((Bookmark) widget).set_actionable (true); });
+        bookmarks_list_box.set_activate_on_single_click (true);
+        bookmarks_list_box.set_selection_mode (SelectionMode.SINGLE);
+
+        edit_mode_stack.set_visible_child_name ("edit-mode-off");
+
+        bookmarks_popover.get_style_context ().remove_class ("edit-mode");
+        enter_edit_mode_button.show ();
+
+        if (row != null)
+            select_row_for_real ((!) row);
+        if (give_focus_to_switch)
+            bookmarked_switch.grab_focus ();
+    }
+
+    private void trash_bookmark (/* SimpleAction action, Variant? variant */)
+    {
+        ListBoxRow? row = (ListBoxRow?) bookmarks_list_box.get_focus_child ();
+        bool focused_row_will_survive = row != null && !((!) row).is_selected ();
+
+        string [] bookmarks_to_remove = new string [0];
+        int upper_index = int.MAX;
+        bookmarks_list_box.selected_foreach ((_list_box, selected_row) => {
+                if (!(selected_row is Bookmark))
+                    assert_not_reached ();
+                bookmarks_to_remove += ((Bookmark) selected_row).bookmark_name;
+
+                if (focused_row_will_survive)
+                    return;
+
+                int index = selected_row.get_index ();
+                if (upper_index > index)
+                    upper_index = index;
+            });
+        if (upper_index == int.MAX)
+            assert_not_reached ();
+
+        if (!focused_row_will_survive)
+        {
+            row = bookmarks_list_box.get_row_at_index (upper_index + 1);
+            if (row == null)
+            {
+                if (upper_index > 0)
+                    row = bookmarks_list_box.get_row_at_index (upper_index - 1);
+                // TODO else quit mode
+            }
+        }
+        if (row != null)
+            bookmarks_list_box.select_row ((!) row);
+
+        remove_bookmarks (settings, bookmarks_to_remove);
+        update_bookmarks_icons (settings.get_value ("bookmarks"));
+    }
+
+    private void set_small_rows (/* SimpleAction action, Variant? variant */)
+    {
+        settings.set_boolean ("small-bookmarks-rows", rows_size_button.get_image () == small_rows_icon);
+    }
+    private void update_rows_size_button_icon (bool small_bookmarks_rows)
+    {
+        if (small_bookmarks_rows)
+            rows_size_button.set_image (big_rows_icon);
+        else
+            rows_size_button.set_image (small_rows_icon);
+    }
+
+    private void move_top       (/* SimpleAction action, Variant? variant */)
+    {
+//        bookmarks_list_box.selected_foreach ((_list_box, selected_row) => {
+
+        ListBoxRow? row = bookmarks_list_box.get_selected_row ();
+        if (row == null)
+            return; // TODO assert_not_reached?
+
+        int index = ((!) row).get_index ();
+        if (index < 0)
+            assert_not_reached ();
+
+        if (index == 0)
+            return;
+        bookmarks_list_box.remove ((!) row);
+        bookmarks_list_box.prepend ((!) row);
+        select_row_for_real ((!) row);
+
+        Adjustment adjustment = bookmarks_list_box.get_adjustment ();
+        adjustment.set_value (adjustment.get_lower ());
+
+        update_bookmarks_after_move ();
+    }
+
+    private void move_up        (/* SimpleAction action, Variant? variant */)
+    {
+        ListBoxRow? row = bookmarks_list_box.get_selected_row ();
+        if (row == null)
+            return; // TODO assert_not_reached?
+
+        int index = ((!) row).get_index ();
+        if (index < 0)
+            assert_not_reached ();
+
+        if (index == 0)
+            return;
+
+        ListBoxRow? prev_row = bookmarks_list_box.get_row_at_index (index - 1);
+        if (prev_row == null)
+            assert_not_reached ();
+
+        Allocation list_allocation, row_allocation;
+        scrolled.get_allocation (out list_allocation);
+        Widget? row_child = ((!) prev_row).get_child ();    // using prev_row as the allocation is not 
updated anyway
+        if (row_child == null)
+            assert_not_reached ();
+        ((!) row_child).get_allocation (out row_allocation);
+        Adjustment adjustment = bookmarks_list_box.get_adjustment ();
+        int proposed_adjustemnt_value = row_allocation.y + (int) ((row_allocation.height - 
list_allocation.height) / 3.0);
+        bool should_adjust = adjustment.get_value () > proposed_adjustemnt_value;
+
+        bookmarks_list_box.unselect_row ((!) row);
+        bookmarks_list_box.remove ((!) prev_row);
+
+        if (should_adjust)
+            adjustment.set_value (proposed_adjustemnt_value);
+
+        bookmarks_list_box.insert ((!) prev_row, index);
+        bookmarks_list_box.select_row ((!) row);
+
+        update_bookmarks_after_move ();
+    }
+
+    private void move_down      (/* SimpleAction action, Variant? variant */)
+    {
+        ListBoxRow? row = bookmarks_list_box.get_selected_row ();
+        if (row == null)
+            return; // TODO assert_not_reached?
+
+        int index = ((!) row).get_index ();
+        if (index < 0)
+            assert_not_reached ();
+
+        ListBoxRow? next_row = bookmarks_list_box.get_row_at_index (index + 1);
+        if (next_row == null)
+            return;
+
+        Allocation list_allocation, row_allocation;
+        scrolled.get_allocation (out list_allocation);
+        Widget? row_child = ((!) next_row).get_child ();    // using next_row as the allocation is not 
updated
+        if (row_child == null)
+            assert_not_reached ();
+        ((!) row_child).get_allocation (out row_allocation);
+        Adjustment adjustment = bookmarks_list_box.get_adjustment ();
+        int proposed_adjustemnt_value = row_allocation.y + (int) (2 * (row_allocation.height - 
list_allocation.height) / 3.0);
+        bool should_adjust = adjustment.get_value () < proposed_adjustemnt_value;
+
+        bookmarks_list_box.unselect_row ((!) row);
+        bookmarks_list_box.remove ((!) next_row);
+
+        if (should_adjust)
+            adjustment.set_value (proposed_adjustemnt_value);
+
+        bookmarks_list_box.insert ((!) next_row, index);
+        bookmarks_list_box.select_row ((!) row);
+
+        update_bookmarks_after_move ();
+    }
+
+    private void move_bottom    (/* SimpleAction action, Variant? variant */)
+    {
+//        bookmarks_list_box.selected_foreach ((_list_box, selected_row) => {
+
+        ListBoxRow? row = bookmarks_list_box.get_selected_row ();
+        if (row == null)
+            return; // TODO assert_not_reached?
+
+        int index = ((!) row).get_index ();
+        if (index < 0)
+            assert_not_reached ();
+
+        bookmarks_list_box.remove ((!) row);
+        bookmarks_list_box.insert ((!) row, -1);
+        select_row_for_real ((!) row);
+
+        Adjustment adjustment = bookmarks_list_box.get_adjustment ();
+        adjustment.set_value (adjustment.get_upper ());
+
+        update_bookmarks_after_move ();
+    }
+    private void select_row_for_real (ListBoxRow row)   // ahem...
+    {
+        bookmarks_list_box.unselect_row (row);
+        bookmarks_list_box.select_row (row);
+    }
+
     private void bookmark (SimpleAction action, Variant? path_variant)
         requires (path_variant != null)
     {
@@ -230,6 +617,22 @@ private class Bookmarks : MenuButton
     * * Bookmarks management
     \*/
 
+    private void update_bookmarks_after_move ()
+    {
+        string [] new_bookmarks = new string [0];
+        bookmarks_list_box.@foreach ((widget) => { new_bookmarks += ((Bookmark) widget).bookmark_name; });
+
+        string [] old_bookmarks = settings.get_strv ("bookmarks");  // be cool :-)
+        foreach (string bookmark in old_bookmarks)
+            if (!(bookmark in new_bookmarks))
+                new_bookmarks += bookmark;
+
+        SignalHandler.block (settings, bookmarks_changed_handler);
+        settings.set_strv ("bookmarks", new_bookmarks);
+        GLib.Settings.sync ();   // TODO better? really needed?
+        SignalHandler.unblock (settings, bookmarks_changed_handler);
+    }
+
     private const string bookmark_this_search_text = _("Bookmark this Search");
     private const string bookmark_this_location_text = _("Bookmark this Location");
     private static void update_switch_label (ViewType old_type, ViewType new_type, ref Label switch_label)
@@ -250,7 +653,6 @@ private class Bookmarks : MenuButton
                 bookmarks_icon.icon_name = "starred-symbolic";
             update_switch_state (true, ref bookmarked_switch);
             bookmarked_switch.set_detailed_action_name ("bookmarks.unbookmark(" + variant.print (true) + 
")");
-            bookmarked_switch.set_sensitive (enable_remove);
         }
         else
         {
@@ -258,7 +660,6 @@ private class Bookmarks : MenuButton
                 bookmarks_icon.icon_name = "non-starred-symbolic";
             update_switch_state (false, ref bookmarked_switch);
             bookmarked_switch.set_detailed_action_name ("bookmarks.bookmark(" + variant.print (true) + ")");
-            bookmarked_switch.set_sensitive (enable_remove);
         }
     }
     private static void update_switch_state (bool bookmarked, ref Switch bookmarked_switch)
@@ -269,16 +670,50 @@ private class Bookmarks : MenuButton
         bookmarked_switch.active = bookmarked;
     }
 
+    private bool has_empty_list_class = false;
     private void update_bookmarks (Variant bookmarks_variant)
     {
         set_detailed_action_name ("ui.update-bookmarks-icons(" + bookmarks_variant.print (true) + ")");  // 
TODO disable action on popover closed
-        create_bookmark_rows (bookmarks_variant, enable_remove, ref bookmarks_list_box, ref 
bookmarks_hashtable, ref last_row);
+        create_bookmark_rows (bookmarks_variant, ref bookmarks_list_box, ref bookmarks_hashtable, ref 
last_row, ref n_bookmarks);
+        if (n_bookmarks == 0)
+        {
+            string? visible_child_name = edit_mode_stack.get_visible_child_name (); // do it like that
+            if (visible_child_name != null && (!) visible_child_name == "edit-mode-on")
+                leave_edit_mode ();
+
+            if (!has_empty_list_class)
+            {
+                bookmarks_list_box.get_style_context ().add_class ("empty-list");
+                has_empty_list_class = true;
+            }
+
+            enter_edit_mode_button.hide ();
+        }
+        else
+        {
+            if (has_empty_list_class)
+            {
+                bookmarks_list_box.get_style_context ().remove_class ("empty-list");
+                has_empty_list_class = false;
+            }
+
+            string? visible_child_name = edit_mode_stack.get_visible_child_name (); // do it like that
+            if (visible_child_name != null && (!) visible_child_name == "edit-mode-off")
+                enter_edit_mode_button.show ();
+        }
     }
-    private static void create_bookmark_rows (Variant bookmarks_variant, bool enable_remove, ref ListBox 
bookmarks_list_box, ref HashTable<string, Bookmark> bookmarks_hashtable, ref Bookmark? last_row)
+    private static void create_bookmark_rows (Variant bookmarks_variant, ref ListBox bookmarks_list_box, ref 
HashTable<string, Bookmark> bookmarks_hashtable, ref Bookmark? last_row, ref uint n_bookmarks)
     {
+        string saved_bookmark_name = "";
+        ListBoxRow? selected_row = bookmarks_list_box.get_selected_row ();
+        if (selected_row != null && ((!) selected_row) is Bookmark)
+            saved_bookmark_name = ((Bookmark) (!) selected_row).bookmark_name;
+        selected_row = null;
+
         bookmarks_list_box.@foreach ((widget) => widget.destroy ());
         bookmarks_hashtable.remove_all ();
         last_row = null;
+        n_bookmarks = 0;
 
         string [] bookmarks = bookmarks_variant.get_strv ();
         string [] unduplicated_bookmarks = new string [0];
@@ -290,36 +725,21 @@ private class Bookmarks : MenuButton
                 continue;
             unduplicated_bookmarks += bookmark;
 
-            Bookmark bookmark_row = create_bookmark_row (bookmark, enable_remove);
+            Bookmark bookmark_row = new Bookmark (bookmark);
             bookmarks_list_box.add (bookmark_row);
+            bookmark_row.show ();
             bookmarks_hashtable.insert (bookmark, bookmark_row);
             last_row = bookmark_row;
+
+            if (saved_bookmark_name == bookmark)
+                selected_row = bookmark_row;
+            n_bookmarks ++;
         }
-        ListBoxRow? first_row = bookmarks_list_box.get_row_at_index (0);
-        if (first_row != null)
-            bookmarks_list_box.select_row ((!) first_row);
-    }
-    private static inline Bookmark create_bookmark_row (string bookmark, bool enable_remove)
-    {
-        Bookmark bookmark_row = new Bookmark (bookmark);
-        if (bookmark.has_prefix ("?"))
-        {
-            Variant variant = new Variant.string (bookmark.slice (1, bookmark.length));
-            bookmark_row.set_detailed_action_name ("ui.open-search(" + variant.print (false) + ")");
-        }
-        else if (ModelUtils.is_key_path (bookmark))
-        {
-            Variant variant = new Variant ("(sq)", bookmark, ModelUtils.undefined_context_id);
-            bookmark_row.set_detailed_action_name ("ui.open-object(" + variant.print (true) + ")");    // 
TODO save context
-        }
-        else
-        {
-            Variant variant = new Variant.string (bookmark);
-            bookmark_row.set_detailed_action_name ("ui.open-folder(" + variant.print (false) + ")");
-        }
-        bookmark_row.set_enable_remove (enable_remove); // put it here as setting detailed action name makes 
the button sensitive
-        bookmark_row.show ();
-        return bookmark_row;
+
+        if (selected_row == null)
+            selected_row = bookmarks_list_box.get_row_at_index (0);
+        if (selected_row != null)
+            bookmarks_list_box.select_row ((!) selected_row);
     }
 
     private static void append_bookmark (GLib.Settings settings, string path, ViewType type)
@@ -336,6 +756,10 @@ private class Bookmarks : MenuButton
     private static void remove_bookmark (GLib.Settings settings, string path, ViewType type)
     {
         string bookmark_name = get_bookmark_name (path, type);
+        _remove_bookmark (settings, bookmark_name);
+    }
+    private static inline void _remove_bookmark (GLib.Settings settings, string bookmark_name)
+    {
         string [] old_bookmarks = settings.get_strv ("bookmarks");
         if (!(bookmark_name in old_bookmarks))
             return;
@@ -347,6 +771,17 @@ private class Bookmarks : MenuButton
         settings.set_strv ("bookmarks", new_bookmarks);
     }
 
+    private static void remove_bookmarks (GLib.Settings settings, string [] bookmarks_to_remove)
+    {
+        string [] old_bookmarks = settings.get_strv ("bookmarks");
+
+        string [] new_bookmarks = new string [0];
+        foreach (string bookmark in old_bookmarks)
+            if (!(bookmark in bookmarks_to_remove) && !(bookmark in new_bookmarks))
+                new_bookmarks += bookmark;
+        settings.set_strv ("bookmarks", new_bookmarks);
+    }
+
     private static inline string get_bookmark_name (string path, ViewType type)
     {
         if (type == ViewType.SEARCH)
@@ -359,38 +794,90 @@ private class Bookmarks : MenuButton
 [GtkTemplate (ui = "/ca/desrt/dconf-editor/ui/bookmark.ui")]
 private class Bookmark : ListBoxRow
 {
-    [GtkChild] private Grid main_grid;
     [GtkChild] private Label bookmark_label;
-    [GtkChild] private Button destroy_button;
 
-    internal Bookmark (string bookmark_name)
+    public string bookmark_name { internal get; internal construct; }
+
+    construct
     {
-        string   bookmark_text;
+        string bookmark_text;
         ViewType bookmark_type;
+        parse_bookmark_name (bookmark_name, out bookmark_text, out bookmark_type);
+
+        construct_actions_names (bookmark_text, bookmark_type, out detailed_action_name, out 
inactive_action_name);
+        set_actionable (true);
+
+        bookmark_label.set_label (bookmark_text);
+    }
+
+    internal Bookmark (string bookmark_name)
+    {
+        Object (bookmark_name: bookmark_name);
+    }
+
+    internal void set_actionable (bool actionable)
+    {
+        if (actionable)
+            set_detailed_action_name (detailed_action_name);
+        else
+            set_detailed_action_name (inactive_action_name);
+    }
+
+    /*\
+    * * Actions names
+    \*/
+
+    private string detailed_action_name;
+    private string inactive_action_name;
+
+    private static void construct_actions_names (string     bookmark_text,
+                                                 ViewType   bookmark_type,
+                                             out string     detailed_action_name,
+                                             out string     inactive_action_name)
+    {
+        switch (bookmark_type)
+        {
+            case ViewType.SEARCH:
+                Variant variant = new Variant.string (bookmark_text);
+                detailed_action_name = "ui.open-search(" + variant.print (false) + ")";
+                inactive_action_name = "ui.empty('')";
+                return;
+
+            case ViewType.FOLDER:
+                Variant variant = new Variant.string (bookmark_text);
+                detailed_action_name = "ui.open-folder(" + variant.print (false) + ")";
+                inactive_action_name = "ui.empty('')";
+                return;
+
+            case ViewType.OBJECT:
+                Variant variant = new Variant ("(sq)", bookmark_text, ModelUtils.undefined_context_id);  // 
TODO save context
+                detailed_action_name = "ui.open-object(" + variant.print (true) + ")";
+                inactive_action_name = "ui.empty(('',uint16 65535))";
+                return;
+
+            case ViewType.CONFIG:
+            default: assert_not_reached ();
+        }
+    }
+
+    private static void parse_bookmark_name (string     bookmark_name,
+                                         out string     bookmark_text,
+                                         out ViewType   bookmark_type)
+    {
         if (bookmark_name.has_prefix ("?"))
         {
             bookmark_text = bookmark_name.slice (1, bookmark_name.length);
             bookmark_type = ViewType.SEARCH;
-            main_grid.get_style_context ().add_class ("search");
+        }
+        else if (ModelUtils.is_folder_path (bookmark_name))
+        {
+            bookmark_text = bookmark_name;
+            bookmark_type = ViewType.FOLDER;
         }
         else
         {
             bookmark_text = bookmark_name;
-            if (ModelUtils.is_folder_path (bookmark_text))  // class is updated elsewhere for keys
-            {
-                main_grid.get_style_context ().add_class ("folder");
-                bookmark_type = ViewType.FOLDER;
-            }
-            else
-                bookmark_type = ViewType.OBJECT;
+            bookmark_type = ViewType.OBJECT;
         }
-        bookmark_label.set_label (bookmark_text);
-        Variant variant = new Variant ("(sy)", bookmark_text, ViewType.to_byte (bookmark_type));
-        destroy_button.set_detailed_action_name ("bookmarks.unbookmark(" + variant.print (true) + ")");
-    }
-
-    internal void set_enable_remove (bool new_sensitivity)
-    {
-        destroy_button.set_sensitive (new_sensitivity);
     }
 }
diff --git a/editor/ca.desrt.dconf-editor.gschema.xml b/editor/ca.desrt.dconf-editor.gschema.xml
index 1f719ea..668d782 100644
--- a/editor/ca.desrt.dconf-editor.gschema.xml
+++ b/editor/ca.desrt.dconf-editor.gschema.xml
@@ -138,11 +138,6 @@
       <summary>A flag to enable small rows for keys list</summary>
       <description>If “true”, the keys list use smaller rows.</description>
     </key>
-    <key name="small-bookmarks-rows" type="b">
-      <default>false</default>
-      <summary>A flag to enable small rows for bookmarks list</summary>
-      <description>If “true”, the bookmarks list use smaller rows.</description>
-    </key>
     <key name="behaviour" enum="ca.desrt.dconf-editor.Behaviour">
       <default>'always-confirm-implicit'</default>
       <summary>Change the behaviour of a key value change request</summary>
@@ -204,6 +199,11 @@
       <summary>A list of bookmarked paths</summary>
       <description>Contains all paths bookmarked by the user as an array of strings.</description>
     </key>
+    <key name="small-bookmarks-rows" type="b">
+      <default>false</default>
+      <summary>A flag to enable small rows for bookmarks list</summary>
+      <description>If “true”, the bookmarks list use smaller rows.</description>
+    </key>
   </schema>
   <enum id="ca.desrt.dconf-editor.DemoEnum">
     <value value="0" nick="Red"/>
diff --git a/editor/dconf-editor.css b/editor/dconf-editor.css
index d9b5ac3..bcf0927 100644
--- a/editor/dconf-editor.css
+++ b/editor/dconf-editor.css
@@ -24,30 +24,65 @@
 * * bookmarks
 \*/
 
-/* no transition as it would start at popover's opening */
-
-                      .bookmarks list > row { min-height:2.6rem; }
-.small-bookmarks-rows .bookmarks list > row { min-height:1.3rem; }
-
-.small-bookmarks-rows .bookmarks list > row > grid > button.circular.flat {
+/*                     .bookmarks list > row > grid > button.circular.flat {
+  transition:min-height 0.3s, padding 0.3s, margin 0.3s;
+}
+.small-bookmarks-rows.bookmarks list > row > grid > button.circular.flat {
   min-height:0;
   padding-bottom:1px;
   padding-top:1px;
   margin-top:-2px;
   margin-bottom:-2px;
+} */
+
+                      .bookmark          { background-repeat:no-repeat;
+                                           transition:all               0 ease,
+                                                      padding-left      0.3s,   /* small-rows; for ltr */
+                                                      margin-left       0.3s,   /* small-rows; for ltr */
+                                                      padding-right     0.3s,   /* small-rows; for rtl */
+                                                      margin-right      0.3s,   /* small-rows; for rtl */
+                                                      background-size   0.3s,   /* small-rows */
+                                                      min-height        0.3s;   /* small-rows */
+                                           background-size:1.5rem; min-height:2.6rem; }
+.small-bookmarks-rows .bookmark          { background-size:1.1rem; min-height:1.3rem; }
+
+                      .bookmark:dir(ltr) { margin-left :0.6rem; padding-left :2.2rem; margin-right:1rem; 
background-position:  0  center }
+                      .bookmark:dir(rtl) { margin-right:0.6rem; padding-right:2.2rem; margin-left :1rem; 
background-position:100% center }
+.small-bookmarks-rows .bookmark:dir(ltr) { margin-left :0.5rem; padding-left :1.7rem; }
+.small-bookmarks-rows .bookmark:dir(rtl) { margin-right:0.5rem; padding-right:1.7rem; }
+
+/* various hacks */
+
+.bookmarks separator {
+  margin-top:0;
+  margin-bottom:0;
 }
 
-                      .bookmark {
-  background-repeat:no-repeat;
-  background-size:1.5rem;
+.bookmarks                 .padding-bottom {
+  padding-bottom:0;
+  transition:padding-bottom 0.3s,
+             font-size      0.3s;
 }
-.small-bookmarks-rows .bookmark {
-  background-size:1.1rem;
+.bookmarks:not(.edit-mode) .padding-bottom:not(.empty-list) {
+  padding-bottom:2.4rem;
+}
+
+.edit-bookmarks-list {
+  padding-left:0.1rem;
+  padding-right:0.1rem;
+  padding-bottom:0.1rem;
+  border-radius:1.8rem 1.8rem 0 0;
+  border-bottom:none;
+
+  transition:all           0    ease,
+             margin-bottom 0.3s ease,
+             padding       0.3s ease;
+  margin-bottom:0;
+}
+
+.edit-bookmarks-list label {
+  transition:all 0 ease;
 }
-                      .bookmark:dir(ltr) { padding-left :2.2rem; background-position:0    center; }
-                      .bookmark:dir(rtl) { padding-right:2.2rem; background-position:100% center; }
-.small-bookmarks-rows .bookmark:dir(ltr) { padding-left :1.7rem; }
-.small-bookmarks-rows .bookmark:dir(rtl) { padding-right:1.7rem; }
 
 /*\
 * * pending change list popover
@@ -161,6 +196,7 @@ window:not(.extra-small-window)    .keys-list:dir(rtl) > row > .key    > grid >
 
              row        >                .folder               { 
background-image:-gtk-icontheme("folder-symbolic"); }
              row:active >                .folder               { 
background-image:-gtk-icontheme("folder-open-symbolic"); }
+             row        >          .erase.folder               { 
background-image:-gtk-icontheme("action-unavailable-symbolic"); }
              row >                       .search               { 
background-image:-gtk-icontheme("edit-find-symbolic"); }
 
              row >                       .return               { 
background-image:-gtk-icontheme("edit-undo-symbolic"); }
@@ -327,8 +363,8 @@ window:not(.extra-small-window)    .keys-list:dir(rtl) > row > .key    > grid >
 * * lists headers
 \*/
 
-.bookmarks > grid > scrolledwindow > viewport > list > row > grid > button,
-.bookmarks > grid > scrolledwindow > viewport > list > row > grid > label,
+/* .bookmarks > grid > overlay > scrolledwindow > viewport > list > row > grid > button, */
+.bookmarks > grid > overlay > scrolledwindow > viewport > list > row > grid > label,
 .delayed-settings-popover list > row > grid > label,
 .delayed-settings-popover list > row > grid > grid > label,
 .modifications-revealer button,
@@ -345,12 +381,12 @@ window:not(.extra-small-window)    .keys-list:dir(rtl) > row > .key    > grid >
              padding 0.3s,
              margin 0.3s;
 }
-.bookmarks > grid > scrolledwindow > viewport > list > row {
+/* .bookmarks > grid > overlay > scrolledwindow > viewport > list > row {
   transition:min-height 0.3s,
              font-size 0.3s,
              padding 0.3s,
              margin 0.3s;
-}
+} */
 
 .header-label {
   margin:0.45em 0.75em 0.2em;
@@ -477,7 +513,3 @@ window:not(.extra-small-window)    .keys-list:dir(rtl) > row > .key    > grid >
 .big-popover {
   font-size:144%;
 }
-
-.margin-top-6px {
-  margin-top:6px;
-}
diff --git a/editor/dconf-model.vala b/editor/dconf-model.vala
index 70c25ea..9b1b34d 100644
--- a/editor/dconf-model.vala
+++ b/editor/dconf-model.vala
@@ -198,15 +198,19 @@ private abstract class SettingsModelCore : Object
     protected bool _get_object (string path, out uint16 context_id, out string name, bool watch)
     {
         SettingObject? object;
-        if (ModelUtils.is_key_path (path))
-            object = (SettingObject?) get_key (path, "");
-        else
+        bool is_folder_path = ModelUtils.is_folder_path (path);
+        if (is_folder_path)
             object = (SettingObject?) get_directory (path);
+        else
+            object = (SettingObject?) get_key (path, "");
 
         if (object == null)
         {
-            context_id = ModelUtils.undefined_context_id;   // garbage 1/2
-            name = "";                                      // garbage 2/2
+            if (is_folder_path)
+                context_id = ModelUtils.folder_context_id;
+            else
+                context_id = ModelUtils.undefined_context_id;   // garbage 1/2
+            name = "";                                          // garbage 2/2
             return false;
         }
 
diff --git a/editor/dconf-window.vala b/editor/dconf-window.vala
index 68be360..3825eee 100644
--- a/editor/dconf-window.vala
+++ b/editor/dconf-window.vala
@@ -127,6 +127,8 @@ private class DConfWindow : ApplicationWindow
         install_ui_action_entries ();
         install_kbd_action_entries ();
 
+        path_widget.update_bookmarks_icons.connect (_update_bookmarks_icons);
+
         use_shortpaths_changed_handler = settings.changed ["use-shortpaths"].connect_after (reload_view);
         settings.bind ("use-shortpaths", model, "use-shortpaths", 
SettingsBindFlags.GET|SettingsBindFlags.NO_SENSITIVITY);
 
@@ -307,8 +309,7 @@ private class DConfWindow : ApplicationWindow
     \*/
 
     private ulong small_keys_list_rows_handler = 0;
-    private ulong small_bookmarks_rows_handler = 0;
-
+    private bool has_small_keys_list_rows_class = false;
     private void set_css_styles ()
     {
         StyleContext context = get_style_context ();
@@ -316,24 +317,16 @@ private class DConfWindow : ApplicationWindow
                 bool small_rows = settings.get_boolean ("small-keys-list-rows");
                 if (small_rows)
                 {
-                    if (!context.has_class ("small-keys-list-rows")) context.add_class 
("small-keys-list-rows");
+                    if (!has_small_keys_list_rows_class) context.add_class ("small-keys-list-rows");
                 }
-                else if (context.has_class ("small-keys-list-rows")) context.remove_class 
("small-keys-list-rows");
+                else if (has_small_keys_list_rows_class) context.remove_class ("small-keys-list-rows");
+                has_small_keys_list_rows_class = small_rows;
                 browser_view.small_keys_list_rows = small_rows;
             });
-        small_bookmarks_rows_handler = settings.changed ["small-bookmarks-rows"].connect (() => {
-                if (settings.get_boolean ("small-bookmarks-rows"))
-                {
-                    if (!context.has_class ("small-bookmarks-rows")) context.add_class 
("small-bookmarks-rows");
-                }
-                else if (context.has_class ("small-bookmarks-rows")) context.remove_class 
("small-bookmarks-rows");
-            });
-        bool small_rows = settings.get_boolean ("small-keys-list-rows");
-        if (small_rows)
+        has_small_keys_list_rows_class = settings.get_boolean ("small-keys-list-rows");
+        if (has_small_keys_list_rows_class)
             context.add_class ("small-keys-list-rows");
-        browser_view.small_keys_list_rows = small_rows;
-        if (settings.get_boolean ("small-bookmarks-rows"))
-            context.add_class ("small-bookmarks-rows");
+        browser_view.small_keys_list_rows = has_small_keys_list_rows_class;
 
         Gtk.Settings? gtk_settings = Gtk.Settings.get_default ();
         if (gtk_settings == null)
@@ -531,7 +524,6 @@ private class DConfWindow : ApplicationWindow
         settings.disconnect (behaviour_changed_handler);
         settings.disconnect (use_shortpaths_changed_handler);
         settings.disconnect (small_keys_list_rows_handler);
-        settings.disconnect (small_bookmarks_rows_handler);
 
         settings.delay ();
         settings.set_string ("saved-view", saved_view);
@@ -693,6 +685,10 @@ private class DConfWindow : ApplicationWindow
 
     private void update_bookmarks_icons (SimpleAction action, Variant? bookmarks_variant)
         requires (bookmarks_variant != null)
+    {
+        _update_bookmarks_icons ((!) bookmarks_variant);
+    }
+    private void _update_bookmarks_icons (Variant bookmarks_variant)
     {
         string [] bookmarks = ((!) bookmarks_variant).get_strv ();
 
@@ -701,27 +697,41 @@ private class DConfWindow : ApplicationWindow
 
         foreach (string bookmark in bookmarks)
         {
-            if (bookmark.has_prefix ("?"))
+            if (bookmark.has_prefix ("?"))  // TODO broken search
+            {
+                path_widget.update_bookmark_icon (bookmark, BookmarkIcon.SEARCH);
                 continue;
-            if (is_path_invalid (bookmark))
+            }
+            if (is_path_invalid (bookmark)) // TODO broken folder and broken object
                 continue;
-            if (ModelUtils.is_folder_path (bookmark))
-                continue;   // TODO check folder existence
 
             uint16 context_id;
             string name;
-            bool bookmark_exists = model.get_object (bookmark, out context_id, out name, false);
+            bool bookmark_exists = model.get_object (bookmark, out context_id, out name, false);    // TODO 
get_folder
+
+            if (context_id == ModelUtils.folder_context_id)
+            {
+                if (bookmark_exists)
+                    path_widget.update_bookmark_icon (bookmark, BookmarkIcon.VALID_FOLDER);
+                else
+                    path_widget.update_bookmark_icon (bookmark, BookmarkIcon.EMPTY_FOLDER);
+                continue;
+            }
+
             if (!bookmark_exists)
-                path_widget.update_bookmark_icon (bookmark, false);
+                path_widget.update_bookmark_icon (bookmark, BookmarkIcon.EMPTY_OBJECT);
             else if (context_id == ModelUtils.dconf_context_id)
-                path_widget.update_bookmark_icon (bookmark, true, false);
+                path_widget.update_bookmark_icon (bookmark, BookmarkIcon.DCONF_OBJECT);
             else
             {
                 RegistryVariantDict bookmark_properties = new RegistryVariantDict.from_aqv 
(model.get_key_properties (bookmark, context_id, (uint16) PropertyQuery.IS_DEFAULT));
                 bool is_default;
                 if (!bookmark_properties.lookup (PropertyQuery.IS_DEFAULT, "b", out is_default))
                     assert_not_reached ();
-                path_widget.update_bookmark_icon (bookmark, true, true, is_default);
+                if (is_default)
+                    path_widget.update_bookmark_icon (bookmark, BookmarkIcon.KEY_DEFAULTS);
+                else
+                    path_widget.update_bookmark_icon (bookmark, BookmarkIcon.EDITED_VALUE);
             }
         }
     }
diff --git a/editor/icons/hicolor/scalable/actions/ca.desrt.dconf-editor.big-rows-symbolic.svg 
b/editor/icons/hicolor/scalable/actions/ca.desrt.dconf-editor.big-rows-symbolic.svg
new file mode 100644
index 0000000..dbc27eb
--- /dev/null
+++ b/editor/icons/hicolor/scalable/actions/ca.desrt.dconf-editor.big-rows-symbolic.svg
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/";
+   xmlns:cc="http://creativecommons.org/ns#";
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+   xmlns:svg="http://www.w3.org/2000/svg";
+   xmlns="http://www.w3.org/2000/svg";
+   xmlns:xlink="http://www.w3.org/1999/xlink";
+   id="svg10"
+   version="1.1"
+   height="16"
+   width="16">
+  <metadata
+     id="metadata16">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage"; />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs14" />
+  <g
+     style="color:#000000;fill:#474747"
+     transform="translate(0,-4.1)"
+     id="g8">
+    <path
+       id="path2"
+       overflow="visible"
+       font-weight="400"
+       
style="font-weight:400;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;text-orientation:mixed;white-space:normal;shape-padding:0;overflow:visible;isolation:auto;mix-blend-mode:normal;marker:none"
+       d="M 8,6.086 2.293,9.293 3.707,10.707 8,8.914 l 4.293,1.793 1.414,-1.414 z" />
+    <path
+       id="path4"
+       overflow="visible"
+       style="overflow:visible;marker:none"
+       d="m 13,10 v 1 h 1 V 10 Z M 2,10 v 1 h 1 v -1 z" />
+    <path
+       id="path6"
+       overflow="visible"
+       style="overflow:visible;marker:none"
+       d="m 2,10 c 0,0.554 0.446,1 1,1 0.554,0 1,-0.446 1,-1 C 4,9.446 3.554,9 3,9 2.446,9 2,9.446 2,10 Z m 
10,0 c 0,0.554 0.446,1 1,1 0.554,0 1,-0.446 1,-1 0,-0.554 -0.446,-1 -1,-1 -0.554,0 -1,0.446 -1,1 z" />
+  </g>
+  <use
+     height="100%"
+     width="100%"
+     transform="matrix(1,0,0,-1,0,15.986)"
+     id="use18"
+     xlink:href="#g8"
+     y="0"
+     x="0" />
+</svg>
diff --git a/editor/icons/hicolor/scalable/actions/ca.desrt.dconf-editor.small-rows-symbolic.svg 
b/editor/icons/hicolor/scalable/actions/ca.desrt.dconf-editor.small-rows-symbolic.svg
new file mode 100644
index 0000000..21997d4
--- /dev/null
+++ b/editor/icons/hicolor/scalable/actions/ca.desrt.dconf-editor.small-rows-symbolic.svg
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/";
+   xmlns:cc="http://creativecommons.org/ns#";
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+   xmlns:svg="http://www.w3.org/2000/svg";
+   xmlns="http://www.w3.org/2000/svg";
+   xmlns:xlink="http://www.w3.org/1999/xlink";
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
+   width="16"
+   height="16"
+   version="1.1"
+   id="svg10"
+   sodipodi:docname="ca.desrt.dconf-editor.small-rows-symbolic-2.svg"
+   inkscape:version="0.92.3 (2405546, 2018-03-11)">
+  <metadata
+     id="metadata16">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage"; />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs14" />
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1366"
+     inkscape:window-height="704"
+     id="namedview12"
+     showgrid="false"
+     inkscape:zoom="29.5"
+     inkscape:cx="7.6984549"
+     inkscape:cy="7.6865103"
+     inkscape:window-x="0"
+     inkscape:window-y="27"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg10" />
+  <g
+     id="g8"
+     transform="translate(0,3)"
+     style="color:#000000;fill:#474747">
+    <path
+       d="M 8,6.086 2.293,9.293 3.707,10.707 8,8.914 l 4.293,1.793 1.414,-1.414 z"
+       
style="font-weight:400;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;text-orientation:mixed;white-space:normal;shape-padding:0;overflow:visible;isolation:auto;mix-blend-mode:normal;marker:none"
+       font-weight="400"
+       overflow="visible"
+       id="path2"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="ccccccc" />
+    <path
+       d="m 13,10 v 1 h 1 V 10 Z M 2,10 v 1 h 1 v -1 z"
+       style="overflow:visible;marker:none"
+       overflow="visible"
+       id="path4"
+       inkscape:connector-curvature="0" />
+    <path
+       d="m 2,10 c 0,0.554 0.446,1 1,1 0.554,0 1,-0.446 1,-1 C 4,9.446 3.554,9 3,9 2.446,9 2,9.446 2,10 Z m 
10,0 c 0,0.554 0.446,1 1,1 0.554,0 1,-0.446 1,-1 0,-0.554 -0.446,-1 -1,-1 -0.554,0 -1,0.446 -1,1 z"
+       style="overflow:visible;marker:none"
+       overflow="visible"
+       id="path6"
+       inkscape:connector-curvature="0" />
+  </g>
+  <use
+     x="0"
+     y="0"
+     xlink:href="#g8"
+     id="use18"
+     transform="matrix(1,0,0,-1,0,15.986)"
+     width="100%"
+     height="100%" />
+</svg>
diff --git a/editor/pathwidget.vala b/editor/pathwidget.vala
index 9326737..53d87bc 100644
--- a/editor/pathwidget.vala
+++ b/editor/pathwidget.vala
@@ -30,6 +30,12 @@ private class PathWidget : Box
     internal signal void search_changed ();
     internal signal void search_stopped ();
 
+    internal signal void update_bookmarks_icons (Variant bookmarks_variant);
+    construct
+    {
+        bookmarks_button.update_bookmarks_icons.connect ((bookmarks_variant) => update_bookmarks_icons 
(bookmarks_variant));
+    }
+
     /*\
     * * search mode
     \*/
@@ -164,9 +170,9 @@ private class PathWidget : Box
     internal void   bookmark_current_path () {   bookmarks_button.bookmark_current_path (); }
     internal void unbookmark_current_path () { bookmarks_button.unbookmark_current_path (); }
 
-    internal void update_bookmark_icon (string bookmark, bool bookmark_exists, bool bookmark_has_schema = 
false, bool bookmark_is_default = false)
+    internal void update_bookmark_icon (string bookmark, BookmarkIcon icon)
     {
-        bookmarks_button.update_bookmark_icon (bookmark, bookmark_exists, bookmark_has_schema, 
bookmark_is_default);
+        bookmarks_button.update_bookmark_icon (bookmark, icon);
     }
 
 /*      string [] tokens = full_name.split (" ");


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