Implement an application-level command stack
This will provide the basis for handling undo/redo in the main window.
This commit is contained in:
parent
8e9f00295e
commit
88eb8f5040
2 changed files with 76 additions and 2 deletions
|
|
@ -127,6 +127,8 @@ public class Application.Controller : Geary.BaseObject {
|
|||
// Null if no folder ever selected
|
||||
private Geary.Account? current_account = null;
|
||||
|
||||
private Application.CommandStack commands { get; protected set; }
|
||||
|
||||
private Cancellable cancellable_folder = new Cancellable();
|
||||
private Cancellable cancellable_search = new Cancellable();
|
||||
private Cancellable cancellable_open_account = new Cancellable();
|
||||
|
|
@ -207,8 +209,10 @@ public class Application.Controller : Geary.BaseObject {
|
|||
);
|
||||
this.plugin_manager.load();
|
||||
|
||||
this.commands = new CommandStack();
|
||||
|
||||
// Create the main window (must be done after creating actions.)
|
||||
main_window = new MainWindow(this.application);
|
||||
main_window = new MainWindow(this.application, this.commands);
|
||||
main_window.retry_service_problem.connect(on_retry_service_problem);
|
||||
main_window.notify["has-toplevel-focus"].connect(on_has_toplevel_focus);
|
||||
|
||||
|
|
@ -292,6 +296,36 @@ public class Application.Controller : Geary.BaseObject {
|
|||
this.expunge_accounts.begin();
|
||||
}
|
||||
|
||||
/** Un-does the last executed application command, if any. */
|
||||
public async void undo() {
|
||||
this.commands.undo.begin(
|
||||
this.open_cancellable,
|
||||
(obj, res) => {
|
||||
try {
|
||||
this.commands.undo.end(res);
|
||||
} catch (GLib.Error err) {
|
||||
// XXX extract account info somehow
|
||||
report_problem(new Geary.ProblemReport(err));
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/** Re-does the last undone application command, if any. */
|
||||
public async void redo() {
|
||||
this.commands.redo.begin(
|
||||
this.open_cancellable,
|
||||
(obj, res) => {
|
||||
try {
|
||||
this.commands.redo.end(res);
|
||||
} catch (GLib.Error err) {
|
||||
// XXX extract account info somehow
|
||||
report_problem(new Geary.ProblemReport(err));
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/** Closes all accounts and windows, releasing held resources. */
|
||||
public async void close_async() {
|
||||
// Cancel internal processes early so they don't block
|
||||
|
|
|
|||
|
|
@ -205,6 +205,8 @@ public class MainWindow : Gtk.ApplicationWindow, Geary.BaseInterface {
|
|||
private Geary.TimeoutManager update_ui_timeout;
|
||||
private int64 update_ui_last = 0;
|
||||
|
||||
private Application.CommandStack commands { get; protected set; }
|
||||
|
||||
|
||||
[GtkChild]
|
||||
private Gtk.Box main_layout;
|
||||
|
|
@ -250,7 +252,8 @@ public class MainWindow : Gtk.ApplicationWindow, Geary.BaseInterface {
|
|||
public signal void on_shift_key(bool pressed);
|
||||
|
||||
|
||||
public MainWindow(GearyApplication application) {
|
||||
public MainWindow(GearyApplication application,
|
||||
Application.CommandStack commands) {
|
||||
Object(
|
||||
application: application,
|
||||
show_menubar: false
|
||||
|
|
@ -265,6 +268,12 @@ public class MainWindow : Gtk.ApplicationWindow, Geary.BaseInterface {
|
|||
setup_layout(application.config);
|
||||
on_change_orientation();
|
||||
|
||||
this.commands = commands;
|
||||
this.commands.executed.connect(on_command_execute);
|
||||
this.commands.undone.connect(on_command_undo);
|
||||
this.commands.redone.connect(on_command_execute);
|
||||
update_command_actions();
|
||||
|
||||
this.application.engine.account_available.connect(on_account_available);
|
||||
this.application.engine.account_unavailable.connect(on_account_unavailable);
|
||||
|
||||
|
|
@ -674,6 +683,15 @@ public class MainWindow : Gtk.ApplicationWindow, Geary.BaseInterface {
|
|||
update_headerbar();
|
||||
}
|
||||
|
||||
private void update_command_actions() {
|
||||
get_action(GearyApplication.ACTION_UNDO).set_enabled(
|
||||
this.commands.can_undo
|
||||
);
|
||||
get_action(GearyApplication.ACTION_REDO).set_enabled(
|
||||
this.commands.can_redo
|
||||
);
|
||||
}
|
||||
|
||||
private void update_ui() {
|
||||
// Only update if we haven't done so within the last while
|
||||
int64 now = GLib.get_monotonic_time() / (1000 * 1000);
|
||||
|
|
@ -1030,12 +1048,34 @@ public class MainWindow : Gtk.ApplicationWindow, Geary.BaseInterface {
|
|||
update_ui();
|
||||
}
|
||||
|
||||
private void on_command_execute(Application.Command command) {
|
||||
if (command.executed_label != null) {
|
||||
Components.InAppNotification ian =
|
||||
new Components.InAppNotification(command.executed_label);
|
||||
ian.set_button(_("Undo"), "win." + GearyApplication.ACTION_UNDO);
|
||||
add_notification(ian);
|
||||
}
|
||||
update_command_actions();
|
||||
}
|
||||
|
||||
private void on_command_undo(Application.Command command) {
|
||||
if (command.undone_label != null) {
|
||||
Components.InAppNotification ian =
|
||||
new Components.InAppNotification(command.undone_label);
|
||||
ian.set_button(_("Redo"), "win." + GearyApplication.ACTION_REDO);
|
||||
add_notification(ian);
|
||||
}
|
||||
update_command_actions();
|
||||
}
|
||||
|
||||
// Action callbacks
|
||||
|
||||
private void on_undo() {
|
||||
this.application.controller.undo.begin();
|
||||
}
|
||||
|
||||
private void on_redo() {
|
||||
this.application.controller.redo.begin();
|
||||
}
|
||||
|
||||
private void on_close() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue