[dconf-editor] Add delay mode.



commit 5ef9f44bbe58514f47159da18f46c8cbf123f308
Author: Arnaud Bonatti <arnaud bonatti gmail com>
Date:   Sat Jul 2 17:38:56 2016 +0200

    Add delay mode.

 editor/ca.desrt.dconf-editor.gschema.xml |   15 +++-
 editor/dconf-window.vala                 |   34 +++++++---
 editor/modifications-revealer.vala       |  108 +++++++++++++++++++++++++++---
 editor/registry-info.vala                |   44 +++++++++---
 editor/registry-view.vala                |   29 ++++++--
 5 files changed, 190 insertions(+), 40 deletions(-)
---
diff --git a/editor/ca.desrt.dconf-editor.gschema.xml b/editor/ca.desrt.dconf-editor.gschema.xml
index 6eb7a68..0b42363 100644
--- a/editor/ca.desrt.dconf-editor.gschema.xml
+++ b/editor/ca.desrt.dconf-editor.gschema.xml
@@ -4,6 +4,13 @@
     <value value="0" nick="three-twenty-two"/>
     <value value="1" nick="small-rows"/>
   </enum>
+  <enum id="ca.desrt.dconf-editor.Behaviour">
+    <value value="0" nick="unsafe"/>
+    <value value="1" nick="safe"/>
+    <value value="2" nick="always-confirm-implicit"/>
+    <value value="3" nick="always-confirm-explicit"/>
+    <value value="4" nick="always-delay"/>
+  </enum>
   <schema id="ca.desrt.dconf-editor.Settings" path="/ca/desrt/dconf-editor/">
     <child schema="ca.desrt.dconf-editor.Demo" name="demo"/>
     <key name="window-width" type="i">
@@ -46,10 +53,10 @@
       <summary>The theme of the navigation list</summary>
       <description>The themes are defined by the application, you cannot add one. Two themes are available 
for now: 'three-twenty-two' that will remain as close as possible to the default theme of the 3.22 release, 
and 'small-rows' that tries to minimize the rows height.</description>
     </key>
-    <key name="delayed-apply-menu" type="b">
-      <default>false</default>
-      <summary>Switch right-click menu in delayed mode</summary>
-      <description>If 'true', dconf-editor ask for confirmation before applying changes set by the 
right-click menu.</description>
+    <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>
+      <description>The 'unsafe' value is discouraged: for keys that have a non-special-cased type, it 
updates the key value each time something changes in the entry, so including intermediate states. The 'safe' 
value asks for confirmation in these cases, but allows instant changes for booleans and nullable booleans, 
enums and flags. The 'always-confirm-implicit' and 'always-confirm-explicit' values always asks for 
confirmation, but the first applies the change if you change path whereas the second dismiss it. The 
'always-delay' value adds each change in delay mode, allowing to apply multiple keys at once.</description>
     </key>
   </schema>
   <enum id="ca.desrt.dconf-editor.DemoEnum">
diff --git a/editor/dconf-window.vala b/editor/dconf-window.vala
index 5c8171b..7aa29c9 100644
--- a/editor/dconf-window.vala
+++ b/editor/dconf-window.vala
@@ -17,13 +17,22 @@
 
 using Gtk;
 
