[geary/wip/714104-refine-account-dialog] Use a command stack with Accounts.EditorServerPane



commit d61d49bef908d8b0661e7713d27d6db2dbe224f7
Author: Michael Gratton <mike vee net>
Date:   Thu Dec 20 19:53:27 2018 +1100

    Use a command stack with Accounts.EditorServerPane
    
    Use the stack to apply changes to the service config copies and update
    the apply button's state.

 src/client/accounts/accounts-editor-row.vala       |  56 +++-
 .../accounts/accounts-editor-servers-pane.vala     | 369 ++++++++++++++++-----
 src/client/application/application-command.vala    |  54 +++
 ui/accounts_editor_servers_pane.ui                 | 137 ++++----
 4 files changed, 469 insertions(+), 147 deletions(-)
---
diff --git a/src/client/accounts/accounts-editor-row.vala b/src/client/accounts/accounts-editor-row.vala
index 6a3716a3..12c828d6 100644
--- a/src/client/accounts/accounts-editor-row.vala
+++ b/src/client/accounts/accounts-editor-row.vala
@@ -357,7 +357,7 @@ private abstract class Accounts.ServiceRow<PaneType,V> : AccountRow<PaneType,V>
                       V value) {
         base(account, label, value);
         this.service = service;
-        this.service.notify.connect(on_notify);
+        this.service.notify.connect_after(on_notify);
 
         bool is_editable = this.is_value_editable;
         set_activatable(is_editable);
@@ -383,6 +383,60 @@ private abstract class Accounts.ServiceRow<PaneType,V> : AccountRow<PaneType,V>
 }
 
 
