Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian W. Damus2016-05-24 21:51:43 +0000
committerGerrit Code Review @ Eclipse.org2016-05-27 12:07:35 +0000
commitc3dcb4914637e5ca63d83d16ef9a9342796b0552 (patch)
tree82a45dcab923a035c26627407fc537ce105fac31 /plugins/uml
parent5861a9b5d65ad4f5324be31c0358901e6ee7879b (diff)
downloadorg.eclipse.papyrus-c3dcb4914637e5ca63d83d16ef9a9342796b0552.tar.gz
org.eclipse.papyrus-c3dcb4914637e5ca63d83d16ef9a9342796b0552.tar.xz
org.eclipse.papyrus-c3dcb4914637e5ca63d83d16ef9a9342796b0552.zip
Bug 494478: StereotypeElementListener dispatches events too early during undo/redo
https://bugs.eclipse.org/bugs/show_bug.cgi?id=494478 Restore the post-commit timing of the dispatch of custom notifications for stereotype applications generated by undo and redo of commands. This ensures that, for example, Adapters attached directly to objects are not notified of unapplication of a stereotype during undo before that stereotype is actually unapplied. The pre-commit timing of the original notifications from command execution is preserved because: * they do not have the problem of preceding the actual model changes * pre-commit listeners such as applied-stereotype display edit-policies still need to receive and react to these notifications before commit * post-commit listeners will still receive these also, as before Delaying the notifications to post-commit phase for undo/redo should not break any listeners' timing assumptions because only post-commit listeners could have received them, anyways: undo/redo transactions do not have the pre-commit (triggers) phase. Change-Id: Iaeda2abfbb86d98fbdf0a93787bef25901a7e312
Diffstat (limited to 'plugins/uml')
-rw-r--r--plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/listeners/StereotypeElementListener.java89
1 files changed, 57 insertions, 32 deletions
diff --git a/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/listeners/StereotypeElementListener.java b/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/listeners/StereotypeElementListener.java
index 7505329b864..f08d8f616ae 100644
--- a/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/listeners/StereotypeElementListener.java
+++ b/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/listeners/StereotypeElementListener.java
@@ -9,7 +9,7 @@
* Contributors:
* Gabriel Pascual (ALL4TEC) gabriel.pascual@all4tec.net - Initial API and implementation
* Gabriel Pascual (ALL4TEC) gabriel.pascual@all4tec.fr - Bug 393532
- * Christian W. Damus - bugs 450523, 399859, 492482
+ * Christian W. Damus - bugs 450523, 399859, 492482, 494478
*
*****************************************************************************/
package org.eclipse.papyrus.uml.tools.listeners;
@@ -38,6 +38,7 @@ import org.eclipse.emf.transaction.NotificationFilter;
import org.eclipse.emf.transaction.ResourceSetChangeEvent;
import org.eclipse.emf.transaction.ResourceSetListenerImpl;
import org.eclipse.emf.transaction.RollbackException;
+import org.eclipse.emf.transaction.Transaction;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Extension;
@@ -61,6 +62,12 @@ public class StereotypeElementListener extends ResourceSetListenerImpl {
private final StereotypeExtensionFinder finder;
+ /** Notifications to dispatch and invert at post-commit of undo/redo transactions. */
+ private final List<NotificationChain> undoRedoNotifications = new ArrayList<>();
+
+ /** The transaction option indicating that a transaction performs undo or redo of a command. */
+ private final Transaction.OptionMetadata undoRedoOption = Transaction.OptionMetadata.Registry.INSTANCE.getOptionMetadata(Transaction.OPTION_IS_UNDO_REDO_TRANSACTION);
+
/**
* Instantiates a new stereotype element listener on an editing domain.
*
@@ -83,18 +90,6 @@ public class StereotypeElementListener extends ResourceSetListenerImpl {
this.finder = new StereotypeExtensionFinder(resourceSet);
}
- /**
- * I am a pre-commit listener. Trigger listeners need to be able to react to
- * these events. And they will be captured and automatically distributed again
- * when the transaction commits (if it doesn't roll back).
- *
- * @return {@code true}
- */
- @Override
- public boolean isPrecommitOnly() {
- return true;
- }
-
@Override
public Command transactionAboutToCommit(ResourceSetChangeEvent event) throws RollbackException {
Command result = null;
@@ -109,7 +104,7 @@ public class StereotypeElementListener extends ResourceSetListenerImpl {
handleFilteredNotification(notification, chain);
}
- result = new AbstractCommand("Inject Stereotype Notifications") {
+ result = new AbstractCommand("Inject Stereotype Notifications") { //$NON-NLS-1$
private NotificationChain notifications;
@Override
@@ -125,38 +120,68 @@ public class StereotypeElementListener extends ResourceSetListenerImpl {
@Override
public void undo() {
- dispatchAndInvert();
+ // Schedule dispatch and inversion at post-commit time
+ undoRedoNotifications.add(this.notifications);
}
@Override
public void redo() {
- dispatchAndInvert();
+ // Schedule dispatch and inversion at post-commit time
+ undoRedoNotifications.add(this.notifications);
}
private void dispatchAndInvert() {
- notifications.dispatch();
- this.notifications = invertNotifications(notifications);
+ this.notifications.dispatch();
+ invertNotifications(this.notifications);
}
+ };
+ }
+
+ return result;
+ }
- private NotificationChain invertNotifications(NotificationChain notifications) {
- // The chain is implemented as an EList
- @SuppressWarnings("unchecked")
- EList<Notification> list = (EList<Notification>) notifications;
+ /**
+ * Invert the semantics of a chain of stereotype-application {@code notifications}
+ * in situ. This includes reversing the order in which they are dispatched.
+ *
+ * @param notifications
+ * notifications to invert
+ * @see StereotypeExtensionNotification#invert()
+ */
+ private void invertNotifications(NotificationChain notifications) {
+ // The chain is implemented as an EList
+ @SuppressWarnings("unchecked")
+ EList<Notification> list = (EList<Notification>) notifications;
- // Reverse the order
- ECollections.reverse(list);
+ // Reverse the order
+ ECollections.reverse(list);
- // And flip the type from applied <--> unapplied
- for (Notification next : list) {
- ((StereotypeExtensionNotification) next).invert();
- }
+ // And flip the type from applied <--> unapplied
+ for (Notification next : list) {
+ ((StereotypeExtensionNotification) next).invert();
+ }
+ }
- return notifications;
+ @Override
+ public void resourceSetChanged(ResourceSetChangeEvent event) {
+ if (Boolean.FALSE.equals(undoRedoOption.getValue(event.getTransaction().getOptions()))) {
+ // Not an undo/redo transaction? Purge any notifications that we may have
+ // had from a rolled-back undo or redo
+ undoRedoNotifications.clear();
+ } else if (!undoRedoNotifications.isEmpty()) {
+ // It's an undo/redo transaction. Dispatch the (inverted) notifications
+ // that were deferred by the notification-injector command
+ try {
+ for (NotificationChain next : undoRedoNotifications) {
+ next.dispatch();
+ invertNotifications(next);
}
- };
+ } finally {
+ // Subsequent redo/undo of the injector command will collect
+ // these again
+ undoRedoNotifications.clear();
+ }
}
-
- return result;
}
/**

Back to the top