+public enum Behaviour {
+    UNSAFE,
+    SAFE,
+    ALWAYS_CONFIRM_IMPLICIT,
+    ALWAYS_CONFIRM_EXPLICIT,
+    ALWAYS_DELAY
+}
+
 [GtkTemplate (ui = "/ca/desrt/dconf-editor/ui/dconf-editor.ui")]
 class DConfWindow : ApplicationWindow
 {
     private const GLib.ActionEntry [] action_entries =
     {
         { "reset-recursive", reset_recursively },
-        { "reset-visible", reset }
+        { "reset-visible", reset },
+        { "enter-delay-mode", enter_delay_mode }
     };
 
     public string current_path { private get; set; default = "/"; } // not synced bidi, needed for saving on 
destroy, even after child destruction
@@ -43,9 +52,8 @@ class DConfWindow : ApplicationWindow
     public DConfWindow ()
     {
         add_action_entries (action_entries, this);
-        add_action (settings.create_action ("delayed-apply-menu"));
 
-        settings.changed["delayed-apply-menu"].connect (invalidate_popovers);
+        settings.changed ["behaviour"].connect (invalidate_popovers);
 
         set_default_size (settings.get_int ("window-width"), settings.get_int ("window-height"));
         if (settings.get_boolean ("window-is-maximized"))
@@ -63,7 +71,7 @@ class DConfWindow : ApplicationWindow
             get_style_context ().add_class ("small-rows");
 
         registry_view.bind_property ("current-path", this, "current-path");    // TODO in UI file?
-        settings.bind ("delayed-apply-menu", registry_view, "delayed-apply-menu", 
SettingsBindFlags.GET|SettingsBindFlags.NO_SENSITIVITY);
+        settings.bind ("behaviour", registry_view, "behaviour", 
SettingsBindFlags.GET|SettingsBindFlags.NO_SENSITIVITY);
         registry_view.init (settings.get_string ("saved-view"), settings.get_boolean ("restore-view"));  // 
TODO better?
     }
 
@@ -153,7 +161,7 @@ class DConfWindow : ApplicationWindow
     * * Action entries
     \*/
 
-    public void update_current_path ()
+    public void update_hamburger_menu ()
     {
         GLib.Menu section;
 
@@ -172,10 +180,13 @@ class DConfWindow : ApplicationWindow
             menu.append_section (null, section);
         }
 
-        section = new GLib.Menu ();
-        section.append (_("Right click menu"), "win.delayed-apply-menu");
-        section.freeze ();
-        menu.append_section (_("Delayed Apply"), section);
+        if (!registry_view.get_current_delay_mode ())
+        {
+            section = new GLib.Menu ();
+            section.append (_("Enter delay mode"), "win.enter-delay-mode");
+            section.freeze ();
+            menu.append_section (null, section);
+        }
 
         menu.freeze ();
         info_button.set_menu_model ((MenuModel) menu);
@@ -191,6 +202,11 @@ class DConfWindow : ApplicationWindow
         registry_view.reset (true);
     }
 
+    private void enter_delay_mode ()
+    {
+        registry_view.enter_delay_mode ();
+    }
+
     /*\
     * * Other callbacks
     \*/
