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.
This commit is contained in:
parent
81f8ddbe43
commit
d61d49bef9
4 changed files with 469 additions and 147 deletions
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
||||
|
||||
private Components.NetworkAddressValidator 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 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue