[geary/mjog/account-command-stacks: 69/77] Prevent the same application action re-executed multiple times
- From: Michael Gratton <mjog src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [geary/mjog/account-command-stacks: 69/77] Prevent the same application action re-executed multiple times
- Date: Tue, 5 Nov 2019 00:38:53 +0000 (UTC)
commit d733027a817d062f6dd29e7bdcd3242f36cfbee8
Author: Michael Gratton <mike vee net>
Date: Thu Oct 31 16:13:37 2019 +1100
Prevent the same application action re-executed multiple times
Before Application.Controller executes an action, ensure it's not the
same action as was execued just before. This stops e.g. issues if
someone holds down Delete.
Fixes #578
src/client/application/application-command.vala | 11 +++-
src/client/application/application-controller.vala | 76 ++++++++++++++++++++++
2 files changed, 84 insertions(+), 3 deletions(-)
---
diff --git a/src/client/application/application-command.vala b/src/client/application/application-command.vala
index a348d584..95f63991 100644
--- a/src/client/application/application-command.vala
+++ b/src/client/application/application-command.vala
@@ -145,6 +145,11 @@ public abstract class Application.Command : GLib.Object {
yield execute(cancellable);
}
+ /** Determines if this command is equal to another. */
+ public virtual bool equal_to(Command other) {
+ return (this == other);
+ }
+
/** Returns a string representation of the command for debugging. */
public virtual string to_string() {
return get_type().name();
@@ -366,7 +371,7 @@ public class Application.CommandStack : GLib.Object {
* This calls {@link Command.execute} and if no error is thrown,
* pushes the command onto the undo stack.
*/
- public async void execute(Command target, GLib.Cancellable? cancellable)
+ public virtual async void execute(Command target, GLib.Cancellable? cancellable)
throws GLib.Error {
debug("Executing: %s", target.to_string());
yield target.execute(cancellable);
@@ -389,7 +394,7 @@ public class Application.CommandStack : GLib.Object {
* stack. If an error is thrown, the command is discarded and the
* redo stack is emptied.
*/
- public async void undo(GLib.Cancellable? cancellable)
+ public virtual async void undo(GLib.Cancellable? cancellable)
throws GLib.Error {
if (!this.undo_stack.is_empty) {
Command target = this.undo_stack.poll_head();
@@ -423,7 +428,7 @@ public class Application.CommandStack : GLib.Object {
* stack. If an error is thrown, the command is discarded and the
* redo stack is emptied.
*/
- public async void redo(GLib.Cancellable? cancellable)
+ public virtual async void redo(GLib.Cancellable? cancellable)
throws GLib.Error {
if (!this.redo_stack.is_empty) {
Command target = this.redo_stack.poll_head();
diff --git a/src/client/application/application-controller.vala
b/src/client/application/application-controller.vala
index 414ab5b6..6fcf7bbb 100644
--- a/src/client/application/application-controller.vala
+++ b/src/client/application/application-controller.vala
@@ -2106,6 +2106,35 @@ public class Application.Controller : Geary.BaseObject {
internal class Application.ControllerCommandStack : CommandStack {
+ private EmailCommand? last_executed = null;
+
+
+ /** {@inheritDoc} */
+ public override async void execute(Command target,
+ GLib.Cancellable? cancellable)
+ throws GLib.Error {
+ // Guard against things like Delete being held down by only
+ // executing a command if it is different to the last one.
+ if (this.last_executed == null || !this.last_executed.equal_to(target)) {
+ this.last_executed = target as EmailCommand;
+ yield base.execute(target, cancellable);
+ }
+ }
+
+ /** {@inheritDoc} */
+ public override async void undo(GLib.Cancellable? cancellable)
+ throws GLib.Error {
+ this.last_executed = null;
+ yield base.undo(cancellable);
+ }
+
+ /** {@inheritDoc} */
+ public override async void redo(GLib.Cancellable? cancellable)
+ throws GLib.Error {
+ this.last_executed = null;
+ yield base.redo(cancellable);
+ }
+
/**
* Notifies the stack that one or more folders were removed.
*
@@ -2213,6 +2242,29 @@ public abstract class Application.EmailCommand : Command {
}
+ public override bool equal_to(Command other) {
+ if (this == other) {
+ return true;
+ }
+
+ if (this.get_type() != other.get_type()) {
+ return false;
+ }
+
+ EmailCommand? other_email = other as EmailCommand;
+ if (other_email == null) {
+ return false;
+ }
+
+ return (
+ this.location == other_email.location &&
+ this.conversations.size == other_email.conversations.size &&
+ this.email.size == other_email.email.size &&
+ this.conversations.contains_all(other_email.conversations) &&
+ this.email.contains_all(other_email.email)
+ );
+ }
+
/**
* Determines the command's response when a folder is removed.
*
@@ -2330,6 +2382,24 @@ private class Application.MarkEmailCommand : TrivialCommand, EmailCommand {
);
}
+ public override bool equal_to(Command other) {
+ if (!base.equal_to(other)) {
+ return false;
+ }
+
+ MarkEmailCommand other_mark = (MarkEmailCommand) other;
+ return (
+ ((this.to_add == other_mark.to_add) ||
+ (this.to_add != null &&
+ other_mark.to_add != null &&
+ this.to_add.equal_to(other_mark.to_add))) &&
+ ((this.to_remove == other_mark.to_remove) ||
+ (this.to_remove != null &&
+ other_mark.to_remove != null &&
+ this.to_remove.equal_to(other_mark.to_remove)))
+ );
+ }
+
}
@@ -2732,4 +2802,10 @@ private class Application.EmptyFolderCommand : Command {
);
}
+ /** Determines if this command is equal to another. */
+ public override bool equal_to(Command other) {
+ EmptyFolderCommand? other_type = other as EmptyFolderCommand;
+ return (other_type != null && this.target == other_type.target);
+ }
+
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]