diff --git a/editor/modifications-revealer.vala b/editor/modifications-revealer.vala
index 75727d1..a0508aa 100644
--- a/editor/modifications-revealer.vala
+++ b/editor/modifications-revealer.vala
@@ -20,6 +20,13 @@ using Gtk;
 [GtkTemplate (ui = "/ca/desrt/dconf-editor/ui/modifications-revealer.ui")]
 class ModificationsRevealer : Revealer
 {
+    private enum Mode {
+        NONE,
+        TEMPORARY,
+        DELAYED
+    }
+    private Mode mode = Mode.NONE;
+
     [GtkChild] private Label label;
     [GtkChild] private ModelButton apply_button;
 
@@ -32,6 +39,8 @@ class ModificationsRevealer : Revealer
 
     public signal void reload ();
 
+    public Behaviour behaviour { get; set; }
+
     /*\
     * * Window management callbacks
     \*/
@@ -58,6 +67,30 @@ class ModificationsRevealer : Revealer
     * * Public calls
     \*/
 
+    public bool get_current_delay_mode ()
+    {
+        return mode == Mode.DELAYED || behaviour == Behaviour.ALWAYS_DELAY;
+    }
+
+    public bool should_delay_apply (string type_string)
+    {
+        if (get_current_delay_mode () || behaviour == Behaviour.ALWAYS_CONFIRM_IMPLICIT || behaviour == 
Behaviour.ALWAYS_CONFIRM_EXPLICIT)
+            return true;
+        if (behaviour == Behaviour.UNSAFE)
+            return false;
+        if (behaviour == Behaviour.SAFE)
+            return type_string != "b" && type_string != "mb" && type_string != "<enum>" && type_string != 
"<flags>";
+        assert_not_reached ();
+    }
+
+    public void enter_delay_mode ()
+    {
+        mode = Mode.DELAYED;
+        apply_button.sensitive = dconf_keys_awaiting_hashtable.length + 
gsettings_keys_awaiting_hashtable.length != 0;
+        update ();
+        reload ();
+    }
+
     public void add_delayed_setting (Key key, Variant? new_value)
     {
         key.planned_change = true;
@@ -68,11 +101,20 @@ class ModificationsRevealer : Revealer
         else
             dconf_keys_awaiting_hashtable.insert (key.descriptor, (DConfKey) key);
 
+        mode = get_current_delay_mode () ? Mode.DELAYED : Mode.TEMPORARY;
+
+        apply_button.sensitive = true;
         update ();
     }
 
     public void dismiss_change (Key key)
     {
+        if (mode == Mode.NONE)
+        {
+            dismiss_delayed_settings ();
+            return;
+        }
+
         key.planned_change = false;
         key.planned_value = null;
 
@@ -81,9 +123,28 @@ class ModificationsRevealer : Revealer
         else
             dconf_keys_awaiting_hashtable.remove (key.descriptor);
 
+        apply_button.sensitive = (mode != Mode.TEMPORARY) && (dconf_keys_awaiting_hashtable.length + 
gsettings_keys_awaiting_hashtable.length != 0);
         update ();
     }
 
+    public void path_changed ()
+    {
+        if (mode != Mode.TEMPORARY)
+            return;
+        if (behaviour == Behaviour.ALWAYS_CONFIRM_IMPLICIT || behaviour == Behaviour.SAFE)
+            apply_delayed_settings ();
+        else if (behaviour == Behaviour.ALWAYS_CONFIRM_EXPLICIT)
+            dismiss_delayed_settings ();
+        else
+            assert_not_reached ();
+    }
+
+    public void warn_if_no_planned_changes ()
+    {
+        if (dconf_keys_awaiting_hashtable.length == 0 && gsettings_keys_awaiting_hashtable.length == 0)
+            label.set_text (_("Nothing to reset."));
+    }
+
     /*\
     * * Buttons callbacks
     \*/
@@ -91,7 +152,8 @@ class ModificationsRevealer : Revealer
     [GtkCallback]
     public void apply_delayed_settings ()
     {
-        set_reveal_child (false);
+        mode = Mode.NONE;
+        update ();
 
         /* GSettings stuff */
 
@@ -134,12 +196,17 @@ class ModificationsRevealer : Revealer
         } catch (Error error) {
             warning (error.message);
         }
+
+        /* reload notably the hamburger menu */
+
+        reload ();
     }
 
     [GtkCallback]
     private void dismiss_delayed_settings ()
     {
-        set_reveal_child (false);
+        mode = Mode.NONE;
+        update ();
 
         /* GSettings stuff */
 
@@ -166,22 +233,43 @@ class ModificationsRevealer : Revealer
 
     private void update ()
     {
-        if (dconf_keys_awaiting_hashtable.length == 0 && gsettings_keys_awaiting_hashtable.length == 0)
+        if (mode == Mode.NONE)
         {
             set_reveal_child (false);
             label.set_text ("");
-            return;
         }
-
-        label.set_text (get_text (dconf_keys_awaiting_hashtable.length, 
gsettings_keys_awaiting_hashtable.length));
-        set_reveal_child (true);
+        else if (mode == Mode.TEMPORARY)
+        {
+            uint length = dconf_keys_awaiting_hashtable.length + gsettings_keys_awaiting_hashtable.length;
+            if (length == 0)
+                label.set_text (_("The value is invalid."));
+            else if (length != 1)
+                assert_not_reached ();
+            else if (behaviour == Behaviour.ALWAYS_CONFIRM_EXPLICIT)
+                label.set_text (_("The change will be dismissed if you quit this view without applying."));
+            else if (behaviour == Behaviour.ALWAYS_CONFIRM_IMPLICIT || behaviour == Behaviour.SAFE)
+                label.set_text (_("The change will be applied on such request or if you quit this view."));
+            else
+                assert_not_reached ();
+            set_reveal_child (true);
+        }
+        else // if (mode == Mode.DELAYED)
+        {
+            label.set_text (get_text (dconf_keys_awaiting_hashtable.length, 
gsettings_keys_awaiting_hashtable.length));
+            set_reveal_child (true);
+        }
     }
 
     private static string get_text (uint dconf, uint gsettings)     // TODO change text if current path is a 
key?
-        requires (dconf > 0 || gsettings > 0)
     {
-        if (dconf == 0) return _("%u gsettings operations awaiting.").printf (gsettings);
-        if (gsettings == 0) return _("%u dconf operations awaiting.").printf (dconf);
+        if (dconf == 0)
+        {
+            if (gsettings == 0)
+                return _("Changes will be delayed until you request it.");
+            return _("%u gsettings operations awaiting.").printf (gsettings);
+        }
+        if (gsettings == 0)
+            return _("%u dconf operations awaiting.").printf (dconf);
         return _("%u gsettings operations and %u dconf operations awaiting.").printf (gsettings, dconf);
     }
 }
