Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian W. Damus2016-05-05 00:33:21 +0000
committerChristian W. Damus2016-05-05 01:36:51 +0000
commit33f75895239c1f533af289399cf174cca5bd3020 (patch)
tree241471eda2c8ee389aae60010d77135151f9a1b3 /plugins
parent47cb24662d263b1eb3bb7f3de22966d94f3d2f23 (diff)
downloadorg.eclipse.papyrus-33f75895239c1f533af289399cf174cca5bd3020.tar.gz
org.eclipse.papyrus-33f75895239c1f533af289399cf174cca5bd3020.tar.xz
org.eclipse.papyrus-33f75895239c1f533af289399cf174cca5bd3020.zip
Bug 492690: [Editor] Welcome page throws when diagrams loaded off the UI thread
https://bugs.eclipse.org/bugs/show_bug.cgi?id=492690 Ensure that the reactions to notifications received by the adapters used by the NotationObservable are processed on the UI thread so that they may safely update the observable in the context of its home realm. Change-Id: I7a6cc13d1ac645618ed166bd7d948461879b9adb
Diffstat (limited to 'plugins')
-rw-r--r--plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.welcome/src/org/eclipse/papyrus/infra/gmfdiag/welcome/internal/modelelements/NotationObservable.java20
-rw-r--r--plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.welcome/src/org/eclipse/papyrus/infra/gmfdiag/welcome/internal/util/UISafeAdapter.java85
2 files changed, 101 insertions, 4 deletions
diff --git a/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.welcome/src/org/eclipse/papyrus/infra/gmfdiag/welcome/internal/modelelements/NotationObservable.java b/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.welcome/src/org/eclipse/papyrus/infra/gmfdiag/welcome/internal/modelelements/NotationObservable.java
index d53aa6be8db..e95d7503d5c 100644
--- a/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.welcome/src/org/eclipse/papyrus/infra/gmfdiag/welcome/internal/modelelements/NotationObservable.java
+++ b/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.welcome/src/org/eclipse/papyrus/infra/gmfdiag/welcome/internal/modelelements/NotationObservable.java
@@ -23,11 +23,13 @@ import org.eclipse.emf.common.notify.impl.AdapterImpl;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.gmf.runtime.notation.Diagram;
import org.eclipse.gmf.runtime.notation.NotationPackage;
+import org.eclipse.papyrus.infra.gmfdiag.welcome.internal.util.UISafeAdapter;
import org.eclipse.papyrus.infra.gmfdiag.welcome.internal.util.ViewUtil;
import org.eclipse.papyrus.infra.nattable.model.nattable.NattablePackage;
import org.eclipse.papyrus.infra.nattable.model.nattable.Table;
import org.eclipse.papyrus.infra.tools.databinding.ReferenceCountedObservable;
import org.eclipse.papyrus.infra.tools.databinding.TouchableValue;
+import org.eclipse.swt.widgets.Display;
/**
* Encapsulation of a {@link Diagram}, {@link Table}, or other notation view that presents the
@@ -101,6 +103,16 @@ public class NotationObservable extends ReferenceCountedObservable.Abstract {
return false;
}
+ /**
+ * Handles a change in the context of a notation view.
+ *
+ * @precondition the current thread is the UI thread
+ *
+ * @param oldContext
+ * the old context (may be {@code null})
+ * @param newContext
+ * the new context (may be {@code null})
+ */
void handleContextChanged(EObject oldContext, EObject newContext) {
ContextAdapter adapter = this.contextAdapter;
@@ -126,7 +138,7 @@ public class NotationObservable extends ReferenceCountedObservable.Abstract {
// Nested types
//
- private class ViewAdapter extends AdapterImpl {
+ private class ViewAdapter extends UISafeAdapter {
ViewAdapter(EObject view) {
super();
@@ -150,7 +162,7 @@ public class NotationObservable extends ReferenceCountedObservable.Abstract {
}
@Override
- public void notifyChanged(Notification msg) {
+ protected void doNotifyChanged(Notification msg) {
if (!msg.isTouch()) {
Object notifier = msg.getNotifier();
@@ -179,7 +191,7 @@ public class NotationObservable extends ReferenceCountedObservable.Abstract {
}
}
- private class ContextAdapter extends AdapterImpl {
+ private class ContextAdapter extends UISafeAdapter {
ContextAdapter(EObject context) {
super();
@@ -203,7 +215,7 @@ public class NotationObservable extends ReferenceCountedObservable.Abstract {
}
@Override
- public void notifyChanged(Notification msg) {
+ protected void doNotifyChanged(Notification msg) {
if (!msg.isTouch()) {
// Can't interpret the change, so just assume that the label needs to change
contextValue.touch();
diff --git a/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.welcome/src/org/eclipse/papyrus/infra/gmfdiag/welcome/internal/util/UISafeAdapter.java b/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.welcome/src/org/eclipse/papyrus/infra/gmfdiag/welcome/internal/util/UISafeAdapter.java
new file mode 100644
index 00000000000..af51c296be8
--- /dev/null
+++ b/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.welcome/src/org/eclipse/papyrus/infra/gmfdiag/welcome/internal/util/UISafeAdapter.java
@@ -0,0 +1,85 @@
+/*****************************************************************************
+ * Copyright (c) 2016 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.infra.gmfdiag.welcome.internal.util;
+
+import org.eclipse.emf.common.notify.Notification;
+import org.eclipse.emf.common.notify.impl.AdapterImpl;
+import org.eclipse.emf.transaction.RunnableWithResult;
+import org.eclipse.emf.transaction.Transaction;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.emf.transaction.impl.InternalTransactionalEditingDomain;
+import org.eclipse.emf.transaction.util.TransactionUtil;
+import org.eclipse.swt.widgets.Display;;
+
+/**
+ * An adapter that ensures reaction to a notification is performed on the UI thread.
+ * To avoid unnecessary synchronization with the UI thread, this adapter never
+ * reacts to {@linkplain Notification#isTouch() touch} notifications.
+ */
+public class UISafeAdapter extends AdapterImpl {
+
+ @Override
+ public void notifyChanged(Notification msg) {
+ if (!msg.isTouch()) {
+ // I have to run on the UI thread in order to operate on observables
+ if (Display.getCurrent() != null) {
+ doNotifyChanged(msg);
+ } else {
+ syncExec(Display.getDefault(),
+ msg.getNotifier(),
+ () -> doNotifyChanged(msg));
+ }
+ }
+ }
+
+ /**
+ * Overridden by subclasses to react to a notification.
+ *
+ * @param msg
+ * a notification
+ */
+ protected void doNotifyChanged(Notification msg) {
+ // Pass
+ }
+
+ private void syncExec(Display display, Object notifier, Runnable action) {
+ // If we're in an editing domain and there is an active transaction,
+ // then we must be careful about how we synchronize with another thread,
+ // in case someone in the call chain attempts further model access
+ Transaction activeTransaction = null;
+ TransactionalEditingDomain domain = TransactionUtil.getEditingDomain(notifier);
+ if (domain instanceof InternalTransactionalEditingDomain) {
+ activeTransaction = ((InternalTransactionalEditingDomain) domain).getActiveTransaction();
+ }
+
+ if (activeTransaction != null) {
+ try {
+ // Replace the action with a privileged wrapper
+ Runnable _action = action;
+ action = TransactionUtil.createPrivilegedRunnable(domain, new RunnableWithResult.Impl<Void>() {
+ @Override
+ public void run() {
+ _action.run();
+ }
+ });
+ } catch (InterruptedException e) {
+ // This can't actually happen (appears to be an error in the
+ // specification of the API) so just leave the action as is
+ }
+ }
+
+ // Go execute on the display thread
+ display.syncExec(action);
+ }
+}

Back to the top