Closes #4580 Edit existing accounts

Squashed commit of the following:

commit e7af3b721314513fc6ea2eb57d10086e4f1e148b
Author: Eric Gregory <eric@yorba.org>
Date:   Mon Jan 28 16:53:56 2013 -0800

    Account dialog is back to being modal

commit cdd214070e67dc735c819df06c46a1d128ef20d2
Author: Eric Gregory <eric@yorba.org>
Date:   Fri Jan 25 18:14:17 2013 -0800

    Fix for password issue

commit 847da391373357bbca90ef6d8028ea8ff85458f1
Author: Eric Gregory <eric@yorba.org>
Date:   Fri Jan 25 17:20:12 2013 -0800

    Merging in changes

commit 7745ac1426fb8560624fed752de0ee162f97bd9e
Author: Eric Gregory <eric@yorba.org>
Date:   Fri Jan 25 15:53:49 2013 -0800

    Changes from code review

commit d7727544aaeacceb5c9b0ac3444a6db0311929db
Author: Eric Gregory <eric@yorba.org>
Date:   Thu Jan 24 17:10:18 2013 -0800

    Account editing, various account management bug fixes
This commit is contained in:
Eric Gregory 2013-01-28 16:59:53 -08:00
parent e971275375
commit fcfb46008b
8 changed files with 197 additions and 59 deletions

View file

@ -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)

View file

@ -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() {

View file

@ -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<string, Geary.AccountInformation> 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))

View file

@ -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;
}
}

View file

@ -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() {

View file

@ -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();

View file

@ -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() {

View file

@ -12,6 +12,11 @@
<property name="stock_id">gtk-close</property>
</object>
</child>
<child>
<object class="GtkAction" id="edit_account">
<property name="icon_name">gtk-edit</property>
</object>
</child>
</object>
<object class="GtkBox" id="container">
<property name="visible">True</property>
@ -69,6 +74,20 @@
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkToolButton" id="edit_button">
<property name="related_action">edit_account</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Edit an account</property>
<property name="label" translatable="yes">toolbutton1</property>
<property name="use_underline">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>