diff --git a/editor/registry-info.vala b/editor/registry-info.vala
index 728bd93..5e9cb20 100644
--- a/editor/registry-info.vala
+++ b/editor/registry-info.vala
@@ -28,7 +28,7 @@ class RegistryInfo : Grid
         bool has_schema;
         unowned Variant [] dict_container;
         key.properties.get ("(ba{ss})", out has_schema, out dict_container);
-        
+
         if (!has_schema)
         {
             if (((DConfKey) key).is_ghost)
@@ -83,23 +83,47 @@ class RegistryInfo : Grid
             custom_value_switch.notify ["active"].connect (() => {
                     if (disable_revealer_for_switch)
                         disable_revealer_for_switch = false;
-                    else if (custom_value_switch.get_active ())
-                        revealer.add_delayed_setting (key, null);
+                    else if (revealer.should_delay_apply (tmp_string))
+                    {
+                        if (custom_value_switch.get_active ())
+                            revealer.add_delayed_setting (key, null);
+                        else
+                        {
+                            Variant tmp_variant = key.planned_change && (key.planned_value != null) ? 
key.planned_value : key.value;
+                            revealer.add_delayed_setting (key, tmp_variant);
+                            key_editor_child.reload (tmp_variant);
+                        }
+                    }
                     else
                     {
-                        Variant tmp_variant = key.planned_change && (key.planned_value != null) ? 
key.planned_value : key.value;
-                        revealer.add_delayed_setting (key, tmp_variant);
-                        key_editor_child.reload (tmp_variant);
+                        if (custom_value_switch.get_active ())
+                        {
+                            ((GSettingsKey) key).set_to_default ();
+                            disable_revealer_for_value = true;
+                            key_editor_child.reload (key.value);
+                            if (tmp_string == "<flags>")
+                                key.planned_value = key.value;
+                        }
+                        else
+                            key.value = key.value;  // TODO that hurts...
                     }
                 });
         }
         key_editor_child.value_has_changed.connect ((enable_revealer, is_valid) => {
                 if (disable_revealer_for_value)
                     disable_revealer_for_value = false;
-                else if (enable_revealer && is_valid)
-                    revealer.add_delayed_setting (key, key_editor_child.get_variant ());
-                else if (enable_revealer && !is_valid)
-                    revealer.dismiss_change (key);
+                else if (enable_revealer)
+                {
+                    if (revealer.should_delay_apply (tmp_string))
+                    {
+                        if (is_valid)
+                            revealer.add_delayed_setting (key, key_editor_child.get_variant ());
+                        else
+                            revealer.dismiss_change (key);
+                    }
+                    else
+                        key.value = key_editor_child.get_variant ();
+                }
             });
         key_editor_child.child_activated.connect (() => { revealer.apply_delayed_settings (); });  // TODO 