+/** Interface for rows that use a validator for editable values. */
+internal interface Accounts.ValidatingRow : EditorRow {
+
+
+    /** The row's validator */
+    public abstract Components.Validator validator { get; protected set; }
+
+    /** Determines if the row's value has actually changed. */
+    public abstract bool has_changed { get; }
+
+    /** Fired when validated and the value has actually changed. */
+    public signal void changed();
+
+    /** Fired when validated and the value has actually changed. */
+    public signal void committed();
+
+    /**
+     * Hooks up signals to the validator.
+     *
+     * Implementing classes should call this in their constructor
+     * after having constructed a validator
+     */
+    protected void setup_validator() {
+        this.validator.changed.connect(on_validator_changed);
+        this.validator.activated.connect(on_validator_check_commit);
+        this.validator.focus_lost.connect(on_validator_check_commit);
+    }
+
+    /**
+     * Called when the row's value should be stored.
+     *
+     * This is only called when the row's value has changed, is
+     * valid, and the user has activated or changed to a different
+     * row. */
+    protected virtual void commit() {
+        // noop
+    }
+
+    private void on_validator_changed() {
+        if (this.has_changed) {
+            changed();
+        }
+    }
+
+    private void on_validator_check_commit() {
+        if (this.has_changed) {
+            commit();
+            committed();
+        }
+    }
+
+}
+
+
 internal class Accounts.TlsComboBox : Gtk.ComboBox {
 
     private const string INSECURE_ICON = "channel-insecure-symbolic";
diff --git a/src/client/accounts/accounts-editor-servers-pane.vala 
b/src/client/accounts/accounts-editor-servers-pane.vala
index 0d919d8d..beaf333b 100644
--- a/src/client/accounts/accounts-editor-servers-pane.vala
+++ b/src/client/accounts/accounts-editor-servers-pane.vala
@@ -15,6 +15,11 @@ internal class Accounts.EditorServersPane : Gtk.Grid, EditorPane, AccountPane {
 
     internal Geary.AccountInformation account { get ; protected set; }
 
+    /** Command stack for pane user commands. */
+    internal Application.CommandStack commands {
+        get; private set; default = new Application.CommandStack();
+    }
+
     protected weak Accounts.Editor editor { get; set; }
 
     private Geary.Engine engine;
@@ -24,6 +29,9 @@ internal class Accounts.EditorServersPane : Gtk.Grid, EditorPane, AccountPane {
     private Geary.ServiceInformation incoming_mutable;
     private Geary.ServiceInformation outgoing_mutable;
 
+    private Gee.List<Components.Validator> validators =
+        new Gee.LinkedList<Components.Validator>();
+
 
     [GtkChild]
     private Gtk.HeaderBar header;
@@ -52,6 +60,8 @@ internal class Accounts.EditorServersPane : Gtk.Grid, EditorPane, AccountPane {
     [GtkChild]
     private Gtk.Spinner apply_spinner;
 
+    private ServiceLoginRow incoming_login;
+
     private SaveDraftsRow save_drafts;
     private ServiceSmtpAuthRow smtp_auth;
     private ServiceLoginRow smtp_login;
@@ -66,6 +76,8 @@ internal class Accounts.EditorServersPane : Gtk.Grid, EditorPane, AccountPane {
 
         this.pane_content.set_focus_vadjustment(this.pane_adjustment);
 
+        // Details
+
         this.details_list.set_header_func(Editor.seperator_headers);
         // Only add an account provider if it is esoteric enough.
         if (this.account.mediator is GoaMediator) {
@@ -80,44 +92,91 @@ internal class Accounts.EditorServersPane : Gtk.Grid, EditorPane, AccountPane {
             );
         service_provider.set_dim_label(true);
         service_provider.activatable = false;
-        this.details_list.add(service_provider);
-        this.save_drafts = new SaveDraftsRow(this.account);
-        this.details_list.add(this.save_drafts);
+        add_row(this.details_list, service_provider);
+
+        this.save_drafts = new SaveDraftsRow(this.account, this.commands);
+        add_row(this.details_list, this.save_drafts);
+
+        // Receiving
 
         this.receiving_list.set_header_func(Editor.seperator_headers);
-        this.receiving_list.add(new ServiceHostRow(account, this.incoming_mutable));
-        this.receiving_list.add(new ServiceSecurityRow(account, this.incoming_mutable));
-        this.receiving_list.add(new ServiceLoginRow(account, this.incoming_mutable));
+        add_row(
+            this.receiving_list,
+            new ServiceHostRow(account, this.incoming_mutable, this.commands)
+        );
+        add_row(
+            this.receiving_list,
+            new ServiceSecurityRow(account, this.incoming_mutable, this.commands)
+        );
+
+        this.incoming_login = new ServiceLoginRow(
+            account, this.incoming_mutable, this.commands
+        );
+        add_row(this.receiving_list, this.incoming_login);
+
+        // Sending
 
         this.sending_list.set_header_func(Editor.seperator_headers);
-        this.sending_list.add(new ServiceHostRow(account, this.outgoing_mutable));
-        this.sending_list.add(new ServiceSecurityRow(account, this.outgoing_mutable));
+        add_row(
+            this.sending_list,
+            new ServiceHostRow(account, this.outgoing_mutable, this.commands)
+        );
+        add_row(
+            this.sending_list,
+            new ServiceSecurityRow(account, this.outgoing_mutable, this.commands)
+        );
         this.smtp_auth = new ServiceSmtpAuthRow(
-            account, this.outgoing_mutable, this.incoming_mutable
+            account, this.outgoing_mutable, this.incoming_mutable, this.commands
         );
         this.smtp_auth.value.changed.connect(on_smtp_auth_changed);
-        this.sending_list.add(this.smtp_auth);
-        this.smtp_login = new ServiceLoginRow(account, this.outgoing_mutable);
-        this.sending_list.add(this.smtp_login);
+        add_row(this.sending_list, this.smtp_auth);
+
+        this.smtp_login = new ServiceLoginRow(
+            account, this.outgoing_mutable, this.commands
+        );
+        add_row(this.sending_list, this.smtp_login);
+
+        // Misc plumbing
 
         this.account.changed.connect(on_account_changed);
 
+        this.commands.executed.connect(on_command);
+        this.commands.undone.connect(on_command);
+        this.commands.redone.connect(on_command);
+
         update_header();
         update_smtp_auth();
     }
 
     ~EditorServersPane() {
         this.account.changed.disconnect(on_account_changed);
+
+        this.commands.executed.disconnect(on_command);
+        this.commands.undone.disconnect(on_command);
+        this.commands.redone.disconnect(on_command);
     }
 
     internal Gtk.HeaderBar get_header() {
         return this.header;
     }
 
+    internal void undo() {
+        this.commands.undo.begin(null);
+    }
+
+    internal void redo() {
+        this.commands.redo.begin(null);
+    }
+
+    private bool is_valid() {
+        return Geary.traverse(this.validators).all((v) => v.is_valid);
+    }
+
     private async void save(GLib.Cancellable? cancellable) {
         this.apply_button.set_sensitive(false);
         this.apply_spinner.show();
         this.apply_spinner.start();
+        this.set_sensitive(false);
 
         // Only need to validate if a generic account
         bool is_valid = true;
@@ -141,7 +200,6 @@ internal class Accounts.EditorServersPane : Gtk.Grid, EditorPane, AccountPane {
 
         if (is_valid) {
             if (this.save_drafts.value_changed) {
-                this.account.save_drafts = this.save_drafts.value.state;
                 has_changed = true;
             }
 
@@ -150,11 +208,20 @@ internal class Accounts.EditorServersPane : Gtk.Grid, EditorPane, AccountPane {
             }
 
             this.editor.pop();
+        } else {
+            // Re-enable apply so that the same config can be re-tried
+            // in the face of transient errors, without having to
+            // change something to re-enable it
+            this.apply_button.set_sensitive(true);
+
+            // Undo save_drafts manually since it would have been
+            // updated already by the command
+            this.account.save_drafts = this.save_drafts.initial_value;
         }
 
-        this.apply_button.set_sensitive(true);
         this.apply_spinner.stop();
         this.apply_spinner.hide();
+        this.set_sensitive(true);
     }
 
     private async bool validate(GLib.Cancellable? cancellable) {
@@ -222,12 +289,43 @@ internal class Accounts.EditorServersPane : Gtk.Grid, EditorPane, AccountPane {
         notification.show();
     }
 
+    private void add_row(Gtk.ListBox list, EditorRow<EditorServersPane> row) {
+        list.add(row);
+        ValidatingRow? validating = row as ValidatingRow;
+        if (validating != null) {
+            validating.changed.connect(on_validator_changed);
+            validating.validator.activated.connect_after(on_validator_activated);
+            this.validators.add(validating.validator);
+        }
+    }
+
+    private void update_actions() {
+        this.editor.get_action(GearyController.ACTION_UNDO).set_enabled(
+            this.commands.can_undo
+        );
+        this.editor.get_action(GearyController.ACTION_REDO).set_enabled(
+            this.commands.can_redo
+        );
+
+        this.apply_button.set_sensitive(this.commands.can_undo);
+    }
+
     private void update_smtp_auth() {
         this.smtp_login.set_visible(
-            this.smtp_auth.value.source == Geary.Credentials.Requirement.CUSTOM
+            this.smtp_auth.value.source == CUSTOM
         );
     }
 
+    private void on_validator_changed() {
+        this.apply_button.set_sensitive(is_valid());
+    }
+
+    private void on_validator_activated() {
+        if (is_valid()) {
+            this.apply_button.clicked();
+        }
+    }
+
     [GtkCallback]
     private void on_cancel_button_clicked() {
         this.editor.pop();
@@ -268,6 +366,10 @@ internal class Accounts.EditorServersPane : Gtk.Grid, EditorPane, AccountPane {
         update_header();
     }
 
+    private void on_command() {
+        update_actions();
+    }
+
     private void on_smtp_auth_changed() {
         update_smtp_auth();
     }
@@ -353,11 +455,12 @@ private class Accounts.SaveDraftsRow :
     public bool value_changed {
         get { return this.initial_value != this.value.state; }
     }
+    public bool initial_value { get; private set; }
 
-    private bool initial_value;
-
+    private Application.CommandStack commands;
 
-    public SaveDraftsRow(Geary.AccountInformation account) {
+    public SaveDraftsRow(Geary.AccountInformation account,
+                         Application.CommandStack commands) {
         Gtk.Switch value = new Gtk.Switch();
         base(
             account,
@@ -366,32 +469,56 @@ private class Accounts.SaveDraftsRow :
             _("Save drafts on server"),
             value
         );
-        set_activatable(false);
         update();
-        value.notify["active"].connect(on_activate);
+        this.commands = commands;
+        this.activatable = false;
+        this.initial_value = this.account.save_drafts;
+        this.account.notify["save-drafts"].connect(on_account_changed);
+        this.value.notify["active"].connect(on_activate);
     }
 
     public override void update() {
-        this.initial_value = this.account.save_drafts;
-        this.value.state = this.initial_value;
+        this.value.state = this.account.save_drafts;
     }
 
     private void on_activate() {
-        this.account.save_drafts = this.value.state;
+        if (this.value.state != this.account.save_drafts) {
+            this.commands.execute.begin(
+                new Application.PropertyCommand<bool>(
+                    this.account, "save_drafts", this.value.state
+                ),
+                null
+            );
+        }
+    }
+
+    private void on_account_changed() {
+        update();
     }
 
 }
 
 
 private class Accounts.ServiceHostRow :
-    ServiceRow<EditorServersPane,Gtk.Entry> {
+    ServiceRow<EditorServersPane,Gtk.Entry>, ValidatingRow {
+
+
+    public Components.Validator validator {
+        get; protected set;
+    }
 
+    public bool has_changed {
+        get {
+            return this.value.text.strip() != get_entry_text();
+        }
+    }
 
-    private Components.NetworkAddressValidator validator;
+    private Application.CommandStack commands;
 
 
     public ServiceHostRow(Geary.AccountInformation account,
-                          Geary.ServiceInformation service) {
+                          Geary.ServiceInformation service,
+                          Application.CommandStack commands) {
         string label = "";
         switch (service.protocol) {
         case Geary.Protocol.IMAP:
@@ -408,21 +535,47 @@ private class Accounts.ServiceHostRow :
         }
 
         base(account, service, label, new Gtk.Entry());
-        update();
+        this.commands = commands;
         this.activatable = false;
         this.validator = new Components.NetworkAddressValidator(this.value);
-        this.validator.state_changed.connect(on_validation_changed);
+
+        // Update after the validator is wired up to ensure the value
+        // is validated
+        setup_validator();
+        update();
     }
 
     public override void update() {
-        string value = get_host_text();
+        string value = get_entry_text();
         if (Geary.String.is_empty(value)) {
             value = _("None");
         }
         this.value.text = value;
     }
 
-    private string? get_host_text() {
+    protected void commit() {
+        GLib.NetworkAddress? address =
+            ((Components.NetworkAddressValidator) this.validator)
+            .validated_address;
+        if (address != null) {
+            uint16 port = address.port != 0
+            ? (uint16) address.port
+            : this.service.get_default_port();
+            this.commands.execute.begin(
+                new Application.CommandSequence({
+                        new Application.PropertyCommand<string>(
+                            this.service, "host", address.hostname
+                        ),
+                        new Application.PropertyCommand<uint16>(
+                            this.service, "port", port
+                        )
+                }),
+                null
+                );
+        }
+    }
+
+    private string? get_entry_text() {
         string? value = this.service.host ?? "";
         if (!Geary.String.is_empty(value)) {
             // Only show the port if it not the appropriate default port
@@ -434,31 +587,26 @@ private class Accounts.ServiceHostRow :
         return value;
     }
 
-    private void on_validation_changed() {
-        if (this.validator.state == Components.Validator.Validity.VALID) {
-            GLib.NetworkAddress? address = this.validator.validated_address;
-            if (address != null) {
-                this.service.host = address.hostname;
-                this.service.port = address.port != 0
-                    ? (uint16) address.port
-                    : this.service.get_default_port();
-            }
-        }
-    }
-
 }
 
 
 private class Accounts.ServiceSecurityRow :
     ServiceRow<EditorServersPane,TlsComboBox> {
 
+
+    private Application.CommandStack commands;
+
+
     public ServiceSecurityRow(Geary.AccountInformation account,
-                              Geary.ServiceInformation service) {
+                              Geary.ServiceInformation service,
+                              Application.CommandStack commands) {
         TlsComboBox value = new TlsComboBox();
         base(account, service, value.label, value);
-        set_activatable(false);
-        value.changed.connect(on_value_changed);
         update();
+
+        this.commands = commands;
+        this.activatable = false;
+        value.changed.connect(on_value_changed);
     }
 
     public override void update() {
@@ -467,15 +615,29 @@ private class Accounts.ServiceSecurityRow :
 
     private void on_value_changed() {
         if (this.service.transport_security != this.value.method) {
+            Application.Command cmd = new Application.PropertyCommand<uint>(
+                this.service, "transport-security", this.value.method
+            );
+
+            debug("Security port: %u", this.service.port);
+
             // Update the port if we're currently using the default,
             // otherwise keep the custom port as-is.
-            bool update_port = (
-                this.service.port == this.service.get_default_port()
-            );
-            this.service.transport_security = this.value.method;
-            if (update_port) {
-                this.service.port = this.service.get_default_port();
+            if (this.service.port == this.service.get_default_port()) {
+                // Work out what the new port would be by copying the
+                // service and applying the new security param up
+                // front
+                Geary.ServiceInformation copy =
+                    new Geary.ServiceInformation.copy(this.service);
+                copy.transport_security = this.value.method;
+                cmd = new Application.CommandSequence(
+                    {cmd,
+                     new Application.PropertyCommand<uint>(
+                         this.service, "port", copy.get_default_port()
+                     )
+                    });
             }
+            this.commands.execute.begin(cmd, null);
         }
     }
 
@@ -483,14 +645,25 @@ private class Accounts.ServiceSecurityRow :
 
 
 private class Accounts.ServiceLoginRow :
-    ServiceRow<EditorServersPane,Gtk.Entry> {
+    ServiceRow<EditorServersPane,Gtk.Entry>, ValidatingRow {
 
 
-    public Components.Validator validator;
+    public Components.Validator validator {
+        get; protected set;
+    }
+
+    public bool has_changed {
+        get {
+            return this.value.text.strip() != get_entry_text();
+        }
+    }
+
+    private Application.CommandStack commands;
 
 
     public ServiceLoginRow(Geary.AccountInformation account,
-                           Geary.ServiceInformation service) {
+                           Geary.ServiceInformation service,
+                           Application.CommandStack commands) {
         base(
             account,
             service,
@@ -500,17 +673,37 @@ private class Accounts.ServiceLoginRow :
             new Gtk.Entry()
         );
 
-        update();
+        this.commands = commands;
         this.activatable = false;
         this.validator = new Components.Validator(this.value);
-        this.validator.state_changed.connect(on_validation_changed);
+
+        // Update after the validator is wired up to ensure the value
+        // is validated
+        update();
+        setup_validator();
     }
 
     public override void update() {
-        this.value.text = get_login_text();
+        this.value.text = get_entry_text();
     }
 
-    private string? get_login_text() {
+    protected void commit() {
+        if (this.service.credentials != null) {
+            this.commands.execute.begin(
+                new Application.PropertyCommand<Geary.Credentials?>(
+                    this.service,
+                    "credentials",
+                    new Geary.Credentials(
+                        this.service.credentials.supported_method,
+                        this.value.text
+                    )
+                ),
+                null
+            );
+        }
+    }
+
+    private string? get_entry_text() {
         string? label = null;
         if (this.service.credentials != null) {
             string method = "%s";
@@ -551,31 +744,29 @@ private class Accounts.ServiceLoginRow :
         return label;
     }
 
-    private void on_validation_changed() {
-        if (this.validator.state == Components.Validator.Validity.VALID) {
-            this.service.credentials =
-                this.service.credentials.copy_with_user(this.value.text);
-        }
-    }
-
 }
 
+
 private class Accounts.ServiceSmtpAuthRow :
     ServiceRow<EditorServersPane,SmtpAuthComboBox> {
 
 
-    Geary.ServiceInformation imap_service;
+    private Application.CommandStack commands;
+    private Geary.ServiceInformation imap_service;
 
 
     public ServiceSmtpAuthRow(Geary.AccountInformation account,
                               Geary.ServiceInformation smtp_service,
-                              Geary.ServiceInformation imap_service) {
+                              Geary.ServiceInformation imap_service,
+                              Application.CommandStack commands) {
         SmtpAuthComboBox value = new SmtpAuthComboBox();
         base(account, smtp_service, value.label, value);
+        update();
+
+        this.commands = commands;
         this.imap_service = imap_service;
         this.activatable = false;
         value.changed.connect(on_value_changed);
-        update();
     }
 
     public override void update() {
@@ -584,21 +775,43 @@ private class Accounts.ServiceSmtpAuthRow :
 
     private void on_value_changed() {
         if (this.service.credentials_requirement != this.value.source) {
+            // Need to update the credentials given the new
+            // requirements, too
+            Geary.Credentials? new_creds = null;
+            if (this.value.source == CUSTOM) {
+                new_creds = new Geary.Credentials(
+                    Geary.Credentials.Method.PASSWORD, ""
+                );
+            }
+
+            Application.CommandSequence seq = new Application.CommandSequence({
+                    new Application.PropertyCommand<Geary.Credentials?>(
+                        this.service, "credentials", new_creds
+                    ),
+                    new Application.PropertyCommand<uint>(
+                        this.service, "credentials-requirement", this.value.source
+                    )
+                });
+
             // The default SMTP port also depends on the auth method
             // used, so also update the port here if we're currently
             // using the default, otherwise keep the custom port
             // as-is.
-            bool update_port = (
-                this.service.port == this.service.get_default_port()
-            );
-            this.service.credentials_requirement = this.value.source;
-            this.service.credentials =
-                (this.service.credentials_requirement != CUSTOM)
-                ? null
-                : new Geary.Credentials(Geary.Credentials.Method.PASSWORD, "");
-            if (update_port) {
-                this.service.port = this.service.get_default_port();
+            if (this.service.port == this.service.get_default_port()) {
+                // Work out what the new port would be by copying the
+                // service and applying the new security param up
+                // front
+                Geary.ServiceInformation copy =
+                    new Geary.ServiceInformation.copy(this.service);
+                copy.credentials_requirement = this.value.source;
+                seq.commands.add(
+                    new Application.PropertyCommand<uint>(
+                        this.service, "port", copy.get_default_port()
+                    )
+                );
             }
+
+            this.commands.execute.begin(seq, null);
         }
     }
 
diff --git a/src/client/application/application-command.vala b/src/client/application/application-command.vala
index 55d80730..3a21027f 100644
--- a/src/client/application/application-command.vala
+++ b/src/client/application/application-command.vala
@@ -108,6 +108,60 @@ public abstract class Application.Command : GLib.Object {
 }
 
 
+/**
+ * A command that executes a sequence of other commands.
+ */
+public class Application.CommandSequence : Command {
+
+
+    public Gee.List<Command> commands {
+        get; private set; default = new Gee.LinkedList<Command>();
+    }
+
+    public CommandSequence(Command[]? commands = null) {
+        if (commands != null) {
+            this.commands.add_all_array(commands);
+        }
+    }
+
+
+    /**
+     * Executes all commands in the sequence, sequentially.
+     */
+    public override async void execute(GLib.Cancellable? cancellable)
+       throws GLib.Error {
+       foreach (Command command in this.commands) {
+           yield command.execute(cancellable);
+       }
+    }
+
+    /**
+     * Un-does all commands in the sequence, in reverse order.
+     */
+    public override async void undo(GLib.Cancellable? cancellable)
+       throws GLib.Error {
+       Gee.LinkedList<Command> reversed = new Gee.LinkedList<Command>();
+       foreach (Command command in this.commands) {
+           reversed.insert(0, command);
+       }
+       foreach (Command command in this.commands) {
+           yield command.undo(cancellable);
+       }
+    }
+
+    /**
+     * Re-does all commands in the sequence, sequentially.
+     */
+    public override async void redo(GLib.Cancellable? cancellable)
+       throws GLib.Error {
+       foreach (Command command in this.commands) {
+           yield command.redo(cancellable);
+       }
+    }
+
+}
+
+
 /**
  * A command that updates a GObject instance property.
  *
diff --git a/ui/accounts_editor_servers_pane.ui b/ui/accounts_editor_servers_pane.ui
index 6b2101e4..9a165a12 100644
--- a/ui/accounts_editor_servers_pane.ui
+++ b/ui/accounts_editor_servers_pane.ui
@@ -2,6 +2,75 @@
 <!-- Generated with glade 3.22.1 -->
 <interface>
   <requires lib="gtk+" version="3.20"/>
+  <object class="GtkHeaderBar" id="header">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="title">Server Settings</property>
+    <property name="subtitle">Account Name</property>
+    <property name="show_close_button">True</property>
+    <child>
+      <object class="GtkGrid">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <child>
+          <object class="GtkButton" id="cancel_button">
+            <property name="label" translatable="yes">Cancel</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">True</property>
+            <signal name="clicked" handler="on_cancel_button_clicked" swapped="no"/>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <child>
+      <object class="GtkGrid">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="column_spacing">12</property>
+        <child>
+          <object class="GtkSpinner" id="apply_spinner">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkButton" id="apply_button">
+            <property name="label" translatable="yes">Apply</property>
+            <property name="visible">True</property>
+            <property name="sensitive">False</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">True</property>
+            <signal name="clicked" handler="on_apply_button_clicked" swapped="no"/>
+            <style>
+              <class name="suggested-action"/>
+            </style>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="pack_type">end</property>
+        <property name="position">1</property>
+      </packing>
+    </child>
+  </object>
+  <object class="GtkAdjustment" id="pane_adjustment">
+    <property name="upper">100</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">10</property>
+  </object>
   <template class="AccountsEditorServersPane" parent="GtkGrid">
     <property name="name">1</property>
     <property name="visible">True</property>
@@ -154,72 +223,4 @@
       <class name="geary-accounts-editor-pane"/>
     </style>
   </template>
-  <object class="GtkHeaderBar" id="header">
-    <property name="visible">True</property>
-    <property name="can_focus">False</property>
-    <property name="title">Server Settings</property>
-    <property name="subtitle">Account Name</property>
-    <property name="show_close_button">True</property>
-    <child>
-      <object class="GtkGrid">
-        <property name="visible">True</property>
-        <property name="can_focus">False</property>
-        <child>
-          <object class="GtkButton" id="cancel_button">
-            <property name="label" translatable="yes">Cancel</property>
-            <property name="visible">True</property>
-            <property name="can_focus">True</property>
-            <property name="receives_default">True</property>
-            <signal name="clicked" handler="on_cancel_button_clicked" swapped="no"/>
-          </object>
-          <packing>
-            <property name="left_attach">0</property>
-            <property name="top_attach">0</property>
-          </packing>
-        </child>
-      </object>
-    </child>
-    <child>
-      <object class="GtkGrid">
-        <property name="visible">True</property>
-        <property name="can_focus">False</property>
-        <property name="column_spacing">12</property>
-        <child>
-          <object class="GtkSpinner" id="apply_spinner">
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
-          </object>
-          <packing>
-            <property name="left_attach">0</property>
-            <property name="top_attach">0</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkButton" id="apply_button">
-            <property name="label" translatable="yes">Apply</property>
-            <property name="visible">True</property>
-            <property name="can_focus">True</property>
-            <property name="receives_default">True</property>
-            <signal name="clicked" handler="on_apply_button_clicked" swapped="no"/>
-            <style>
-              <class name="suggested-action"/>
-            </style>
-          </object>
-          <packing>
-            <property name="left_attach">1</property>
-            <property name="top_attach">0</property>
-          </packing>
-        </child>
-      </object>
-      <packing>
-        <property name="pack_type">end</property>
-        <property name="position">1</property>
-      </packing>
-    </child>
-  </object>
-  <object class="GtkAdjustment" id="pane_adjustment">
-    <property name="upper">100</property>
-    <property name="step_increment">1</property>
-    <property name="page_increment">10</property>
-  </object>
 </interface>


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