[geary/mjog/account-command-stacks: 33/77] Move GAction related code from app Controller to MainWindow
- From: Michael Gratton <mjog src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [geary/mjog/account-command-stacks: 33/77] Move GAction related code from app Controller to MainWindow
- Date: Tue, 5 Nov 2019 00:35:51 +0000 (UTC)
commit 8e9f00295e918888f72d5853f13e4048ae8d1a35
Author: Michael Gratton <mike vee net>
Date: Sat Oct 5 10:27:02 2019 +1000
Move GAction related code from app Controller to MainWindow
This moves a large nummber of the main window's concerns to the main
window, decouping a large number of dependencies from the controller to
the main window, and enables managing action and UI state per-window.
src/client/application/application-controller.vala | 717 ++-------------------
src/client/application/geary-application.vala | 1 +
src/client/components/main-toolbar.vala | 4 +-
src/client/components/main-window.vala | 301 ++++++++-
.../conversation-list/conversation-list-view.vala | 19 +-
5 files changed, 349 insertions(+), 693 deletions(-)
---
diff --git a/src/client/application/application-controller.vala
b/src/client/application/application-controller.vala
index afeb4b4a..2b070eeb 100644
--- a/src/client/application/application-controller.vala
+++ b/src/client/application/application-controller.vala
@@ -14,32 +14,6 @@
*/
public class Application.Controller : Geary.BaseObject {
- // Named actions.
- public const string ACTION_REPLY_TO_MESSAGE = "reply-to-message";
- public const string ACTION_REPLY_ALL_MESSAGE = "reply-all-message";
- public const string ACTION_FORWARD_MESSAGE = "forward-message";
- public const string ACTION_ARCHIVE_CONVERSATION = "archive-conv";
- public const string ACTION_TRASH_CONVERSATION = "trash-conv";
- public const string ACTION_DELETE_CONVERSATION = "delete-conv";
- public const string ACTION_EMPTY_SPAM = "empty-spam";
- public const string ACTION_EMPTY_TRASH = "empty-trash";
- public const string ACTION_FIND_IN_CONVERSATION = "conv-find";
- public const string ACTION_ZOOM = "zoom";
- public const string ACTION_SHOW_MARK_MENU = "mark-message-menu";
- public const string ACTION_MARK_AS_READ = "mark-message-read";
- public const string ACTION_MARK_AS_UNREAD = "mark-message-unread";
- public const string ACTION_MARK_AS_STARRED = "mark-message-starred";
- public const string ACTION_MARK_AS_UNSTARRED = "mark-message-unstarred";
- public const string ACTION_MARK_AS_SPAM = "mark-message-spam";
- public const string ACTION_MARK_AS_NOT_SPAM = "mark-message-not-spam";
- public const string ACTION_COPY_MENU = "show-copy-menu";
- public const string ACTION_MOVE_MENU = "show-move-menu";
- public const string ACTION_SEARCH = "search-conv";
- public const string ACTION_CONVERSATION_LIST = "focus-conv-list";
- public const string ACTION_TOGGLE_SEARCH = "toggle-search";
- public const string ACTION_TOGGLE_FIND = "toggle-find";
- public const string ACTION_CONVERSATION_UP = "up-conversation";
- public const string ACTION_CONVERSATION_DOWN = "down-conversation";
// Properties
public const string PROP_SELECTED_CONVERSATIONS ="selected-conversations";
@@ -166,48 +140,9 @@ public class Application.Controller : Geary.BaseObject {
private Geary.Folder? previous_non_search_folder = null;
private Gee.List<string?> pending_mailtos = new Gee.ArrayList<string>();
- private uint operation_count = 0;
- private Geary.Revokable? revokable = null;
-
- // Store the description for the revokable for tooltip display.
- // This was previously stored within the context of undo button of the main toolbar.
- private string revokable_description { get; set; }
-
// List of windows we're waiting to close before Geary closes.
private Gee.List<ComposerWidget> waiting_to_close = new Gee.ArrayList<ComposerWidget>();
- private const ActionEntry[] win_action_entries = {
- {GearyApplication.ACTION_CLOSE, on_close },
- {GearyApplication.ACTION_UNDO, on_revoke },
-
- {ACTION_CONVERSATION_LIST, on_conversation_list },
- {ACTION_FIND_IN_CONVERSATION, on_find_in_conversation_action },
- {ACTION_SEARCH, on_search_activated },
- {ACTION_EMPTY_SPAM, on_empty_spam },
- {ACTION_EMPTY_TRASH, on_empty_trash },
- // Message actions
- {ACTION_REPLY_TO_MESSAGE, on_reply_to_message_action },
- {ACTION_REPLY_ALL_MESSAGE, on_reply_all_message_action },
- {ACTION_FORWARD_MESSAGE, on_forward_message_action },
- {ACTION_ARCHIVE_CONVERSATION, on_archive_conversation },
- {ACTION_TRASH_CONVERSATION, on_trash_conversation },
- {ACTION_DELETE_CONVERSATION, on_delete_conversation },
- {ACTION_COPY_MENU, on_show_copy_menu },
- {ACTION_MOVE_MENU, on_show_move_menu },
- {ACTION_CONVERSATION_UP, on_conversation_up },
- {ACTION_CONVERSATION_DOWN, on_conversation_down },
- // Message marking actions
- {ACTION_SHOW_MARK_MENU, on_show_mark_menu },
- {ACTION_MARK_AS_READ, on_mark_as_read },
- {ACTION_MARK_AS_UNREAD, on_mark_as_unread },
- {ACTION_MARK_AS_STARRED, on_mark_as_starred },
- {ACTION_MARK_AS_UNSTARRED, on_mark_as_unstarred },
- {ACTION_MARK_AS_SPAM, on_mark_as_spam_toggle },
- {ACTION_MARK_AS_NOT_SPAM, on_mark_as_spam_toggle },
- // Message viewer
- {ACTION_ZOOM, on_zoom, "s" },
- };
-
/**
* Constructs a new instance of the controller.
@@ -277,8 +212,6 @@ public class Application.Controller : Geary.BaseObject {
main_window.retry_service_problem.connect(on_retry_service_problem);
main_window.notify["has-toplevel-focus"].connect(on_has_toplevel_focus);
- setup_actions();
-
enable_message_buttons(false);
engine.account_available.connect(on_account_available);
@@ -286,13 +219,8 @@ public class Application.Controller : Geary.BaseObject {
// Connect to various UI signals.
main_window.conversation_list_view.conversations_selected.connect(on_conversations_selected);
main_window.conversation_list_view.conversation_activated.connect(on_conversation_activated);
- main_window.conversation_list_view.mark_conversations.connect(on_mark_conversations);
main_window.conversation_list_view.visible_conversations_changed.connect(on_visible_conversations_changed);
main_window.folder_list.folder_selected.connect(on_folder_selected);
- main_window.folder_list.copy_conversation.connect(on_copy_conversation);
- main_window.folder_list.move_conversation.connect(on_move_conversation);
- main_window.main_toolbar.copy_folder_menu.folder_selected.connect(on_copy_conversation);
- main_window.main_toolbar.move_folder_menu.folder_selected.connect(on_move_conversation);
main_window.search_bar.search_text_changed.connect((text) => { do_search(text); });
main_window.conversation_viewer.conversation_added.connect(
on_conversation_view_added
@@ -303,9 +231,6 @@ public class Application.Controller : Geary.BaseObject {
this.main_window.conversation_list_view.grab_focus();
- // initialize revokable
- save_revokable(null, null);
-
// Migrate configuration if necessary.
try {
Migrate.xdg_config_dir(this.application.get_user_data_directory(),
@@ -382,13 +307,8 @@ public class Application.Controller : Geary.BaseObject {
// Disconnect from various UI signals.
this.main_window.conversation_list_view.conversations_selected.disconnect(on_conversations_selected);
this.main_window.conversation_list_view.conversation_activated.disconnect(on_conversation_activated);
- this.main_window.conversation_list_view.mark_conversations.disconnect(on_mark_conversations);
this.main_window.conversation_list_view.visible_conversations_changed.disconnect(on_visible_conversations_changed);
this.main_window.folder_list.folder_selected.disconnect(on_folder_selected);
- this.main_window.folder_list.copy_conversation.disconnect(on_copy_conversation);
- this.main_window.folder_list.move_conversation.disconnect(on_move_conversation);
- this.main_window.main_toolbar.copy_folder_menu.folder_selected.disconnect(on_copy_conversation);
- this.main_window.main_toolbar.move_folder_menu.folder_selected.disconnect(on_move_conversation);
this.main_window.conversation_viewer.conversation_added.disconnect(
on_conversation_view_added
);
@@ -401,9 +321,6 @@ public class Application.Controller : Geary.BaseObject {
// be freed up
this.plugin_manager.notifications.clear_folders();
- // drop the Revokable, which will commit it if necessary
- save_revokable(null, null);
-
this.cancellable_open_account.cancel();
// Create an array of known accounts so the loops below do not
@@ -554,50 +471,6 @@ public class Application.Controller : Geary.BaseObject {
}
}
- private void setup_actions() {
- this.main_window.add_action_entries(win_action_entries, this);
-
- // Marking actions
- //
- // Unmark is the primary action
- add_window_accelerators(ACTION_MARK_AS_READ, { "<Ctrl><Shift>U", "<Shift>I" });
- add_window_accelerators(ACTION_MARK_AS_UNREAD, { "<Ctrl>U", "<Shift>U" });
- // Ephy uses Ctrl+D for bookmarking
- add_window_accelerators(ACTION_MARK_AS_STARRED, { "<Ctrl>D", "S" });
- add_window_accelerators(ACTION_MARK_AS_UNSTARRED, { "<Ctrl><Shift>D", "D" });
- add_window_accelerators(ACTION_MARK_AS_SPAM, { "<Ctrl>J", "exclam" }); // Exclamation mark (!)
-
- // Replying & forwarding
- add_window_accelerators(ACTION_REPLY_TO_MESSAGE, { "<Ctrl>R", "R" });
- add_window_accelerators(ACTION_REPLY_ALL_MESSAGE, { "<Ctrl><Shift>R", "<Shift>R" });
- add_window_accelerators(ACTION_FORWARD_MESSAGE, { "<Ctrl>L", "F" });
-
- // Moving & labelling
- add_window_accelerators(ACTION_COPY_MENU, { "<Ctrl>L", "L" });
- add_window_accelerators(ACTION_MOVE_MENU, { "<Ctrl>M", "M" });
- add_window_accelerators(ACTION_ARCHIVE_CONVERSATION, { "<Ctrl>K", "A", "Y" });
- add_window_accelerators(ACTION_TRASH_CONVERSATION, { "Delete", "BackSpace" });
- add_window_accelerators(ACTION_DELETE_CONVERSATION, { "<Shift>Delete", "<Shift>BackSpace" });
-
- // Find & search
- add_window_accelerators(ACTION_FIND_IN_CONVERSATION, { "<Ctrl>F", "slash" });
- add_window_accelerators(ACTION_SEARCH, { "<Ctrl>S" });
-
- // Zoom
- add_window_accelerators(ACTION_ZOOM+("('in')"), { "<Ctrl>equal", "<Ctrl>plus" });
- add_window_accelerators(ACTION_ZOOM+("('out')"), { "<Ctrl>minus" });
- add_window_accelerators(ACTION_ZOOM+("('normal')"), { "<Ctrl>0" });
-
- // Navigation
- add_window_accelerators(ACTION_CONVERSATION_LIST, { "<Ctrl>B" });
- add_window_accelerators(ACTION_CONVERSATION_UP, { "<Ctrl>bracketleft", "K" });
- add_window_accelerators(ACTION_CONVERSATION_DOWN, { "<Ctrl>bracketright", "J" });
- }
-
- private void add_window_accelerators(string action, string[] accelerators, Variant? param = null) {
- this.application.set_accels_for_action("win."+action, accelerators);
- }
-
private void open_account(Geary.Account account) {
account.information.authentication_failure.connect(
on_authentication_failure
@@ -1041,7 +914,7 @@ public class Application.Controller : Geary.BaseObject {
this.main_window.folder_selected(null, null);
} else if (folder != this.current_folder) {
this.main_window.conversation_viewer.show_loading();
- get_window_action(ACTION_FIND_IN_CONVERSATION).set_enabled(false);
+ get_window_action(MainWindow.ACTION_FIND_IN_CONVERSATION).set_enabled(false);
enable_message_buttons(false);
// To prevent the user from selecting folders too quickly,
@@ -1087,9 +960,6 @@ public class Application.Controller : Geary.BaseObject {
// reenter.
int mutex_token = yield select_folder_mutex.claim_async(cancellable_folder);
- // clear Revokable, as Undo is only available while a folder is selected
- save_revokable(null, null);
-
// re-enable copy/move to the last selected folder
if (current_folder != null) {
main_window.main_toolbar.copy_folder_menu.enable_disable_folder(current_folder, true);
@@ -1146,7 +1016,7 @@ public class Application.Controller : Geary.BaseObject {
private void on_conversations_selected(Gee.Set<Geary.App.Conversation> selected) {
this.selected_conversations = selected;
- get_window_action(ACTION_FIND_IN_CONVERSATION).set_enabled(false);
+ get_window_action(MainWindow.ACTION_FIND_IN_CONVERSATION).set_enabled(false);
ConversationViewer viewer = this.main_window.conversation_viewer;
if (this.current_folder != null && !this.main_window.has_composer) {
switch(selected.size) {
@@ -1181,7 +1051,7 @@ public class Application.Controller : Geary.BaseObject {
viewer.load_conversation.end(ret);
enable_message_buttons(true);
get_window_action(
- ACTION_FIND_IN_CONVERSATION
+ MainWindow.ACTION_FIND_IN_CONVERSATION
).set_enabled(true);
} catch (GLib.IOError.CANCELLED err) {
// All good
@@ -1469,56 +1339,6 @@ public class Application.Controller : Geary.BaseObject {
);
}
- private void mark_email(Gee.Collection<Geary.EmailIdentifier> ids,
- Geary.EmailFlags? flags_to_add, Geary.EmailFlags? flags_to_remove) {
- if (ids.size > 0) {
- Geary.App.EmailStore? store = get_email_store_for_folder(current_folder);
- if (store != null) {
- store.mark_email_async.begin(
- ids, flags_to_add, flags_to_remove, cancellable_folder
- );
- }
- }
- }
-
- private void on_show_mark_menu() {
- bool unread_selected = false;
- bool read_selected = false;
- bool starred_selected = false;
- bool unstarred_selected = false;
- foreach (Geary.App.Conversation conversation in selected_conversations) {
- if (conversation.is_unread())
- unread_selected = true;
-
- // Only check the messages that "Mark as Unread" would mark, so we
- // don't add the menu option and have it not do anything.
- //
- // Sort by Date: field to correspond with ConversationViewer ordering
- Geary.Email? latest = conversation.get_latest_sent_email(
- Geary.App.Conversation.Location.IN_FOLDER_OUT_OF_FOLDER);
- if (latest != null && latest.email_flags != null
- && !latest.email_flags.contains(Geary.EmailFlags.UNREAD))
- read_selected = true;
-
- if (conversation.is_flagged()) {
- starred_selected = true;
- } else {
- unstarred_selected = true;
- }
- }
- get_window_action(ACTION_MARK_AS_READ).set_enabled(unread_selected);
- get_window_action(ACTION_MARK_AS_UNREAD).set_enabled(read_selected);
- get_window_action(ACTION_MARK_AS_STARRED).set_enabled(unstarred_selected);
- get_window_action(ACTION_MARK_AS_UNSTARRED).set_enabled(starred_selected);
-
- bool in_spam_folder = current_folder.special_folder_type == Geary.SpecialFolderType.SPAM;
- get_window_action(ACTION_MARK_AS_NOT_SPAM).set_enabled(in_spam_folder);
- // If we're in Drafts/Outbox, we also shouldn't set a message as SPAM.
- get_window_action(ACTION_MARK_AS_SPAM).set_enabled(!in_spam_folder &&
- current_folder.special_folder_type != Geary.SpecialFolderType.DRAFTS &&
- current_folder.special_folder_type != Geary.SpecialFolderType.OUTBOX);
- }
-
private void on_visible_conversations_changed(Gee.Set<Geary.App.Conversation> visible) {
clear_new_messages("on_visible_conversations_changed", visible);
}
@@ -1558,139 +1378,9 @@ public class Application.Controller : Geary.BaseObject {
}
}
- private void on_mark_conversations(Gee.Collection<Geary.App.Conversation> conversations,
- Geary.EmailFlags? flags_to_add, Geary.EmailFlags? flags_to_remove,
- bool latest_only = false) {
- mark_email(get_conversation_email_ids(conversations, latest_only),
- flags_to_add, flags_to_remove);
- }
-
- private void on_conversation_viewer_mark_emails(Gee.Collection<Geary.EmailIdentifier> emails,
- Geary.EmailFlags? flags_to_add, Geary.EmailFlags? flags_to_remove) {
- mark_email(emails, flags_to_add, flags_to_remove);
- }
-
- private void on_mark_as_read(SimpleAction action) {
- Geary.EmailFlags flags = new Geary.EmailFlags();
- flags.add(Geary.EmailFlags.UNREAD);
-
- Gee.Collection<Geary.EmailIdentifier> ids = get_selected_email_ids(false);
- mark_email(ids, null, flags);
-
- ConversationListBox? list =
- main_window.conversation_viewer.current_list;
- if (list != null) {
- foreach (Geary.EmailIdentifier id in ids)
- list.mark_manual_read(id);
- }
- }
-
- private void on_mark_as_unread(SimpleAction action) {
- Geary.EmailFlags flags = new Geary.EmailFlags();
- flags.add(Geary.EmailFlags.UNREAD);
-
- Gee.Collection<Geary.EmailIdentifier> ids = get_selected_email_ids(true);
- mark_email(ids, flags, null);
-
- ConversationListBox? list =
- main_window.conversation_viewer.current_list;
- if (list != null) {
- foreach (Geary.EmailIdentifier id in ids)
- list.mark_manual_unread(id);
- }
- }
-
- private void on_mark_as_starred(SimpleAction action) {
- Geary.EmailFlags flags = new Geary.EmailFlags();
- flags.add(Geary.EmailFlags.FLAGGED);
- mark_email(get_selected_email_ids(true), flags, null);
- }
-
- private void on_mark_as_unstarred(SimpleAction action) {
- Geary.EmailFlags flags = new Geary.EmailFlags();
- flags.add(Geary.EmailFlags.FLAGGED);
- mark_email(get_selected_email_ids(false), null, flags);
- }
-
- private void on_show_move_menu(SimpleAction? action) {
- this.main_window.main_toolbar.move_message_button.clicked();
- }
-
- private void on_show_copy_menu(SimpleAction? action) {
- this.main_window.main_toolbar.copy_message_button.clicked();
- }
-
- private async void mark_as_spam_toggle_async(Cancellable? cancellable) {
- Geary.Folder? destination_folder = null;
- if (current_folder.special_folder_type != Geary.SpecialFolderType.SPAM) {
- // Move to spam folder.
- try {
- destination_folder = yield current_account.get_required_special_folder_async(
- Geary.SpecialFolderType.SPAM, cancellable);
- } catch (Error e) {
- debug("Error getting spam folder: %s", e.message);
- }
- } else {
- // Move out of spam folder, back to inbox.
- destination_folder = current_account.get_special_folder(Geary.SpecialFolderType.INBOX);
- }
-
- if (destination_folder != null)
- on_move_conversation(destination_folder);
- }
-
- private void on_mark_as_spam_toggle(SimpleAction action) {
- mark_as_spam_toggle_async.begin(null);
- }
-
- private void copy_email(Gee.Collection<Geary.EmailIdentifier> ids,
- Geary.FolderPath destination) {
- if (ids.size > 0) {
- Geary.App.EmailStore? store = get_email_store_for_folder(current_folder);
- if (store != null) {
- store.copy_email_async.begin(
- ids, destination, cancellable_folder
- );
- }
- }
- }
-
- private void on_copy_conversation(Geary.Folder destination) {
- copy_email(get_selected_email_ids(false), destination.path);
- }
-
- private void on_move_conversation(Geary.Folder destination) {
- // Nothing to do if nothing selected.
- if (selected_conversations == null || selected_conversations.size == 0)
- return;
-
- Gee.Collection<Geary.EmailIdentifier> ids = get_selected_email_ids(false);
- if (ids.size == 0)
- return;
-
- selection_operation_started();
-
- Geary.FolderSupport.Move? supports_move = current_folder as Geary.FolderSupport.Move;
- if (supports_move != null)
- move_conversation_async.begin(
- supports_move, ids, destination.path, cancellable_folder,
- (obj, ret) => {
- move_conversation_async.end(ret);
- selection_operation_finished();
- });
- }
-
- private async void move_conversation_async(Geary.FolderSupport.Move source_folder,
- Gee.Collection<Geary.EmailIdentifier> ids,
- Geary.FolderPath destination,
- Cancellable? cancellable) {
- try {
- save_revokable(yield source_folder.move_email_async(ids, destination, cancellable),
- ngettext("Moved %d message to %s", "Moved %d messages to %s", ids.size).printf(ids.size,
destination.to_string()));
- } catch (Error err) {
- debug("%s: Unable to move %d emails: %s", source_folder.to_string(), ids.size,
- err.message);
- }
+ private void on_conversation_viewer_mark_emails(Gee.Collection<Geary.EmailIdentifier> email,
+ Geary.EmailFlags? to_add,
+ Geary.EmailFlags? to_remove) {
}
private void on_attachments_activated(Gee.Collection<Geary.Attachment> attachments) {
@@ -1952,29 +1642,6 @@ public class Application.Controller : Geary.BaseObject {
return true;
}
- // View contains the email from whose menu this reply or forward
- // was triggered. If null, this was triggered from the headerbar
- // or shortcut.
- private void create_reply_forward_widget(ComposerWidget.ComposeType compose_type,
- owned ConversationEmail? email_view) {
- if (email_view == null) {
- ConversationListBox? list_view =
- main_window.conversation_viewer.current_list;
- if (list_view != null) {
- email_view = list_view.get_reply_target();
- }
- }
-
- if (email_view != null) {
- email_view.get_selection_for_quoting.begin((obj, res) => {
- string? quote = email_view.get_selection_for_quoting.end(res);
- create_compose_widget(compose_type, email_view.email, quote);
- });
- } else {
- create_compose_widget(compose_type, email_view.email, null);
- }
- }
-
/**
* Creates a composer widget.
*
@@ -2110,323 +1777,12 @@ public class Application.Controller : Geary.BaseObject {
}
}
- private void on_close() {
- this.main_window.close();
- }
-
- private void on_reply_to_message(ConversationEmail target_view) {
- create_reply_forward_widget(ComposerWidget.ComposeType.REPLY, target_view);
- }
-
- private void on_reply_to_message_action(SimpleAction action) {
- create_reply_forward_widget(ComposerWidget.ComposeType.REPLY, null);
- }
-
- private void on_reply_all_message(ConversationEmail target_view) {
- create_reply_forward_widget(ComposerWidget.ComposeType.REPLY_ALL, target_view);
- }
-
- private void on_reply_all_message_action(SimpleAction action) {
- create_reply_forward_widget(ComposerWidget.ComposeType.REPLY_ALL, null);
- }
-
- private void on_forward_message(ConversationEmail target_view) {
- create_reply_forward_widget(ComposerWidget.ComposeType.FORWARD, target_view);
- }
-
- private void on_forward_message_action(SimpleAction action) {
- create_reply_forward_widget(ComposerWidget.ComposeType.FORWARD, null);
- }
-
- private void on_find_in_conversation_action(SimpleAction action) {
- this.main_window.conversation_viewer.enable_find();
- }
-
- private void on_search_activated(SimpleAction action) {
- this.main_window.show_search_bar();
- }
-
- private void on_archive_conversation(SimpleAction action) {
- archive_or_delete_selection_async.begin(true, false, cancellable_folder,
- on_archive_or_delete_selection_finished);
- }
-
- private void on_trash_conversation(SimpleAction action) {
- archive_or_delete_selection_async.begin(false, true, cancellable_folder,
- on_archive_or_delete_selection_finished);
- }
-
- private void on_delete_conversation(SimpleAction action) {
- archive_or_delete_selection_async.begin(false, false, cancellable_folder,
- on_archive_or_delete_selection_finished);
- }
-
- private void on_empty_spam(SimpleAction action) {
- on_empty_trash_or_spam(Geary.SpecialFolderType.SPAM);
- }
-
- private void on_empty_trash(SimpleAction action) {
- on_empty_trash_or_spam(Geary.SpecialFolderType.TRASH);
- }
-
- private void on_empty_trash_or_spam(Geary.SpecialFolderType special_folder_type) {
- // Account must be in place, must have the specified special folder type, and that folder
- // must support Empty in order for this command to proceed
- if (current_account == null)
- return;
-
- Geary.Folder? folder = current_account.get_special_folder(special_folder_type);
- if (folder == null)
- return;
-
- Geary.FolderSupport.Empty? emptyable = folder as Geary.FolderSupport.Empty;
- if (emptyable == null) {
- debug("%s: Special folder %s (%s) does not support emptying", current_account.to_string(),
- folder.path.to_string(), special_folder_type.to_string());
-
- return;
- }
-
- ConfirmationDialog dialog = new ConfirmationDialog(main_window,
- _("Empty all email from your %s folder?").printf(special_folder_type.get_display_name()),
- _("This removes the email from Geary and your email server.")
- + " <b>" + _("This cannot be undone.") + "</b>",
- _("Empty %s").printf(special_folder_type.get_display_name()), "destructive-action");
- dialog.use_secondary_markup(true);
- dialog.set_focus_response(Gtk.ResponseType.CANCEL);
-
- if (dialog.run() == Gtk.ResponseType.OK)
- empty_folder_async.begin(emptyable, cancellable_folder);
- }
-
- private async void empty_folder_async(Geary.FolderSupport.Empty emptyable, Cancellable? cancellable) {
- try {
- yield do_empty_folder_async(emptyable, cancellable);
- } catch (Error err) {
- // don't report to user if cancelled
- if (err is IOError.CANCELLED)
- return;
-
- ErrorDialog dialog = new ErrorDialog(main_window,
- _("Error emptying %s").printf(emptyable.get_display_name()), err.message);
- dialog.run();
- }
- }
-
- private async void do_empty_folder_async(Geary.FolderSupport.Empty emptyable, Cancellable? cancellable)
- throws Error {
- bool open = false;
- try {
- yield emptyable.open_async(Geary.Folder.OpenFlags.NO_DELAY, cancellable);
- open = true;
- yield emptyable.empty_folder_async(cancellable);
- } finally {
- if (open) {
- try {
- yield emptyable.close_async(null);
- } catch (Error err) {
- // ignored
- }
- }
- }
- }
-
private bool current_folder_supports_trash() {
return (current_folder != null && current_folder.special_folder_type != Geary.SpecialFolderType.TRASH
&& !current_folder.properties.is_local_only && current_account != null
&& (current_folder as Geary.FolderSupport.Move) != null);
}
- private bool confirm_delete(int num_messages) {
- ConfirmationDialog dialog = new ConfirmationDialog(main_window, ngettext(
- "Do you want to permanently delete this message?",
- "Do you want to permanently delete these messages?", num_messages),
- null, _("Delete"), "destructive-action");
-
- return (dialog.run() == Gtk.ResponseType.OK);
- }
-
- private async void trash_messages_async(Gee.Collection<Geary.EmailIdentifier> ids, Cancellable?
cancellable)
- throws Error {
- debug("Trashing selected messages");
-
- Geary.FolderSupport.Move? supports_move = current_folder as Geary.FolderSupport.Move;
- if (current_folder_supports_trash() && supports_move != null) {
- Geary.FolderPath trash_path = (yield current_account.get_required_special_folder_async(
- Geary.SpecialFolderType.TRASH, cancellable)).path;
- save_revokable(yield supports_move.move_email_async(ids, trash_path, cancellable),
- ngettext("Trashed %d message", "Trashed %d messages", ids.size).printf(ids.size));
- } else {
- debug("Folder %s doesn't support move or account %s doesn't have a trash folder",
- current_folder.to_string(), current_account.to_string());
- }
- }
-
- private async void delete_messages_async(Gee.Collection<Geary.EmailIdentifier> ids, Cancellable?
cancellable)
- throws Error {
- debug("Deleting selected messages");
-
- Geary.FolderSupport.Remove? supports_remove = current_folder as Geary.FolderSupport.Remove;
- if (supports_remove != null) {
- if (confirm_delete(ids.size)) {
- yield supports_remove.remove_email_async(ids, cancellable);
- } else {
- last_deleted_conversation = null;
- }
- } else {
- debug("Folder %s doesn't support remove", current_folder.to_string());
- }
- }
-
- private async void archive_or_delete_selection_async(bool archive, bool trash,
- Cancellable? cancellable) throws Error {
- ConversationListBox list_view =
- main_window.conversation_viewer.current_list;
- if (list_view != null &&
- list_view.conversation == last_deleted_conversation) {
- debug("Not archiving/trashing/deleting; viewed conversation is last deleted conversation");
- return;
- }
-
- selection_operation_started();
-
- last_deleted_conversation = selected_conversations.size > 0
- ? Geary.traverse<Geary.App.Conversation>(selected_conversations).first() : null;
-
- Gee.Collection<Geary.EmailIdentifier> ids = get_selected_email_ids(false);
- if (archive) {
- debug("Archiving selected messages");
-
- Geary.FolderSupport.Archive? supports_archive = current_folder as Geary.FolderSupport.Archive;
- if (supports_archive == null) {
- debug("Folder %s doesn't support archive", current_folder.to_string());
- } else {
- save_revokable(yield supports_archive.archive_email_async(ids, cancellable),
- ngettext("Archived %d message", "Archived %d messages", ids.size).printf(ids.size));
- }
-
- return;
- }
-
- if (trash) {
- yield trash_messages_async(ids, cancellable);
- } else {
- yield delete_messages_async(ids, cancellable);
- }
- }
-
- private void on_archive_or_delete_selection_finished(Object? source, AsyncResult result) {
- try {
- archive_or_delete_selection_async.end(result);
- } catch (Error e) {
- debug("Unable to archive/trash/delete messages: %s", e.message);
- }
- selection_operation_finished();
- }
-
- private void save_revokable(Geary.Revokable? new_revokable, string? description) {
- // disconnect old revokable & blindly commit it
- if (revokable != null) {
- revokable.notify[Geary.Revokable.PROP_VALID].disconnect(on_revokable_valid_changed);
- revokable.notify[Geary.Revokable.PROP_IN_PROCESS].disconnect(update_revokable_action);
- revokable.committed.disconnect(on_revokable_committed);
-
- revokable.commit_async.begin();
- }
-
- // store new revokable
- this.revokable = new_revokable;
- this.revokable_description = description;
-
- // connect to new revokable
- if (revokable != null) {
- revokable.notify[Geary.Revokable.PROP_VALID].connect(on_revokable_valid_changed);
- revokable.notify[Geary.Revokable.PROP_IN_PROCESS].connect(update_revokable_action);
- revokable.committed.connect(on_revokable_committed);
- }
-
- if (this.main_window != null) {
- if (this.revokable != null && this.revokable_description != null) {
- Components.InAppNotification ian =
- new Components.InAppNotification(this.revokable_description);
- ian.set_button(_("Undo"), "win." + GearyApplication.ACTION_UNDO);
- this.main_window.add_notification(ian);
- }
- update_revokable_action();
- }
- }
-
- private void update_revokable_action() {
- get_window_action(GearyApplication.ACTION_UNDO).set_enabled(
- this.revokable != null &&
- this.revokable.valid &&
- !this.revokable.in_process
- );
- }
-
- private void on_revokable_valid_changed() {
- // remove revokable if it goes invalid
- if (revokable != null && !revokable.valid)
- save_revokable(null, null);
- }
-
- private void on_revokable_committed(Geary.Revokable? committed_revokable) {
- if (committed_revokable == null)
- return;
-
- save_revokable(committed_revokable, this.revokable_description);
- }
-
- private void on_revoke() {
- if (revokable != null && revokable.valid)
- revokable.revoke_async.begin(null, on_revoke_completed);
- }
-
- private void on_revoke_completed(Object? object, AsyncResult result) {
- // Don't use the "revokable" instance because it might have gone null before this callback
- // was reached
- Geary.Revokable? origin = object as Geary.Revokable;
- if (origin == null)
- return;
-
- try {
- origin.revoke_async.end(result);
- } catch (Error err) {
- debug("Unable to revoke operation: %s", err.message);
- }
- }
-
- private void selection_operation_started() {
- this.operation_count += 1;
- if (this.operation_count == 1) {
- this.main_window.conversation_list_view.set_changing_selection(true);
- }
- }
-
- private void selection_operation_finished() {
- this.operation_count -= 1;
- if (this.operation_count == 0) {
- this.main_window.conversation_list_view.set_changing_selection(false);
- }
- }
-
- private void on_zoom(SimpleAction action, Variant? parameter) {
- ConversationListBox? view = main_window.conversation_viewer.current_list;
- if (view != null && parameter != null) {
- string zoom_action = parameter.get_string();
- if (zoom_action == "in")
- view.zoom_in();
- else if (zoom_action == "out")
- view.zoom_out();
- else
- view.zoom_reset();
- }
- }
-
- private void on_conversation_list() {
- this.main_window.conversation_list_view.grab_focus();
- }
-
private void on_sent(Geary.Account account, Geary.RFC822.Message sent) {
// Translators: The label for an in-app notification. The
// string substitution is a list of recipients of the email.
@@ -2478,17 +1834,9 @@ public class Application.Controller : Geary.BaseObject {
}
private void on_trash_message(ConversationEmail target_view) {
- Gee.Collection<Geary.EmailIdentifier> ids =
- new Gee.ArrayList<Geary.EmailIdentifier>();
- ids.add(target_view.email.id);
- trash_messages_async.begin(ids, cancellable_folder);
}
private void on_delete_message(ConversationEmail target_view) {
- Gee.Collection<Geary.EmailIdentifier> ids =
- new Gee.ArrayList<Geary.EmailIdentifier>();
- ids.add(target_view.email.id);
- delete_messages_async.begin(ids, cancellable_folder);
}
private void on_view_source(ConversationEmail email_view) {
@@ -2526,15 +1874,15 @@ public class Application.Controller : Geary.BaseObject {
main_window.main_toolbar.selected_conversations = this.selected_conversations.size;
// Single message only buttons.
- get_window_action(ACTION_REPLY_TO_MESSAGE).set_enabled(false);
- get_window_action(ACTION_REPLY_ALL_MESSAGE).set_enabled(false);
- get_window_action(ACTION_FORWARD_MESSAGE).set_enabled(false);
+ get_window_action(MainWindow.ACTION_REPLY_TO_MESSAGE).set_enabled(false);
+ get_window_action(MainWindow.ACTION_REPLY_ALL_MESSAGE).set_enabled(false);
+ get_window_action(MainWindow.ACTION_FORWARD_MESSAGE).set_enabled(false);
// Mutliple message buttons.
- get_window_action(ACTION_MOVE_MENU).set_enabled(current_folder is Geary.FolderSupport.Move);
- get_window_action(ACTION_ARCHIVE_CONVERSATION).set_enabled(current_folder is
Geary.FolderSupport.Archive);
- get_window_action(ACTION_TRASH_CONVERSATION).set_enabled(current_folder_supports_trash());
- get_window_action(ACTION_DELETE_CONVERSATION).set_enabled(current_folder is
Geary.FolderSupport.Remove);
+ get_window_action(MainWindow.ACTION_MOVE_MENU).set_enabled(current_folder is
Geary.FolderSupport.Move);
+ get_window_action(MainWindow.ACTION_ARCHIVE_CONVERSATION).set_enabled(current_folder is
Geary.FolderSupport.Archive);
+ get_window_action(MainWindow.ACTION_TRASH_CONVERSATION).set_enabled(current_folder_supports_trash());
+ get_window_action(MainWindow.ACTION_DELETE_CONVERSATION).set_enabled(current_folder is
Geary.FolderSupport.Remove);
cancel_context_dependent_buttons();
enable_context_dependent_buttons_async.begin(true, cancellable_context_dependent_buttons);
@@ -2549,13 +1897,13 @@ public class Application.Controller : Geary.BaseObject {
if (current_folder != null && current_folder.special_folder_type == Geary.SpecialFolderType.DRAFTS)
respond_sensitive = false;
- get_window_action(ACTION_REPLY_TO_MESSAGE).set_enabled(respond_sensitive);
- get_window_action(ACTION_REPLY_ALL_MESSAGE).set_enabled(respond_sensitive);
- get_window_action(ACTION_FORWARD_MESSAGE).set_enabled(respond_sensitive);
- get_window_action(ACTION_MOVE_MENU).set_enabled(sensitive && (current_folder is
Geary.FolderSupport.Move));
- get_window_action(ACTION_ARCHIVE_CONVERSATION).set_enabled(sensitive && (current_folder is
Geary.FolderSupport.Archive));
- get_window_action(ACTION_TRASH_CONVERSATION).set_enabled(sensitive &&
current_folder_supports_trash());
- get_window_action(ACTION_DELETE_CONVERSATION).set_enabled(sensitive && (current_folder is
Geary.FolderSupport.Remove));
+ get_window_action(MainWindow.ACTION_REPLY_TO_MESSAGE).set_enabled(respond_sensitive);
+ get_window_action(MainWindow.ACTION_REPLY_ALL_MESSAGE).set_enabled(respond_sensitive);
+ get_window_action(MainWindow.ACTION_FORWARD_MESSAGE).set_enabled(respond_sensitive);
+ get_window_action(MainWindow.ACTION_MOVE_MENU).set_enabled(sensitive && (current_folder is
Geary.FolderSupport.Move));
+ get_window_action(MainWindow.ACTION_ARCHIVE_CONVERSATION).set_enabled(sensitive && (current_folder
is Geary.FolderSupport.Archive));
+ get_window_action(MainWindow.ACTION_TRASH_CONVERSATION).set_enabled(sensitive &&
current_folder_supports_trash());
+ get_window_action(MainWindow.ACTION_DELETE_CONVERSATION).set_enabled(sensitive && (current_folder is
Geary.FolderSupport.Remove));
cancel_context_dependent_buttons();
enable_context_dependent_buttons_async.begin(sensitive, cancellable_context_dependent_buttons);
@@ -2584,8 +1932,8 @@ public class Application.Controller : Geary.BaseObject {
if (selected_operations != null)
supported_operations.add_all(selected_operations.get_values());
- get_window_action(ACTION_SHOW_MARK_MENU).set_enabled(sensitive && (typeof(Geary.FolderSupport.Mark)
in supported_operations));
- get_window_action(ACTION_COPY_MENU).set_enabled(sensitive &&
(supported_operations.contains(typeof(Geary.FolderSupport.Copy))));
+ get_window_action(MainWindow.ACTION_SHOW_MARK_MENU).set_enabled(sensitive &&
(typeof(Geary.FolderSupport.Mark) in supported_operations));
+ get_window_action(MainWindow.ACTION_COPY_MENU).set_enabled(sensitive &&
(supported_operations.contains(typeof(Geary.FolderSupport.Copy))));
}
// Returns a list of composer windows for an account, or null if none.
@@ -2842,12 +2190,25 @@ public class Application.Controller : Geary.BaseObject {
);
}
- private void on_conversation_up() {
- this.main_window.conversation_list_view.scroll(Gtk.ScrollType.STEP_UP);
+ private void on_reply_to_message(ConversationEmail target_view) {
+ target_view.get_selection_for_quoting.begin((obj, res) => {
+ string? quote = target_view.get_selection_for_quoting.end(res);
+ create_compose_widget(REPLY, target_view.email, quote);
+ });
+ }
+
+ private void on_reply_all_message(ConversationEmail target_view) {
+ target_view.get_selection_for_quoting.begin((obj, res) => {
+ string? quote = target_view.get_selection_for_quoting.end(res);
+ create_compose_widget(REPLY_ALL, target_view.email, quote);
+ });
}
- private void on_conversation_down() {
- this.main_window.conversation_list_view.scroll(Gtk.ScrollType.STEP_DOWN);
+ private void on_forward_message(ConversationEmail target_view) {
+ target_view.get_selection_for_quoting.begin((obj, res) => {
+ string? quote = target_view.get_selection_for_quoting.end(res);
+ create_compose_widget(FORWARD, target_view.email, quote);
+ });
}
private void on_save_attachments(Gee.Collection<Geary.Attachment> attachments) {
diff --git a/src/client/application/geary-application.vala b/src/client/application/geary-application.vala
index 5746ad0c..3fe307cb 100644
--- a/src/client/application/geary-application.vala
+++ b/src/client/application/geary-application.vala
@@ -446,6 +446,7 @@ public class GearyApplication : Gtk.Application {
add_window_accelerators(ACTION_REDO, { "<Ctrl><Shift>Z" });
add_window_accelerators(ACTION_UNDO, { "<Ctrl>Z" });
+ MainWindow.add_window_accelerators(this);
ComposerWidget.add_window_accelerators(this);
Components.Inspector.add_window_accelerators(this);
diff --git a/src/client/components/main-toolbar.vala b/src/client/components/main-toolbar.vala
index 8896f1df..8d40bf7e 100644
--- a/src/client/components/main-toolbar.vala
+++ b/src/client/components/main-toolbar.vala
@@ -157,7 +157,7 @@ public class MainToolbar : Gtk.Box {
);
if (this.show_trash_button) {
- this.trash_delete_button.action_name = "win."+Application.Controller.ACTION_TRASH_CONVERSATION;
+ this.trash_delete_button.action_name = "win."+MainWindow.ACTION_TRASH_CONVERSATION;
this.trash_delete_button.image = trash_image;
this.trash_delete_button.tooltip_text = ngettext(
"Move conversation to Trash",
@@ -165,7 +165,7 @@ public class MainToolbar : Gtk.Box {
this.selected_conversations
);
} else {
- this.trash_delete_button.action_name = "win."+Application.Controller.ACTION_DELETE_CONVERSATION;
+ this.trash_delete_button.action_name = "win."+MainWindow.ACTION_DELETE_CONVERSATION;
this.trash_delete_button.image = delete_image;
this.trash_delete_button.tooltip_text = ngettext(
"Delete conversation",
diff --git a/src/client/components/main-window.vala b/src/client/components/main-window.vala
index 9ee97cda..2d034cbb 100644
--- a/src/client/components/main-window.vala
+++ b/src/client/components/main-window.vala
@@ -10,16 +10,165 @@
public class MainWindow : Gtk.ApplicationWindow, Geary.BaseInterface {
+ // Named actions.
+ public const string ACTION_ARCHIVE_CONVERSATION = "archive-conv";
+ public const string ACTION_CONVERSATION_DOWN = "down-conversation";
+ public const string ACTION_CONVERSATION_LIST = "focus-conv-list";
+ public const string ACTION_CONVERSATION_UP = "up-conversation";
+ public const string ACTION_COPY_MENU = "show-copy-menu";
+ public const string ACTION_DELETE_CONVERSATION = "delete-conv";
+ public const string ACTION_EMPTY_SPAM = "empty-spam";
+ public const string ACTION_EMPTY_TRASH = "empty-trash";
+ public const string ACTION_FIND_IN_CONVERSATION = "conv-find";
+ public const string ACTION_FORWARD_MESSAGE = "forward-message";
+ public const string ACTION_MARK_AS_READ = "mark-message-read";
+ public const string ACTION_MARK_AS_STARRED = "mark-message-starred";
+ public const string ACTION_MARK_AS_UNREAD = "mark-message-unread";
+ public const string ACTION_MARK_AS_UNSTARRED = "mark-message-unstarred";
+ public const string ACTION_MOVE_MENU = "show-move-menu";
+ public const string ACTION_REPLY_ALL_MESSAGE = "reply-all-message";
+ public const string ACTION_REPLY_TO_MESSAGE = "reply-to-message";
+ public const string ACTION_SEARCH = "search-conv";
+ public const string ACTION_SHOW_MARK_MENU = "mark-message-menu";
+ public const string ACTION_TOGGLE_FIND = "toggle-find";
+ public const string ACTION_TOGGLE_SEARCH = "toggle-search";
+ public const string ACTION_TOGGLE_SPAM = "toggle-message-spam";
+ public const string ACTION_TRASH_CONVERSATION = "trash-conv";
+ public const string ACTION_ZOOM = "zoom";
+
private const int STATUS_BAR_HEIGHT = 18;
private const int UPDATE_UI_INTERVAL = 60;
private const int MIN_CONVERSATION_COUNT = 50;
+ private const ActionEntry[] win_action_entries = {
+ {GearyApplication.ACTION_CLOSE, on_close },
+ {GearyApplication.ACTION_UNDO, on_undo },
+ {GearyApplication.ACTION_REDO, on_redo },
+
+ {ACTION_CONVERSATION_LIST, on_conversation_list },
+ {ACTION_FIND_IN_CONVERSATION, on_find_in_conversation_action },
+ {ACTION_SEARCH, on_search_activated },
+ {ACTION_EMPTY_SPAM, on_empty_spam },
+ {ACTION_EMPTY_TRASH, on_empty_trash },
+ // Message actions
+ {ACTION_REPLY_TO_MESSAGE, on_reply_to_message },
+ {ACTION_REPLY_ALL_MESSAGE, on_reply_all_message },
+ {ACTION_FORWARD_MESSAGE, on_forward_message },
+ {ACTION_ARCHIVE_CONVERSATION, on_archive_conversation },
+ {ACTION_TRASH_CONVERSATION, on_trash_conversation },
+ {ACTION_DELETE_CONVERSATION, on_delete_conversation },
+ {ACTION_COPY_MENU, on_show_copy_menu },
+ {ACTION_MOVE_MENU, on_show_move_menu },
+ {ACTION_CONVERSATION_UP, on_conversation_up },
+ {ACTION_CONVERSATION_DOWN, on_conversation_down },
+ // Message marking actions
+ {ACTION_SHOW_MARK_MENU, on_show_mark_menu },
+ {ACTION_MARK_AS_READ, on_mark_as_read },
+ {ACTION_MARK_AS_UNREAD, on_mark_as_unread },
+ {ACTION_MARK_AS_STARRED, on_mark_as_starred },
+ {ACTION_MARK_AS_UNSTARRED, on_mark_as_unstarred },
+ {ACTION_TOGGLE_SPAM, on_mark_as_spam_toggle },
+ // Message viewer
+ {ACTION_ZOOM, on_zoom, "s" },
+ };
+
+
+ public static void add_window_accelerators(GearyApplication owner) {
+ // Marking actions
+ //
+ // Unmark is the primary action
+ owner.add_window_accelerators(
+ ACTION_MARK_AS_READ, { "<Ctrl><Shift>U", "<Shift>I" }
+ );
+ owner.add_window_accelerators(
+ ACTION_MARK_AS_UNREAD, { "<Ctrl>U", "<Shift>U" }
+ );
+ // Ephy uses Ctrl+D for bookmarking
+ owner.add_window_accelerators(
+ ACTION_MARK_AS_STARRED, { "<Ctrl>D", "S" }
+ );
+ owner.add_window_accelerators(
+ ACTION_MARK_AS_UNSTARRED, { "<Ctrl><Shift>D", "D" }
+ );
+ owner.add_window_accelerators(
+ ACTION_TOGGLE_SPAM, { "<Ctrl>J", "exclam" } // Exclamation mark (!)
+ );
+
+ // Replying & forwarding
+ owner.add_window_accelerators(
+ ACTION_REPLY_TO_MESSAGE, { "<Ctrl>R", "R" }
+ );
+ owner.add_window_accelerators(
+ ACTION_REPLY_ALL_MESSAGE, { "<Ctrl><Shift>R", "<Shift>R" }
+ );
+ owner.add_window_accelerators(
+ ACTION_FORWARD_MESSAGE, { "<Ctrl>L", "F" }
+ );
+
+ // Moving & labelling
+ owner.add_window_accelerators(
+ ACTION_COPY_MENU, { "<Ctrl>L", "L" }
+ );
+ owner.add_window_accelerators(
+ ACTION_MOVE_MENU, { "<Ctrl>M", "M" }
+ );
+ owner.add_window_accelerators(
+ ACTION_ARCHIVE_CONVERSATION, { "<Ctrl>K", "A", "Y" }
+ );
+ owner.add_window_accelerators(
+ ACTION_TRASH_CONVERSATION, { "Delete", "BackSpace" }
+ );
+ owner.add_window_accelerators(
+ ACTION_DELETE_CONVERSATION, { "<Shift>Delete", "<Shift>BackSpace" }
+ );
+
+ // Find & search
+ owner.add_window_accelerators(
+ ACTION_FIND_IN_CONVERSATION, { "<Ctrl>F", "slash" }
+ );
+ owner.add_window_accelerators(
+ ACTION_SEARCH, { "<Ctrl>S" }
+ );
+
+ // Zoom
+ owner.add_window_accelerators(
+ ACTION_ZOOM+("('in')"), { "<Ctrl>equal", "<Ctrl>plus" }
+ );
+ owner.add_window_accelerators(
+ ACTION_ZOOM+("('out')"), { "<Ctrl>minus" }
+ );
+ owner.add_window_accelerators(
+ ACTION_ZOOM+("('normal')"), { "<Ctrl>0" }
+ );
+
+ // Navigation
+ owner.add_window_accelerators(
+ ACTION_CONVERSATION_LIST, { "<Ctrl>B" }
+ );
+ owner.add_window_accelerators(
+ ACTION_CONVERSATION_UP, { "<Ctrl>bracketleft", "K" }
+ );
+ owner.add_window_accelerators(
+ ACTION_CONVERSATION_DOWN, { "<Ctrl>bracketright", "J" }
+ );
+ }
+
public new GearyApplication application {
get { return (GearyApplication) base.get_application(); }
set { base.set_application(value); }
}
+ /** Currently selected account, null if none selected */
+ public Geary.Account? current_account {
+ owned get {
+ Geary.Account? account = null;
+ if (this.current_folder != null) {
+ account = this.current_folder.account;
+ }
+ return account;
+ }
+ }
/** Currently selected folder, null if none selected */
public Geary.Folder? current_folder { get; private set; default = null; }
@@ -110,14 +259,15 @@ public class MainWindow : Gtk.ApplicationWindow, Geary.BaseInterface {
load_config(application.config);
restore_saved_window_state();
-
- this.application.engine.account_available.connect(on_account_available);
- this.application.engine.account_unavailable.connect(on_account_unavailable);
+ add_action_entries(win_action_entries, this);
set_styling();
setup_layout(application.config);
on_change_orientation();
+ this.application.engine.account_available.connect(on_account_available);
+ this.application.engine.account_unavailable.connect(on_account_unavailable);
+
this.update_ui_timeout = new Geary.TimeoutManager.seconds(
UPDATE_UI_INTERVAL, on_update_ui_timeout
);
@@ -235,7 +385,7 @@ public class MainWindow : Gtk.ApplicationWindow, Geary.BaseInterface {
new ComposerWindow(composer, this.application);
} else {
this.conversation_viewer.do_compose(composer);
- get_action(Application.Controller.ACTION_FIND_IN_CONVERSATION).set_enabled(false);
+ get_action(ACTION_FIND_IN_CONVERSATION).set_enabled(false);
}
}
@@ -382,6 +532,8 @@ public class MainWindow : Gtk.ApplicationWindow, Geary.BaseInterface {
);
this.main_toolbar = new MainToolbar(config);
+ this.main_toolbar.move_folder_menu.folder_selected.connect(on_move_conversation);
+ this.main_toolbar.copy_folder_menu.folder_selected.connect(on_copy_conversation);
this.main_toolbar.bind_property("search-open", this.search_bar, "search-mode-enabled",
BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL);
this.main_toolbar.bind_property("find-open", this.conversation_viewer.conversation_find_bar,
@@ -405,10 +557,15 @@ public class MainWindow : Gtk.ApplicationWindow, Geary.BaseInterface {
// Search bar
this.search_bar_box.pack_start(this.search_bar, false, false, 0);
+
// Folder list
this.folder_list_scrolled.add(this.folder_list);
+ this.folder_list.move_conversation.connect(on_move_conversation);
+ this.folder_list.copy_conversation.connect(on_copy_conversation);
+
// Conversation list
this.conversation_list_scrolled.add(this.conversation_list_view);
+
// Conversation viewer
this.conversations_paned.pack2(this.conversation_viewer, true, true);
@@ -873,4 +1030,140 @@ public class MainWindow : Gtk.ApplicationWindow, Geary.BaseInterface {
update_ui();
}
+ // Action callbacks
+
+ private void on_undo() {
+ }
+
+ private void on_redo() {
+ }
+
+ private void on_close() {
+ close();
+ }
+
+ private void on_conversation_list() {
+ this.conversation_list_view.grab_focus();
+ }
+
+ private void on_find_in_conversation_action() {
+ this.conversation_viewer.enable_find();
+ }
+
+ private void on_search_activated() {
+ show_search_bar();
+ }
+
+ private void on_zoom(SimpleAction action, Variant? parameter) {
+ ConversationListBox? view = this.conversation_viewer.current_list;
+ if (view != null && parameter != null) {
+ string zoom_action = parameter.get_string();
+ if (zoom_action == "in")
+ view.zoom_in();
+ else if (zoom_action == "out")
+ view.zoom_out();
+ else
+ view.zoom_reset();
+ }
+ }
+
+ private void on_reply_to_message() {
+ }
+
+ private void on_reply_all_message() {
+ }
+
+ private void on_forward_message() {
+ }
+
+ private void on_show_copy_menu() {
+ this.main_toolbar.copy_message_button.clicked();
+ }
+
+ private void on_show_move_menu() {
+ this.main_toolbar.move_message_button.clicked();
+ }
+
+ private void on_conversation_up() {
+ this.conversation_list_view.scroll(Gtk.ScrollType.STEP_UP);
+ }
+
+ private void on_conversation_down() {
+ this.conversation_list_view.scroll(Gtk.ScrollType.STEP_DOWN);
+ }
+
+ private void on_show_mark_menu() {
+ bool unread_selected = false;
+ bool read_selected = false;
+ bool starred_selected = false;
+ bool unstarred_selected = false;
+ foreach (Geary.App.Conversation conversation in
+ this.conversation_list_view.get_selected_conversations()) {
+ if (conversation.is_unread())
+ unread_selected = true;
+
+ // Only check the messages that "Mark as Unread" would mark, so we
+ // don't add the menu option and have it not do anything.
+ //
+ // Sort by Date: field to correspond with ConversationViewer ordering
+ Geary.Email? latest = conversation.get_latest_sent_email(
+ Geary.App.Conversation.Location.IN_FOLDER_OUT_OF_FOLDER);
+ if (latest != null && latest.email_flags != null
+ && !latest.email_flags.contains(Geary.EmailFlags.UNREAD))
+ read_selected = true;
+
+ if (conversation.is_flagged()) {
+ starred_selected = true;
+ } else {
+ unstarred_selected = true;
+ }
+ }
+ get_action(ACTION_MARK_AS_READ).set_enabled(unread_selected);
+ get_action(ACTION_MARK_AS_UNREAD).set_enabled(read_selected);
+ get_action(ACTION_MARK_AS_STARRED).set_enabled(unstarred_selected);
+ get_action(ACTION_MARK_AS_UNSTARRED).set_enabled(starred_selected);
+
+ // If we're in Drafts/Outbox, we also shouldn't set a message as SPAM.
+ bool in_spam_folder = current_folder.special_folder_type == Geary.SpecialFolderType.SPAM;
+ get_action(ACTION_TOGGLE_SPAM).set_enabled(!in_spam_folder &&
+ current_folder.special_folder_type != Geary.SpecialFolderType.DRAFTS &&
+ current_folder.special_folder_type != Geary.SpecialFolderType.OUTBOX);
+ }
+
+ private void on_mark_as_read() {
+ }
+
+ private void on_mark_as_unread() {
+ }
+
+ private void on_mark_as_starred() {
+ }
+
+ private void on_mark_as_unstarred() {
+ }
+
+ private void on_mark_as_spam_toggle() {
+ }
+
+ private void on_move_conversation(Geary.Folder destination) {
+ }
+
+ private void on_copy_conversation(Geary.Folder destination) {
+ }
+
+ private void on_archive_conversation() {
+ }
+
+ private void on_trash_conversation() {
+ }
+
+ private void on_delete_conversation() {
+ }
+
+ private void on_empty_spam() {
+ }
+
+ private void on_empty_trash() {
+ }
+
}
diff --git a/src/client/conversation-list/conversation-list-view.vala
b/src/client/conversation-list/conversation-list-view.vala
index 6a1dedf3..4ab74dad 100644
--- a/src/client/conversation-list/conversation-list-view.vala
+++ b/src/client/conversation-list/conversation-list-view.vala
@@ -338,7 +338,7 @@ public class ConversationListView : Gtk.TreeView, Geary.BaseInterface {
"Move conversations to _Trash",
this.selected.size
),
- "win." + Application.Controller.ACTION_ARCHIVE_CONVERSATION
+ "win." + MainWindow.ACTION_ARCHIVE_CONVERSATION
);
} else {
context_menu_model.append(
@@ -348,25 +348,25 @@ public class ConversationListView : Gtk.TreeView, Geary.BaseInterface {
"_Delete conversations",
this.selected.size
),
- "win." + Application.Controller.ACTION_DELETE_CONVERSATION
+ "win." + MainWindow.ACTION_DELETE_CONVERSATION
);
}
if (conversation.is_unread())
- context_menu_model.append(_("Mark as _Read"),
"win."+Application.Controller.ACTION_MARK_AS_READ);
+ context_menu_model.append(_("Mark as _Read"), "win."+MainWindow.ACTION_MARK_AS_READ);
if (conversation.has_any_read_message())
- context_menu_model.append(_("Mark as _Unread"),
"win."+Application.Controller.ACTION_MARK_AS_UNREAD);
+ context_menu_model.append(_("Mark as _Unread"), "win."+MainWindow.ACTION_MARK_AS_UNREAD);
if (conversation.is_flagged())
- context_menu_model.append(_("U_nstar"),
"win."+Application.Controller.ACTION_MARK_AS_UNSTARRED);
+ context_menu_model.append(_("U_nstar"), "win."+MainWindow.ACTION_MARK_AS_UNSTARRED);
else
- context_menu_model.append(_("_Star"), "win."+Application.Controller.ACTION_MARK_AS_STARRED);
+ context_menu_model.append(_("_Star"), "win."+MainWindow.ACTION_MARK_AS_STARRED);
Menu actions_section = new Menu();
- actions_section.append(_("_Reply"), "win."+Application.Controller.ACTION_REPLY_TO_MESSAGE);
- actions_section.append(_("R_eply All"), "win."+Application.Controller.ACTION_REPLY_ALL_MESSAGE);
- actions_section.append(_("_Forward"), "win."+Application.Controller.ACTION_FORWARD_MESSAGE);
+ actions_section.append(_("_Reply"), "win."+MainWindow.ACTION_REPLY_TO_MESSAGE);
+ actions_section.append(_("R_eply All"), "win."+MainWindow.ACTION_REPLY_ALL_MESSAGE);
+ actions_section.append(_("_Forward"), "win."+MainWindow.ACTION_FORWARD_MESSAGE);
context_menu_model.append_section(null, actions_section);
// Use a popover rather than a regular context menu since
@@ -577,4 +577,5 @@ public class ConversationListView : Gtk.TreeView, Geary.BaseInterface {
return Gdk.EVENT_PROPAGATE;
}
+
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]