Closes #6286 Delete accounts
Squashed commit of the following:
commit 1b045edd6c28e3f837107577726b61c839816bc2
Author: Eric Gregory <eric@yorba.org>
Date: Mon Feb 4 19:25:36 2013 -0800
Changes from code review
commit bcd52b9f571de316eda39bd181df121bc4753c40
Author: Eric Gregory <eric@yorba.org>
Date: Mon Feb 4 18:21:53 2013 -0800
Removed cancellable check
commit 1cc528ca39555233cd5e851229a242fc118c11ae
Author: Eric Gregory <eric@yorba.org>
Date: Mon Feb 4 18:17:42 2013 -0800
Delete account (2nd branch)
This commit is contained in:
parent
5e9703a1e5
commit
0350a8fe0f
17 changed files with 485 additions and 24 deletions
|
|
@ -181,6 +181,7 @@ engine/state/state-mapping.vala
|
|||
|
||||
engine/util/util-collection.vala
|
||||
engine/util/util-converter.vala
|
||||
engine/util/util-files.vala
|
||||
engine/util/util-generic-capabilities.vala
|
||||
engine/util/util-html.vala
|
||||
engine/util/util-inet.vala
|
||||
|
|
@ -206,6 +207,7 @@ client/main.vala
|
|||
client/accounts/account-dialog.vala
|
||||
client/accounts/account-dialog-account-list-pane.vala
|
||||
client/accounts/account-dialog-add-edit-pane.vala
|
||||
client/accounts/account-dialog-remove-confirm-pane.vala
|
||||
client/accounts/account-spinner-page.vala
|
||||
client/accounts/add-edit-page.vala
|
||||
client/accounts/login-dialog.vala
|
||||
|
|
|
|||
|
|
@ -14,11 +14,14 @@ public class AccountDialogAccountListPane : Gtk.Box {
|
|||
private Gtk.TreeView list_view;
|
||||
private Gtk.ListStore list_model = new Gtk.ListStore(2, typeof (string), typeof (string));
|
||||
private Gtk.Action edit_action;
|
||||
private Gtk.Action delete_action;
|
||||
|
||||
public signal void add_account();
|
||||
|
||||
public signal void edit_account(string email_address);
|
||||
|
||||
public signal void delete_account(string email_address);
|
||||
|
||||
public signal void close();
|
||||
|
||||
public AccountDialogAccountListPane() {
|
||||
|
|
@ -28,6 +31,7 @@ public class AccountDialogAccountListPane : Gtk.Box {
|
|||
pack_end((Gtk.Box) builder.get_object("container"));
|
||||
Gtk.ActionGroup actions = (Gtk.ActionGroup) builder.get_object("account list actions");
|
||||
edit_action = actions.get_action("edit_account");
|
||||
delete_action = actions.get_action("delete_account");
|
||||
|
||||
// Set up list.
|
||||
list_view = (Gtk.TreeView) builder.get_object("account_list");
|
||||
|
|
@ -43,7 +47,8 @@ public class AccountDialogAccountListPane : Gtk.Box {
|
|||
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);
|
||||
delete_action.activate.connect(notify_delete_account);
|
||||
list_view.get_selection().changed.connect(update_buttons);
|
||||
list_view.button_press_event.connect(on_button_press);
|
||||
|
||||
// Theme hint: "join" the toolbar to the scrolled window above it.
|
||||
|
|
@ -75,6 +80,12 @@ public class AccountDialogAccountListPane : Gtk.Box {
|
|||
edit_account(account);
|
||||
}
|
||||
|
||||
private void notify_delete_account() {
|
||||
string? account = get_selected_account();
|
||||
if (account != null)
|
||||
delete_account(account);
|
||||
}
|
||||
|
||||
private bool on_button_press(Gdk.EventButton event) {
|
||||
if (event.type != Gdk.EventType.2BUTTON_PRESS)
|
||||
return false;
|
||||
|
|
@ -108,8 +119,19 @@ public class AccountDialogAccountListPane : Gtk.Box {
|
|||
return account;
|
||||
}
|
||||
|
||||
private void on_selection_changed() {
|
||||
private void update_buttons() {
|
||||
edit_action.sensitive = get_selected_account() != null;
|
||||
delete_action.sensitive = edit_action.sensitive && get_num_accounts() > 1;
|
||||
}
|
||||
|
||||
private int get_num_accounts() {
|
||||
try {
|
||||
return Geary.Engine.instance.get_accounts().size;
|
||||
} catch (Error e) {
|
||||
debug("Error getting number of accounts: %s", e.message);
|
||||
}
|
||||
|
||||
return 0; // on error
|
||||
}
|
||||
|
||||
private void on_account_added(Geary.AccountInformation account) {
|
||||
|
|
@ -119,11 +141,13 @@ public class AccountDialogAccountListPane : Gtk.Box {
|
|||
|
||||
add_account_to_list(account.nickname, account.email);
|
||||
account.notify.connect(on_account_changed);
|
||||
update_buttons();
|
||||
}
|
||||
|
||||
private void on_account_removed(Geary.AccountInformation account) {
|
||||
remove_account_from_list(account.email);
|
||||
account.notify.disconnect(on_account_changed);
|
||||
update_buttons();
|
||||
}
|
||||
|
||||
// Adds an account to the list.
|
||||
|
|
|
|||
37
src/client/accounts/account-dialog-remove-confirm-pane.vala
Normal file
37
src/client/accounts/account-dialog-remove-confirm-pane.vala
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/* Copyright 2013 Yorba Foundation
|
||||
*
|
||||
* This software is licensed under the GNU Lesser General Public License
|
||||
* (version 2.1 or later). See the COPYING file in this distribution.
|
||||
*/
|
||||
|
||||
// Confirmation of the deletion of an account
|
||||
public class AccountDialogRemoveConfirmPane : Gtk.Box {
|
||||
private Geary.AccountInformation? account = null;
|
||||
private Gtk.Label account_nickname_label;
|
||||
private Gtk.Label email_address_label;
|
||||
|
||||
public signal void ok(Geary.AccountInformation? account);
|
||||
|
||||
public signal void cancel();
|
||||
|
||||
public AccountDialogRemoveConfirmPane() {
|
||||
Object(orientation: Gtk.Orientation.VERTICAL, spacing: 6);
|
||||
|
||||
Gtk.Builder builder = GearyApplication.instance.create_builder("remove_confirm.glade");
|
||||
pack_end((Gtk.Box) builder.get_object("container"));
|
||||
Gtk.ActionGroup actions = (Gtk.ActionGroup) builder.get_object("actions");
|
||||
account_nickname_label = (Gtk.Label) builder.get_object("account_nickname_label");
|
||||
email_address_label = (Gtk.Label) builder.get_object("email_address_label");
|
||||
|
||||
// Hook up signals.
|
||||
actions.get_action("cancel_action").activate.connect(() => { cancel(); });
|
||||
actions.get_action("remove_action").activate.connect(() => { ok(account); });
|
||||
}
|
||||
|
||||
public void set_account(Geary.AccountInformation a) {
|
||||
account = a;
|
||||
account_nickname_label.label = account.nickname;
|
||||
email_address_label.label = account.email;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -11,9 +11,11 @@ public class AccountDialog : Gtk.Dialog {
|
|||
private AccountDialogAccountListPane account_list_pane = new AccountDialogAccountListPane();
|
||||
private AccountDialogAddEditPane add_edit_pane = new AccountDialogAddEditPane();
|
||||
private AccountSpinnerPage spinner_pane = new AccountSpinnerPage();
|
||||
private AccountDialogRemoveConfirmPane remove_confirm_pane = new AccountDialogRemoveConfirmPane();
|
||||
private int add_edit_page_number;
|
||||
private int account_list_page_number;
|
||||
private int spinner_page_number;
|
||||
private int remove_confirm_page_number;
|
||||
|
||||
public AccountDialog() {
|
||||
set_size_request(450, -1); // Sets min size.
|
||||
|
|
@ -26,14 +28,18 @@ public class AccountDialog : Gtk.Dialog {
|
|||
account_list_page_number = notebook.append_page(account_list_pane, null);
|
||||
add_edit_page_number = notebook.append_page(add_edit_pane, null);
|
||||
spinner_page_number = notebook.append_page(spinner_pane, null);
|
||||
remove_confirm_page_number = notebook.append_page(remove_confirm_pane, null);
|
||||
|
||||
// Connect signals from pages.
|
||||
account_list_pane.close.connect(on_close);
|
||||
account_list_pane.add_account.connect(on_add_account);
|
||||
account_list_pane.edit_account.connect(on_edit_account);
|
||||
account_list_pane.delete_account.connect(on_delete_account);
|
||||
add_edit_pane.ok.connect(on_save_add_or_edit);
|
||||
add_edit_pane.cancel.connect(on_cancel_add_edit);
|
||||
add_edit_pane.cancel.connect(on_cancel_back_to_list);
|
||||
add_edit_pane.size_changed.connect(() => { resize(1, 1); });
|
||||
remove_confirm_pane.ok.connect(on_delete_account_confirmed);
|
||||
remove_confirm_pane.cancel.connect(on_cancel_back_to_list);
|
||||
|
||||
// Set default page.
|
||||
notebook.set_current_page(account_list_page_number);
|
||||
|
|
@ -55,28 +61,55 @@ public class AccountDialog : Gtk.Dialog {
|
|||
notebook.set_current_page(add_edit_page_number);
|
||||
}
|
||||
|
||||
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;
|
||||
// Grab the account info. While the addresses passed into this method should *always* be
|
||||
// available in Geary, we double-check to be defensive.
|
||||
private Geary.AccountInformation? get_account_info_for_email(string email_address) {
|
||||
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;
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!accounts.has_key(email_address)) {
|
||||
debug("Unable to get account info for: %s", email_address);
|
||||
return;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return accounts.get(email_address);
|
||||
}
|
||||
|
||||
private void on_edit_account(string email_address) {
|
||||
Geary.AccountInformation? account = get_account_info_for_email(email_address);
|
||||
if (account == null)
|
||||
return;
|
||||
|
||||
add_edit_pane.set_mode(AddEditPage.PageMode.EDIT);
|
||||
add_edit_pane.set_account_information(accounts.get(email_address));
|
||||
add_edit_pane.set_account_information(account);
|
||||
notebook.set_current_page(add_edit_page_number);
|
||||
}
|
||||
|
||||
private void on_delete_account(string email_address) {
|
||||
Geary.AccountInformation? account = get_account_info_for_email(email_address);
|
||||
if (account == null)
|
||||
return;
|
||||
|
||||
// Send user to confirmation screen.
|
||||
remove_confirm_pane.set_account(account);
|
||||
notebook.set_current_page(remove_confirm_page_number);
|
||||
}
|
||||
|
||||
private void on_delete_account_confirmed(Geary.AccountInformation? account) {
|
||||
assert(account != null); // Should not be able to happen since we checked earlier.
|
||||
|
||||
// Remove account, then set the page back to the account list.
|
||||
GearyApplication.instance.remove_account_async.begin(account, null, () => {
|
||||
notebook.set_current_page(account_list_page_number); });
|
||||
}
|
||||
|
||||
private void on_save_add_or_edit(Geary.AccountInformation info) {
|
||||
// Show the busy spinner.
|
||||
notebook.set_current_page(spinner_page_number);
|
||||
|
|
@ -94,7 +127,7 @@ public class AccountDialog : Gtk.Dialog {
|
|||
notebook.set_current_page(add_edit_page_number);
|
||||
}
|
||||
|
||||
private void on_cancel_add_edit() {
|
||||
private void on_cancel_back_to_list() {
|
||||
notebook.set_current_page(account_list_page_number);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -308,6 +308,17 @@ along with Geary; if not, write to the Free Software Foundation, Inc.,
|
|||
}
|
||||
}
|
||||
|
||||
// Removes an existing account.
|
||||
public async void remove_account_async(Geary.AccountInformation account,
|
||||
Cancellable? cancellable = null) {
|
||||
try {
|
||||
yield GearyApplication.instance.get_account_instance(account).close_async(cancellable);
|
||||
yield Geary.Engine.instance.remove_account_async(account, cancellable);
|
||||
} catch (Error e) {
|
||||
message("Error removing account: %s", e.message);
|
||||
}
|
||||
}
|
||||
|
||||
public File get_user_data_directory() {
|
||||
return File.new_for_path(Environment.get_user_data_dir()).get_child("geary");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -322,12 +322,16 @@ public class GearyController {
|
|||
}
|
||||
|
||||
private void on_folder_selected(Geary.Folder? folder) {
|
||||
debug("Folder %s selected", folder != null ? folder.to_string() : "(null)");
|
||||
|
||||
// If the folder is being unset, clear the message list and exit here.
|
||||
if (folder == null) {
|
||||
debug("no folder selected");
|
||||
main_window.conversation_list_store.clear();
|
||||
main_window.conversation_viewer.clear(null, null);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
debug("Folder %s selected", folder.to_string());
|
||||
set_busy(true);
|
||||
do_select_folder.begin(folder, on_select_folder_completed);
|
||||
}
|
||||
|
|
@ -364,13 +368,6 @@ public class GearyController {
|
|||
main_window.main_toolbar.move_folder_menu.add_folder(f);
|
||||
}
|
||||
|
||||
// The current folder may be null if the user rapidly switches between folders. If they have
|
||||
// done that then this folder selection is invalid anyways, so just return.
|
||||
if (current_folder == null) {
|
||||
warning("Can not open folder: %s", folder.to_string());
|
||||
return;
|
||||
}
|
||||
|
||||
update_ui();
|
||||
|
||||
if (!inboxes.values.contains(current_folder)) {
|
||||
|
|
|
|||
|
|
@ -222,12 +222,25 @@ public class FolderList : Sidebar.Tree {
|
|||
assert(account_branch != null);
|
||||
assert(has_branch(account_branch));
|
||||
|
||||
// If this is the current folder, unselect it.
|
||||
Sidebar.Entry? entry = account_branch.folder_entries.get(folder.get_path());
|
||||
if (entry != null && is_selected(entry))
|
||||
folder_selected(null);
|
||||
|
||||
account_branch.remove_folder(folder);
|
||||
}
|
||||
|
||||
public void remove_account(Geary.Account account) {
|
||||
AccountBranch? account_branch = account_branches.get(account);
|
||||
if (account_branch != null) {
|
||||
// If a folder on this account is selected, unselect it.
|
||||
foreach (FolderEntry entry in account_branch.folder_entries.values) {
|
||||
if (is_selected(entry)) {
|
||||
folder_selected(null);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (has_branch(account_branch))
|
||||
prune(account_branch);
|
||||
account_branches.unset(account);
|
||||
|
|
|
|||
|
|
@ -44,6 +44,8 @@ public abstract class Geary.AbstractAccount : Object, Geary.Account {
|
|||
|
||||
public abstract async void close_async(Cancellable? cancellable = null) throws Error;
|
||||
|
||||
public abstract bool is_open();
|
||||
|
||||
public abstract Gee.Collection<Geary.Folder> list_matching_folders(
|
||||
Geary.FolderPath? parent) throws Error;
|
||||
|
||||
|
|
|
|||
|
|
@ -375,4 +375,48 @@ public class Geary.AccountInformation : Object {
|
|||
debug("Error writing to account info file: %s", err.message);
|
||||
}
|
||||
}
|
||||
|
||||
public async void clear_stored_passwords_async(
|
||||
CredentialsMediator.ServiceFlag services) throws Error {
|
||||
Error? return_error = null;
|
||||
check_mediator_instance();
|
||||
CredentialsMediator mediator = Geary.Engine.instance.authentication_mediator;
|
||||
|
||||
try {
|
||||
if (services.has_imap()) {
|
||||
yield mediator.clear_password_async(
|
||||
CredentialsMediator.Service.IMAP, imap_credentials.user);
|
||||
}
|
||||
} catch (Error e) {
|
||||
return_error = e;
|
||||
}
|
||||
|
||||
try {
|
||||
if (services.has_smtp()) {
|
||||
yield mediator.clear_password_async(
|
||||
CredentialsMediator.Service.SMTP, smtp_credentials.user);
|
||||
}
|
||||
} catch (Error e) {
|
||||
return_error = e;
|
||||
}
|
||||
|
||||
if (return_error != null)
|
||||
throw return_error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an account from disk. This is used by Geary.Engine and should not
|
||||
* normally be invoked directly.
|
||||
*/
|
||||
internal async void remove_async(Cancellable? cancellable = null) {
|
||||
try {
|
||||
yield clear_stored_passwords_async(CredentialsMediator.ServiceFlag.IMAP
|
||||
| CredentialsMediator.ServiceFlag.SMTP);
|
||||
} catch (Error e) {
|
||||
debug("Error clearing SMTP password: %s", e.message);
|
||||
}
|
||||
|
||||
// Delete files.
|
||||
yield Files.recursive_delete_async(settings_dir, cancellable);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,6 +80,11 @@ public interface Geary.Account : Object {
|
|||
*/
|
||||
public abstract async void close_async(Cancellable? cancellable = null) throws Error;
|
||||
|
||||
/**
|
||||
* Returns true if this account is open, else false.
|
||||
*/
|
||||
public abstract bool is_open();
|
||||
|
||||
/**
|
||||
* Lists all the currently-available folders found under the parent path
|
||||
* unless it's null, in which case it lists all the root folders. If the
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ public errordomain Geary.EngineError {
|
|||
BAD_RESPONSE,
|
||||
INCOMPLETE_MESSAGE,
|
||||
SERVER_UNAVAILABLE,
|
||||
ALREADY_CLOSED
|
||||
ALREADY_CLOSED,
|
||||
CLOSE_REQUIRED
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -293,13 +293,25 @@ public class Geary.Engine {
|
|||
public async void remove_account_async(AccountInformation account,
|
||||
Cancellable? cancellable = null) throws Error {
|
||||
check_opened();
|
||||
|
||||
|
||||
// Ensure account is closed.
|
||||
if (account_instances.has_key(account.email) && account_instances.get(account.email).is_open()) {
|
||||
throw new EngineError.CLOSE_REQUIRED("Account %s must be closed before removal",
|
||||
account.email);
|
||||
}
|
||||
|
||||
if (accounts.unset(account.email)) {
|
||||
// Removal *MUST* be done in the following order:
|
||||
// 1. Send the account-unavailable signal.
|
||||
account_unavailable(account);
|
||||
|
||||
// TODO: delete the account from disk.
|
||||
|
||||
// 2. Delete the corresponding files.
|
||||
yield account.remove_async(cancellable);
|
||||
|
||||
// 3. Send the account-removed signal.
|
||||
account_removed(account);
|
||||
|
||||
// 4. Remove the account data from the engine.
|
||||
account_instances.unset(account.email);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -126,6 +126,7 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.AbstractAccount {
|
|||
properties_map.clear();
|
||||
existing_folders.clear();
|
||||
local_only.clear();
|
||||
open = false;
|
||||
|
||||
if (local_err != null)
|
||||
throw local_err;
|
||||
|
|
@ -134,6 +135,10 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.AbstractAccount {
|
|||
throw remote_err;
|
||||
}
|
||||
|
||||
public override bool is_open() {
|
||||
return open;
|
||||
}
|
||||
|
||||
// Subclasses should implement this to return their flavor of a GenericFolder with the
|
||||
// appropriate interfaces attached. The returned folder should have its SpecialFolderType
|
||||
// set using either the properties from the local folder or its path.
|
||||
|
|
|
|||
57
src/engine/util/util-files.vala
Normal file
57
src/engine/util/util-files.vala
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
/* Copyright 2013 Yorba Foundation
|
||||
*
|
||||
* This software is licensed under the GNU Lesser General Public License
|
||||
* (version 2.1 or later). See the COPYING file in this distribution.
|
||||
*/
|
||||
|
||||
namespace Geary.Files {
|
||||
|
||||
// Number of files to delete in each step.
|
||||
public const int RECURSIVE_DELETE_BATCH_SIZE = 50;
|
||||
|
||||
/**
|
||||
* Recursively deletes a folder and its children.
|
||||
* This method is designed to keep chugging along even if an error occurs.
|
||||
* If this method is called with a file, it will simply be deleted.
|
||||
*/
|
||||
public async void recursive_delete_async(File folder, Cancellable? cancellable = null) {
|
||||
// If this is a folder, recurse children.
|
||||
if (folder.query_file_type(FileQueryInfoFlags.NONE) == FileType.DIRECTORY) {
|
||||
FileEnumerator? enumerator = null;
|
||||
try {
|
||||
enumerator = yield folder.enumerate_children_async(FileAttribute.STANDARD_NAME,
|
||||
FileQueryInfoFlags.NOFOLLOW_SYMLINKS, Priority.DEFAULT, cancellable);
|
||||
} catch (Error e) {
|
||||
debug("Error enumerating files for deletion: %s", e.message);
|
||||
}
|
||||
|
||||
// Iterate the enumerated files in batches.
|
||||
try {
|
||||
while (true) {
|
||||
List<FileInfo>? info_list = null;
|
||||
|
||||
info_list = yield enumerator.next_files_async(RECURSIVE_DELETE_BATCH_SIZE,
|
||||
Priority.DEFAULT, cancellable);
|
||||
|
||||
if (info_list == null)
|
||||
break; // Stop condition.
|
||||
|
||||
// Recursive step.
|
||||
foreach (FileInfo info in info_list)
|
||||
yield recursive_delete_async(folder.get_child(info.get_name()), cancellable);
|
||||
}
|
||||
} catch (Error e) {
|
||||
debug("Error enumerating batch of files: %s", e.message);
|
||||
}
|
||||
}
|
||||
|
||||
// Children have been deleted, it's now safe to delete this file/folder.
|
||||
try {
|
||||
yield folder.delete_async(Priority.DEFAULT, cancellable);
|
||||
} catch (Error e) {
|
||||
debug("Error removing file: %s", e.message);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -9,6 +9,7 @@ install(FILES login.glade DESTINATION ${UI_DEST})
|
|||
install(FILES message.glade DESTINATION ${UI_DEST})
|
||||
install(FILES password-dialog.glade DESTINATION ${UI_DEST})
|
||||
install(FILES preferences.glade DESTINATION ${UI_DEST})
|
||||
install(FILES remove_confirm.glade DESTINATION ${UI_DEST})
|
||||
install(FILES toolbar.glade DESTINATION ${UI_DEST})
|
||||
install(FILES toolbar_mark_menu.ui DESTINATION ${UI_DEST})
|
||||
install(FILES toolbar_menu.ui DESTINATION ${UI_DEST})
|
||||
|
|
|
|||
|
|
@ -17,6 +17,11 @@
|
|||
<property name="icon_name">gtk-edit</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkAction" id="delete_account">
|
||||
<property name="icon_name">list-remove-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkBox" id="container">
|
||||
<property name="visible">True</property>
|
||||
|
|
@ -88,6 +93,19 @@
|
|||
<property name="homogeneous">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkToolButton" id="delete_button">
|
||||
<property name="related_action">delete_account</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</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>
|
||||
|
|
|
|||
199
ui/remove_confirm.glade
Normal file
199
ui/remove_confirm.glade
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<!-- interface-requires gtk+ 3.0 -->
|
||||
<object class="GtkActionGroup" id="actions">
|
||||
<child>
|
||||
<object class="GtkAction" id="cancel_action">
|
||||
<property name="stock_id">gtk-cancel</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkAction" id="remove_action">
|
||||
<property name="stock_id">gtk-remove</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkBox" id="container">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_left">1</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="image1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="yalign">0</property>
|
||||
<property name="stock">gtk-dialog-warning</property>
|
||||
<property name="icon-size">6</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="padding">6</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="box2">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label4">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_bottom">20</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes"><span weight="bold" size="larger">Are you sure you want to remove this account?</span> </property>
|
||||
<property name="use_markup">True</property>
|
||||
<property name="wrap">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">All email associated with this account will be removed from your computer. This will not affect email on the server.</property>
|
||||
<property name="wrap">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="padding">6</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkGrid" id="grid1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="vexpand">True</property>
|
||||
<property name="row_spacing">5</property>
|
||||
<property name="column_spacing">5</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label2">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">Nickname:</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">0</property>
|
||||
<property name="width">1</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label3">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">Email address:</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="width">1</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="account_nickname_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="xpad">6</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold"/>
|
||||
</attributes>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">0</property>
|
||||
<property name="width">1</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="email_address_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="xpad">6</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold"/>
|
||||
</attributes>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="width">1</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="padding">6</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButtonBox" id="buttonbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="spacing">12</property>
|
||||
<property name="layout_style">end</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="button1">
|
||||
<property name="label" translatable="yes">_Cancel</property>
|
||||
<property name="related_action">cancel_action</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="use_underline">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="button2">
|
||||
<property name="label" translatable="yes">_Remove</property>
|
||||
<property name="related_action">remove_action</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="use_underline">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
Loading…
Add table
Add a link
Reference in a new issue