"only" used for string-based and spin widgets
         revealer.reload.connect (() => {
diff --git a/editor/registry-view.vala b/editor/registry-view.vala
index 035725e..e581283 100644
--- a/editor/registry-view.vala
+++ b/editor/registry-view.vala
@@ -22,8 +22,7 @@ class RegistryView : Grid
 {
     public string current_path { get; private set; }
     public bool show_search_bar { get; set; }
-    public bool delayed_apply_menu { get; set; }
-    public bool planned_change { get { return revealer.get_reveal_child (); }}
+    public Behaviour behaviour { get; set; }
 
     private SettingsModel model = new SettingsModel ();
     [GtkChild] private TreeView dir_tree_view;
@@ -50,6 +49,7 @@ class RegistryView : Grid
         search_entry.get_buffer ().deleted_text.connect (() => { search_next_button.set_sensitive (true); });
         search_bar.connect_entry (search_entry);
         bind_property ("show-search-bar", search_bar, "search-mode-enabled", BindingFlags.BIDIRECTIONAL);   
// TODO in UI file?
+        bind_property ("behaviour", revealer, "behaviour", 
BindingFlags.BIDIRECTIONAL|BindingFlags.SYNC_CREATE);
     }
 
     public void init (string path, bool restore_view)
@@ -67,8 +67,9 @@ class RegistryView : Grid
 
     private void update_current_path (string path)
     {
+        revealer.path_changed ();
         current_path = path;
-        ((DConfWindow) this.get_parent ()).update_current_path ();
+        ((DConfWindow) this.get_parent ()).update_hamburger_menu ();
     }
 
     /*\
@@ -183,7 +184,7 @@ class RegistryView : Grid
         if (event.button == Gdk.BUTTON_SECONDARY)
         {
             ClickableListBoxRow row = (ClickableListBoxRow) widget;
-            row.show_right_click_popover (delayed_apply_menu || planned_change, (int) (event.x - 
row.get_allocated_width () / 2.0));
+            row.show_right_click_popover (get_current_delay_mode (), (int) (event.x - 
row.get_allocated_width () / 2.0));
             rows_possibly_with_popover.append (row);
         }
 
@@ -209,15 +210,27 @@ class RegistryView : Grid
             row = (ClickableListBoxRow?) rows_possibly_with_popover.get_item (position);
         }
         rows_possibly_with_popover.remove_all ();
+        ((DConfWindow) this.get_parent ()).update_hamburger_menu ();
     }
 
     /*\
     * * Revealer stuff
     \*/
 
+    public bool get_current_delay_mode ()
+    {
+        return revealer.get_current_delay_mode ();
+    }
+
+    public void enter_delay_mode ()
+    {
+        revealer.enter_delay_mode ();
+        ((DConfWindow) this.get_parent ()).update_hamburger_menu ();
+    }
+
     private void set_key_value (Key key, Variant? new_value)
     {
-        if (delayed_apply_menu || planned_change)
+        if (get_current_delay_mode ())
             revealer.add_delayed_setting (key, new_value);
         else if (new_value != null)
             key.value = (!) new_value;
@@ -233,11 +246,13 @@ class RegistryView : Grid
 
     public void reset (bool recursively)
     {
+        revealer.enter_delay_mode ();
         reset_generic (key_model, recursively);
         invalidate_popovers ();
+        revealer.warn_if_no_planned_changes ();
     }
 
-    private void reset_generic (GLib.ListStore? objects, bool recursively)   // TODO notification if nothing 
to reset
+    private void reset_generic (GLib.ListStore? objects, bool recursively)
     {
         if (objects == null)
             return;
@@ -302,7 +317,7 @@ class RegistryView : Grid
             return false;
 
         ClickableListBoxRow row = (ClickableListBoxRow) ((!) selected_row).get_child ();
-        row.show_right_click_popover (delayed_apply_menu || planned_change);
+        row.show_right_click_popover (get_current_delay_mode ());
         rows_possibly_with_popover.append (row);
         return true;
     }


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