From fcfb46008ba389fe6321fb66aba3325e58ca9875 Mon Sep 17 00:00:00 2001 From: Eric Gregory Date: Mon, 28 Jan 2013 16:59:53 -0800 Subject: [PATCH] Closes #4580 Edit existing accounts Squashed commit of the following: commit e7af3b721314513fc6ea2eb57d10086e4f1e148b Author: Eric Gregory Date: Mon Jan 28 16:53:56 2013 -0800 Account dialog is back to being modal commit cdd214070e67dc735c819df06c46a1d128ef20d2 Author: Eric Gregory Date: Fri Jan 25 18:14:17 2013 -0800 Fix for password issue commit 847da391373357bbca90ef6d8028ea8ff85458f1 Author: Eric Gregory Date: Fri Jan 25 17:20:12 2013 -0800 Merging in changes commit 7745ac1426fb8560624fed752de0ee162f97bd9e Author: Eric Gregory Date: Fri Jan 25 15:53:49 2013 -0800 Changes from code review commit d7727544aaeacceb5c9b0ac3444a6db0311929db Author: Eric Gregory Date: Thu Jan 24 17:10:18 2013 -0800 Account editing, various account management bug fixes --- .../account-dialog-account-list-pane.vala | 55 ++++++++++- .../account-dialog-add-edit-pane.vala | 23 ++++- src/client/accounts/account-dialog.vala | 35 +++++-- src/client/accounts/add-edit-page.vala | 92 +++++++++++++++---- src/client/accounts/login-dialog.vala | 21 +---- src/client/geary-application.vala | 9 +- src/client/geary-controller.vala | 2 - ui/account_list.glade | 19 ++++ 8 files changed, 197 insertions(+), 59 deletions(-) diff --git a/src/client/accounts/account-dialog-account-list-pane.vala b/src/client/accounts/account-dialog-account-list-pane.vala index def829ec..e1361b36 100644 --- a/src/client/accounts/account-dialog-account-list-pane.vala +++ b/src/client/accounts/account-dialog-account-list-pane.vala @@ -8,10 +8,12 @@ public class AccountDialogAccountListPane : Gtk.Box { private Gtk.TreeView list_view; private Gtk.ListStore list_model = new Gtk.ListStore(1, typeof (string)); - private Gtk.ActionGroup actions; + private Gtk.Action edit_action; public signal void add_account(); + public signal void edit_account(string email_address); + public signal void close(); public AccountDialogAccountListPane() { @@ -23,9 +25,15 @@ public class AccountDialogAccountListPane : Gtk.Box { list_view = (Gtk.TreeView) builder.get_object("account_list"); list_view.set_model(list_model); list_view.insert_column_with_attributes (-1, "Account", new Gtk.CellRendererText (), "text", 0); - actions = (Gtk.ActionGroup) builder.get_object("account list actions"); + Gtk.ActionGroup actions = (Gtk.ActionGroup) builder.get_object("account list actions"); + edit_action = actions.get_action("edit_account"); + + // Hook up signals. actions.get_action("close").activate.connect(() => { close(); }); actions.get_action("add_account").activate.connect(() => { add_account(); }); + edit_action.activate.connect(notify_edit_account); + list_view.get_selection().changed.connect(on_selection_changed); + list_view.button_press_event.connect(on_button_press); // Theme hint: "join" the toolbar to the scrolled window above it. Gtk.Toolbar toolbar = (Gtk.Toolbar) builder.get_object("toolbar"); @@ -46,6 +54,49 @@ public class AccountDialogAccountListPane : Gtk.Box { Geary.Engine.instance.account_removed.connect(on_account_removed); } + private void notify_edit_account() { + string? account = get_selected_account(); + if (account != null) + edit_account(account); + } + + private bool on_button_press(Gdk.EventButton event) { + if (event.type != Gdk.EventType.2BUTTON_PRESS) + return false; + + // Get the path. + int cell_x; + int cell_y; + Gtk.TreePath? path; + list_view.get_path_at_pos((int) event.x, (int) event.y, out path, null, out cell_x, out cell_y); + if (path == null) + return false; + + // If the user didn't click on an element in the list, we've already returned. + notify_edit_account(); + return true; + } + + // Returns the email address of the selected account. Returns null if no account is selected. + private string? get_selected_account() { + if (list_view.get_selection().count_selected_rows() != 1) + return null; + + Gtk.TreeModel model; + Gtk.TreeIter iter; + Gtk.TreePath path = list_view.get_selection().get_selected_rows(out model).nth_data(0); + if (!list_model.get_iter(out iter, path)) + return null; + + string? account = null; + list_model.get(iter, 0, out account); + return account; + } + + private void on_selection_changed() { + edit_action.sensitive = get_selected_account() != null; + } + private void on_account_added(Geary.AccountInformation account) { Gtk.TreeIter? iter = list_contains(account.email); if (iter != null) diff --git a/src/client/accounts/account-dialog-add-edit-pane.vala b/src/client/accounts/account-dialog-add-edit-pane.vala index fbfffcf9..1d7e3251 100644 --- a/src/client/accounts/account-dialog-add-edit-pane.vala +++ b/src/client/accounts/account-dialog-add-edit-pane.vala @@ -8,7 +8,7 @@ public class AccountDialogAddEditPane : Gtk.Box { public AddEditPage add_edit_page { get; private set; default = new AddEditPage(); } private Gtk.ButtonBox button_box = new Gtk.ButtonBox(Gtk.Orientation.HORIZONTAL); - private Gtk.Button ok_button = new Gtk.Button.from_stock(Gtk.Stock.ADD); + private Gtk.Button ok_button = new Gtk.Button.from_stock(Gtk.Stock.OK); private Gtk.Button cancel_button = new Gtk.Button.from_stock(Gtk.Stock.CANCEL); public signal void ok(Geary.AccountInformation info); @@ -20,7 +20,6 @@ public class AccountDialogAddEditPane : Gtk.Box { public AccountDialogAddEditPane() { Object(orientation: Gtk.Orientation.VERTICAL, spacing: 4); - add_edit_page.show_welcome(false); button_box.set_layout(Gtk.ButtonBoxStyle.END); button_box.expand = false; button_box.spacing = 6; @@ -38,6 +37,26 @@ public class AccountDialogAddEditPane : Gtk.Box { pack_start(add_edit_page); pack_start(button_box); + + // Default mode is Welcome. + set_mode(AddEditPage.PageMode.WELCOME); + } + + public void set_mode(AddEditPage.PageMode mode) { + ok_button.label = (mode == AddEditPage.PageMode.EDIT) ? _("_Save") : _("_Add"); + add_edit_page.set_mode(mode); + } + + public AddEditPage.PageMode get_mode() { + return add_edit_page.get_mode(); + } + + public void set_account_information(Geary.AccountInformation info) { + add_edit_page.set_account_information(info); + } + + public void reset_all() { + add_edit_page.reset_all(); } private void on_ok() { diff --git a/src/client/accounts/account-dialog.vala b/src/client/accounts/account-dialog.vala index 674845cd..42bd4136 100644 --- a/src/client/accounts/account-dialog.vala +++ b/src/client/accounts/account-dialog.vala @@ -30,7 +30,8 @@ public class AccountDialog : Gtk.Dialog { // Connect signals from pages. account_list_pane.close.connect(on_close); account_list_pane.add_account.connect(on_add_account); - add_edit_pane.ok.connect(on_add_or_edit_account); + account_list_pane.edit_account.connect(on_edit_account); + add_edit_pane.ok.connect(on_save_add_or_edit); add_edit_pane.cancel.connect(on_cancel_add_edit); add_edit_pane.size_changed.connect(() => { resize(1, 1); }); @@ -45,24 +46,46 @@ public class AccountDialog : Gtk.Dialog { } private void on_close() { - response(Gtk.ResponseType.CLOSE); + destroy(); } private void on_add_account() { + add_edit_pane.reset_all(); + add_edit_pane.set_mode(AddEditPage.PageMode.ADD); notebook.set_current_page(add_edit_page_number); } - private void on_add_or_edit_account(Geary.AccountInformation info) { - // TODO: Edit existing account. + private void on_edit_account(string email_address) { + // Grab the account info. While the addresses passed into this method should *always* be + // available in Geary, we double-check to be defensive. + Gee.Map accounts; + try { + accounts = Geary.Engine.instance.get_accounts(); + } catch (Error e) { + debug("Error getting account info: %s", e.message); + + return; + } + if (!accounts.has_key(email_address)) { + debug("Unable to get account info for: %s", email_address); + return; + } + + add_edit_pane.set_mode(AddEditPage.PageMode.EDIT); + add_edit_pane.set_account_information(accounts.get(email_address)); + notebook.set_current_page(add_edit_page_number); + } + + private void on_save_add_or_edit(Geary.AccountInformation info) { // Show the busy spinner. notebook.set_current_page(spinner_page_number); // Validate account. - GearyApplication.instance.validate_async.begin(info, null, on_add_or_edit_account_completed); + GearyApplication.instance.validate_async.begin(info, null, on_save_add_or_edit_completed); } - private void on_add_or_edit_account_completed(Object? source, AsyncResult result) { + private void on_save_add_or_edit_completed(Object? source, AsyncResult result) { // If account was successfully added return to the account list. Otherwise, go back to the // account add page so the user can try again. if (GearyApplication.instance.validate_async.end(result)) diff --git a/src/client/accounts/add-edit-page.vala b/src/client/accounts/add-edit-page.vala index b785b244..cd70a3fd 100644 --- a/src/client/accounts/add-edit-page.vala +++ b/src/client/accounts/add-edit-page.vala @@ -6,6 +6,12 @@ // Page for adding or editing an account. public class AddEditPage : Gtk.Box { + public enum PageMode { + WELCOME, + ADD, + EDIT + } + public string real_name { get { return entry_real_name.text; } set { entry_real_name.text = value; } @@ -105,7 +111,7 @@ public class AddEditPage : Gtk.Box { STARTTLS = 2 } - private bool welcome_mode = true; + private PageMode mode = PageMode.WELCOME; private Gtk.Widget container_widget; private Gtk.Box welcome_box; @@ -181,10 +187,7 @@ public class AddEditPage : Gtk.Box { foreach (Geary.ServiceProvider p in Geary.ServiceProvider.get_providers()) combo_service.append_text(p.display_name()); - // Set defaults. - set_service_provider(Geary.ServiceProvider.GMAIL); - imap_ssl = true; - smtp_ssl = true; + reset_all(); combo_service.changed.connect(update_ui); entry_email.changed.connect(on_changed); @@ -214,6 +217,27 @@ public class AddEditPage : Gtk.Box { update_ui(); } + // Sets the account information to display on this page. + public void set_account_information(Geary.AccountInformation info) { + set_all_info(info.real_name, + info.email, + info.imap_credentials.user, + info.imap_credentials.pass, + info.imap_remember_password && info.smtp_remember_password, + info.smtp_credentials.user, + info.smtp_credentials.pass, + info.service_provider, + info.default_imap_server_host, + info.default_imap_server_port, + info.default_imap_server_ssl, + info.default_imap_server_starttls, + info.default_smtp_server_host, + info.default_smtp_server_port, + info.default_smtp_server_ssl, + info.default_smtp_server_starttls); + } + + // Can use this instead of set_account_information(), both do the same thing. public void set_all_info( string? initial_real_name = null, string? initial_email = null, @@ -222,7 +246,7 @@ public class AddEditPage : Gtk.Box { bool initial_remember_password = true, string? initial_smtp_username = null, string? initial_smtp_password = null, - int initial_service_provider = -1, + int initial_service_provider = Geary.ServiceProvider.GMAIL, string? initial_default_imap_host = null, uint16 initial_default_imap_port = Geary.Imap.ClientConnection.DEFAULT_PORT_SSL, bool initial_default_imap_ssl = true, @@ -232,13 +256,12 @@ public class AddEditPage : Gtk.Box { bool initial_default_smtp_ssl = true, bool initial_default_smtp_starttls = false) { - // Set defaults (other than service provider, which is set above) + // Set defaults real_name = initial_real_name ?? ""; email_address = initial_email ?? ""; - bool use_imap_password = initial_imap_password == initial_smtp_password && - initial_imap_password != null; - password = use_imap_password ? initial_imap_password : ""; + password = initial_imap_password != null ? initial_imap_password : ""; remember_password = initial_remember_password; + set_service_provider((Geary.ServiceProvider) initial_service_provider); // Set defaults for IMAP info imap_host = initial_default_imap_host ?? ""; @@ -253,8 +276,8 @@ public class AddEditPage : Gtk.Box { smtp_port = initial_default_smtp_port; smtp_username = initial_smtp_username ?? ""; smtp_password = initial_smtp_password ?? ""; - imap_ssl = initial_default_imap_ssl; - imap_starttls = initial_default_imap_starttls; + smtp_ssl = initial_default_smtp_ssl; + smtp_starttls = initial_default_smtp_starttls; if (Geary.String.is_empty(real_name)) entry_real_name.grab_focus(); @@ -262,13 +285,26 @@ public class AddEditPage : Gtk.Box { entry_email.grab_focus(); } - // Puts this page into welcome mode which shows the "Welcome to Geary" message, etc. - // Default is true. - public void show_welcome(bool welcome) { - welcome_mode = welcome; + // Resets all fields to their defaults. + public void reset_all() { + // Take advantage of set_all_info()'s defaults. + set_all_info(get_default_real_name()); + } + + /** Puts this page into one of three different modes: + * WELCOME: The first screen when Geary is started. + * ADD: Add account screen is like the Welcome screen, but without the welcome message. + * EDIT: This screen has only a few options that can be modified after creating an account. + */ + public void set_mode(PageMode m) { + mode = m; update_ui(); } + public PageMode get_mode() { + return mode; + } + // TODO: Only reset if not manually set by user. private void on_email_changed() { entry_imap_username.text = entry_email.text; @@ -367,6 +403,7 @@ public class AddEditPage : Gtk.Box { public Geary.AccountInformation? get_account_information() { Geary.AccountInformation account_information; + update_ui(); // Force password update. Geary.Credentials imap_credentials = new Geary.Credentials(imap_username.strip(), imap_password.strip()); Geary.Credentials smtp_credentials = new Geary.Credentials(smtp_username.strip(), smtp_password.strip()); @@ -404,7 +441,7 @@ public class AddEditPage : Gtk.Box { // Updates UI based on various options. private void update_ui() { base.show_all(); - welcome_box.visible = welcome_mode; + welcome_box.visible = mode == PageMode.WELCOME; if (get_service_provider() == Geary.ServiceProvider.OTHER) { // Display all options for custom providers. @@ -418,8 +455,7 @@ public class AddEditPage : Gtk.Box { entry_password.show(); other_info.hide(); - // TODO: Will be used by upcoming edit mode to display greyed-out other info. - set_other_info_sensitive(welcome_mode); + set_other_info_sensitive(mode == PageMode.WELCOME); // For supported providers, fill out the rest of the form automagically. imap_username = email_address; @@ -428,6 +464,19 @@ public class AddEditPage : Gtk.Box { smtp_password = password; } + // In edit mode, certain fields are not sensitive. + combo_service.sensitive = + entry_email.sensitive = + entry_imap_host.sensitive = + entry_imap_port.sensitive = + entry_imap_username.sensitive = + combo_imap_encryption.sensitive = + entry_smtp_host.sensitive = + entry_smtp_port.sensitive = + entry_smtp_username.sensitive = + combo_smtp_encryption.sensitive = + mode != PageMode.EDIT; + size_changed(); } @@ -466,5 +515,10 @@ public class AddEditPage : Gtk.Box { // Note that update_ui() calls base.show_all(), so no need to do that here. update_ui(); } + + private string get_default_real_name() { + string real_name = Environment.get_real_name(); + return real_name == "Unknown" ? "" : real_name; + } } diff --git a/src/client/accounts/login-dialog.vala b/src/client/accounts/login-dialog.vala index d41f816b..f4f430ab 100644 --- a/src/client/accounts/login-dialog.vala +++ b/src/client/accounts/login-dialog.vala @@ -40,27 +40,8 @@ public class LoginDialog : Gtk.Dialog { set_account_information(initial_account_information); } - public void set_real_name(string name) { - page.real_name = name; - } - public void set_account_information(Geary.AccountInformation info) { - page.set_all_info(info.real_name, - info.email, - info.imap_credentials.user, - info.imap_credentials.pass, - info.imap_remember_password && info.smtp_remember_password, - info.smtp_credentials.user, - info.smtp_credentials.pass, - info.service_provider, - info.default_imap_server_host, - info.default_imap_server_port, - info.default_imap_server_ssl, - info.default_imap_server_starttls, - info.default_smtp_server_host, - info.default_smtp_server_port, - info.default_smtp_server_ssl, - info.default_smtp_server_starttls); + page.set_account_information(info); } public Geary.AccountInformation get_account_information() { diff --git a/src/client/geary-application.vala b/src/client/geary-application.vala index 3d4b1c27..64a976ef 100644 --- a/src/client/geary-application.vala +++ b/src/client/geary-application.vala @@ -301,20 +301,13 @@ along with Geary; if not, write to the Free Software Foundation, Inc., return null; } - private string get_default_real_name() { - string real_name = Environment.get_real_name(); - return real_name == "Unknown" ? "" : real_name; - } - // Prompt the user for a service, real name, username, and password, and try to start Geary. private Geary.AccountInformation? request_account_information(Geary.AccountInformation? old_info) { Geary.AccountInformation? new_info = old_info; if (login_dialog == null) login_dialog = new LoginDialog(); // Create here so we know GTK is initialized. - if (new_info == null) - login_dialog.set_real_name(get_default_real_name()); - else + if (new_info != null) login_dialog.set_account_information(new_info); login_dialog.present(); diff --git a/src/client/geary-controller.vala b/src/client/geary-controller.vala index 2e9dae3b..fc63f3e1 100644 --- a/src/client/geary-controller.vala +++ b/src/client/geary-controller.vala @@ -266,7 +266,6 @@ public class GearyController { } inbox_conversations = null; - inbox_folder = null; } if (inbox_folder != null) { @@ -709,7 +708,6 @@ public class GearyController { private void on_accounts() { AccountDialog dialog = new AccountDialog(); dialog.run(); - dialog.destroy(); } private void on_preferences() { diff --git a/ui/account_list.glade b/ui/account_list.glade index ef6d6fcf..58a72c4e 100644 --- a/ui/account_list.glade +++ b/ui/account_list.glade @@ -12,6 +12,11 @@ gtk-close + + + gtk-edit + + True @@ -69,6 +74,20 @@ True + + + edit_account + True + False + Edit an account + toolbutton1 + True + + + False + True + + False