Browse Source

Issue responsive ui (#1556)

* Make Content Assist Processor cancelable when aborting embedded editor

* reduce UI thread time.

* Allow Document parallel read

* removed sysout

* Use Shared Editing Domain

* replace with non resolving cross reference adapter

* revalidate model when external referenced resource changes

* Update .travis.yml

* Update SharedEditingDomainFactory.java

* Update SharedEditingDomainFactory.java

* added missing final
Andreas Mülder 8 years ago
parent
commit
fb3eacc60d

+ 35 - 0
plugins/org.yakindu.base.xtext.utils.jface/src/org/yakindu/base/xtext/utils/jface/viewers/ParallelReadXtextDocument.java

@@ -0,0 +1,35 @@
+/** 
+ * Copyright (c) 2017 committers of YAKINDU 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:
+ * committers of YAKINDU - initial API and implementation
+ *
+*/
+package org.yakindu.base.xtext.utils.jface.viewers;
+
+import org.eclipse.xtext.ui.editor.model.DocumentTokenSource;
+import org.eclipse.xtext.ui.editor.model.XtextDocument;
+import org.eclipse.xtext.ui.editor.model.edit.ITextEditComposer;
+
+import com.google.inject.Inject;
+
+/**
+ * 
+ * @author andreas muelder - Initial contribution and API
+ * 
+ */
+public class ParallelReadXtextDocument extends XtextDocument {
+
+	@Inject
+	public ParallelReadXtextDocument(DocumentTokenSource tokenSource, ITextEditComposer composer) {
+		super(tokenSource, composer);
+	}
+
+	@Override
+	protected Object getResourceLock() {
+		return new Object();
+	}
+}

+ 26 - 21
plugins/org.yakindu.base.xtext.utils.jface/src/org/yakindu/base/xtext/utils/jface/viewers/StyledTextXtextAdapter.java

@@ -80,10 +80,6 @@ import com.google.inject.Provider;
 @SuppressWarnings("restriction")
 public class StyledTextXtextAdapter {
 
-	/**
-	 * The sourceViewer, that provides additional functions to the styled text
-	 * widget
-	 */
 	protected XtextSourceViewer sourceviewer;
 
 	private ValidationJob validationJob;
@@ -110,6 +106,8 @@ public class StyledTextXtextAdapter {
 
 	private ControlDecoration decoration;
 
+	private SourceViewerDecorationSupport decorationSupport;
+
 	public StyledTextXtextAdapter(Injector injector, IXtextFakeContextResourcesProvider contextFakeResourceProvider) {
 		this.contextFakeResourceProvider = contextFakeResourceProvider;
 		injector.injectMembers(this);
@@ -187,7 +185,7 @@ public class StyledTextXtextAdapter {
 			styledText.addFocusListener(listener);
 			styledText.addDisposeListener(listener);
 		} catch (NullPointerException ex) {
-			//Do nothing, not opened within editor context
+			// Do nothing, not opened within editor context
 		}
 
 	}
@@ -197,8 +195,8 @@ public class StyledTextXtextAdapter {
 		decoration.setShowHover(true);
 		decoration.setShowOnlyOnFocus(true);
 
-		final Image image = ImageDescriptor.createFromFile(XtextStyledTextCellEditor.class,
-				"images/content_assist_cue.gif").createImage();
+		final Image image = ImageDescriptor
+				.createFromFile(XtextStyledTextCellEditor.class, "images/content_assist_cue.gif").createImage();
 		decoration.setImage(image);
 		decoration.setDescriptionText("Content Assist Available (CTRL + Space)");
 		decoration.setMarginWidth(2);
@@ -215,8 +213,9 @@ public class StyledTextXtextAdapter {
 	}
 
 	protected ValidationJob createValidationJob() {
-		return new ValidationJob(validator, document, new AnnotationIssueProcessor(document,
-				sourceviewer.getAnnotationModel(), resolutionProvider), CheckMode.ALL);
+		return new ValidationJob(validator, document,
+				new AnnotationIssueProcessor(document, sourceviewer.getAnnotationModel(), resolutionProvider),
+				CheckMode.FAST_ONLY);
 	}
 
 	protected void createFakeResourceContext(Injector injector) {
@@ -227,9 +226,9 @@ public class StyledTextXtextAdapter {
 		sourceviewer = new XtextSourceViewerEx(styledText, preferenceStoreAccess.getPreferenceStore());
 		sourceviewer.configure(configuration);
 		sourceviewer.setDocument(document, new AnnotationModel());
-		SourceViewerDecorationSupport support = new SourceViewerDecorationSupport(sourceviewer, null,
-				new DefaultMarkerAnnotationAccess(), getSharedColors());
-		configureSourceViewerDecorationSupport(support);
+		decorationSupport = new SourceViewerDecorationSupport(sourceviewer, null, new DefaultMarkerAnnotationAccess(),
+				getSharedColors());
+		configureSourceViewerDecorationSupport(decorationSupport);
 	}
 
 	protected ISharedTextColors getSharedColors() {
@@ -237,9 +236,8 @@ public class StyledTextXtextAdapter {
 	}
 
 	/**
-	 * Creates decoration support for the sourceViewer. code is entirely copied
-	 * from {@link XtextEditor} and its super class
-	 * {@link AbstractDecoratedTextEditor}.
+	 * Creates decoration support for the sourceViewer. code is entirely copied from
+	 * {@link XtextEditor} and its super class {@link AbstractDecoratedTextEditor}.
 	 * 
 	 */
 	protected void configureSourceViewerDecorationSupport(SourceViewerDecorationSupport support) {
@@ -254,7 +252,10 @@ public class StyledTextXtextAdapter {
 				BracketMatchingPreferencesInitializer.COLOR_KEY);
 
 		support.install(preferenceStoreAccess.getPreferenceStore());
+	}
 
+	protected void unconfigureSourceViewerDecorationSupport(SourceViewerDecorationSupport support) {
+		support.uninstall();
 	}
 
 	protected void initXtextDocument(XtextFakeResourceContext context) {
@@ -285,6 +286,10 @@ public class StyledTextXtextAdapter {
 	}
 
 	public void dispose() {
+		document.setOutdated(true);
+		if (decorationSupport != null) {
+			unconfigureSourceViewerDecorationSupport(decorationSupport);
+		}
 		uninstallHighlightingHelper();
 		document.disposeInput();
 	}
@@ -383,12 +388,12 @@ public class StyledTextXtextAdapter {
 		}
 
 		public void widgetDisposed(DisposeEvent e) {
-            if (selectionProviderOnFocusLost != null) {
-                site.setSelectionProvider(selectionProviderOnFocusLost);
-            }
-            ((StyledText) e.getSource()).removeFocusListener(this);
-            ((StyledText) e.getSource()).removeDisposeListener(this);
-        }
+			if (selectionProviderOnFocusLost != null) {
+				site.setSelectionProvider(selectionProviderOnFocusLost);
+			}
+			((StyledText) e.getSource()).removeFocusListener(this);
+			((StyledText) e.getSource()).removeDisposeListener(this);
+		}
 
 	}
 }

+ 3 - 0
plugins/org.yakindu.sct.model.stext.ui/src/org/yakindu/sct/model/stext/ui/STextUiModule.java

@@ -26,12 +26,14 @@ import org.eclipse.xtext.ui.editor.hyperlinking.IHyperlinkHelper;
 import org.eclipse.xtext.ui.editor.model.IResourceForEditorInputFactory;
 import org.eclipse.xtext.ui.editor.model.JavaClassPathResourceForIEditorInputFactory;
 import org.eclipse.xtext.ui.editor.model.ResourceForIEditorInputFactory;
+import org.eclipse.xtext.ui.editor.model.XtextDocument;
 import org.eclipse.xtext.ui.editor.syntaxcoloring.IHighlightingConfiguration;
 import org.eclipse.xtext.ui.resource.IResourceSetProvider;
 import org.eclipse.xtext.ui.resource.SimpleResourceSetProvider;
 import org.eclipse.xtext.ui.resource.XtextResourceSetProvider;
 import org.eclipse.xtext.ui.shared.Access;
 import org.yakindu.base.utils.jface.help.CrossRefObjectTextHover;
+import org.yakindu.base.xtext.utils.jface.viewers.ParallelReadXtextDocument;
 import org.yakindu.sct.model.stext.ui.contentassist.AsyncContentAssistContextFactory;
 import org.yakindu.sct.model.stext.ui.contentassist.AsyncXtextContentAssistProcessor;
 import org.yakindu.sct.model.stext.ui.contentassist.STextStatefulFactory;
@@ -81,6 +83,7 @@ public class STextUiModule extends org.yakindu.sct.model.stext.ui.AbstractSTextU
 	public void configure(Binder binder) {
 		super.configure(binder);
 		binder.bind(String.class).annotatedWith(Names.named("stylesheet")).toInstance("/StextHoverStyleSheet.css");
+		binder.bind(XtextDocument.class).to(ParallelReadXtextDocument.class);
 	}
 
 	public com.google.inject.Provider<org.eclipse.xtext.resource.containers.IAllContainersState> provideIAllContainersState() {

+ 39 - 2
plugins/org.yakindu.sct.model.stext.ui/src/org/yakindu/sct/model/stext/ui/contentassist/AsyncXtextContentAssistProcessor.java

@@ -14,9 +14,12 @@ import java.util.Arrays;
 
 import org.eclipse.jface.text.ITextViewer;
 import org.eclipse.jface.text.contentassist.ICompletionProposal;
+import org.eclipse.xtext.resource.XtextResource;
 import org.eclipse.xtext.ui.editor.contentassist.CompletionProposalComputer;
 import org.eclipse.xtext.ui.editor.contentassist.XtextContentAssistProcessor;
 import org.eclipse.xtext.ui.editor.model.IXtextDocument;
+import org.eclipse.xtext.util.CancelIndicator;
+import org.eclipse.xtext.util.concurrent.CancelableUnitOfWork;
 
 /**
  * 
@@ -30,11 +33,45 @@ public class AsyncXtextContentAssistProcessor extends XtextContentAssistProcesso
 		if (getContentProposalProvider() == null)
 			return null;
 		IXtextDocument document = (IXtextDocument) viewer.getDocument();
-		CompletionProposalComputer computer = createCompletionProposalComputer(viewer, offset);
-		ICompletionProposal[] result = document.readOnly(computer);
+		final CancelableCompletionProposalComputer computer = createCompletionProposalComputer(viewer, offset);
+		ICompletionProposal[] result = document
+				.readOnly(new CancelableUnitOfWork<ICompletionProposal[], XtextResource>() {
+					@Override
+					public ICompletionProposal[] exec(XtextResource state, CancelIndicator cancelIndicator)
+							throws Exception {
+						computer.setCancelIndicator(cancelIndicator);
+						return computer.exec(state);
+					}
+				});
 		Arrays.sort(result, getCompletionProposalComparator());
 		result = getCompletionProposalPostProcessor().postProcess(result);
 		return result;
 	}
 
+	@Override
+	protected CancelableCompletionProposalComputer createCompletionProposalComputer(ITextViewer viewer, int offset) {
+		return new CancelableCompletionProposalComputer(this, viewer, offset);
+	}
+
+	public static class CancelableCompletionProposalComputer extends CompletionProposalComputer {
+
+		private CancelIndicator cancelIndicator;
+
+		public CancelableCompletionProposalComputer(State state, ITextViewer viewer, int offset) {
+			super(state, viewer, offset);
+		}
+
+		public void setCancelIndicator(CancelIndicator indicator) {
+			this.cancelIndicator = indicator;
+		}
+
+		@Override 
+		public boolean canAcceptMoreProposals() {
+			if (cancelIndicator == null) {
+				return super.canAcceptMoreProposals();
+			}
+			return !cancelIndicator.isCanceled();
+		}
+
+	}
 }

+ 16 - 27
plugins/org.yakindu.sct.model.stext.ui/src/org/yakindu/sct/model/stext/ui/contentassist/STextStatefulFactory.java

@@ -10,21 +10,18 @@
 */
 package org.yakindu.sct.model.stext.ui.contentassist;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
+import java.util.Collections;
 
 import org.eclipse.emf.ecore.EObject;
-import org.eclipse.jface.text.BadLocationException;
-import org.eclipse.jface.text.ITextViewer;
 import org.eclipse.swt.widgets.Display;
 import org.eclipse.xtext.nodemodel.INode;
 import org.eclipse.xtext.parser.IParseResult;
-import org.eclipse.xtext.resource.XtextResource;
 import org.eclipse.xtext.ui.editor.contentassist.ContentAssistContext;
 import org.eclipse.xtext.ui.editor.contentassist.ContentAssistContext.Builder;
 import org.eclipse.xtext.ui.editor.contentassist.antlr.ParserBasedContentAssistContextFactory.StatefulFactory;
 
+import com.google.common.collect.Lists;
+
 /**
  * This class is used to always set a current model when the context for the
  * proposal provider is created. It is used to propose Events as Transition
@@ -34,27 +31,6 @@ import org.eclipse.xtext.ui.editor.contentassist.antlr.ParserBasedContentAssistC
 public class STextStatefulFactory extends StatefulFactory {
 	private IParseResult parseResult;
 
-	@Override
-	public ContentAssistContext[] create(final ITextViewer viewer, final int offset, final XtextResource resource)
-			throws BadLocationException {
-		this.parseResult = resource.getParseResult();
-		if (Display.getCurrent() == null) {
-			final List<ContentAssistContext> result = new ArrayList<>();
-			Display.getDefault().syncExec(new Runnable() {
-				@Override
-				public void run() {
-					try {
-						result.addAll(Arrays.asList(STextStatefulFactory.super.create(viewer, offset, resource)));
-					} catch (BadLocationException e) {
-						e.printStackTrace();
-					}
-				}
-			});
-			return result.toArray(new ContentAssistContext[] {});
-		}
-		return super.create(viewer, offset, resource);
-	}
-
 	@Override
 	public Builder doCreateContext(INode lastCompleteNode, EObject currentModel, EObject previousModel,
 			INode currentNode, String prefix) {
@@ -64,4 +40,17 @@ public class STextStatefulFactory extends StatefulFactory {
 		Builder result = super.doCreateContext(lastCompleteNode, currentModel, previousModel, currentNode, prefix);
 		return result;
 	}
+
+	protected void initializeFromViewerAndResource(final int offset) {
+		if (Display.getCurrent() == null) {
+			Display.getDefault().syncExec(new Runnable() {
+				@Override
+				public void run() {
+					initializeAndAdjustCompletionOffset(offset);
+					initializeNodeAndModelData();
+					contextBuilders = Collections.synchronizedList(Lists.<ContentAssistContext.Builder>newArrayList());
+				}
+			});
+		}
+	}
 }

+ 3 - 71
plugins/org.yakindu.sct.model.stext/src/org/yakindu/sct/model/stext/scoping/URI2ResourceDescriptionCache.java

@@ -10,21 +10,14 @@
  */
 package org.yakindu.sct.model.stext.scoping;
 
-import java.util.concurrent.ExecutionException;
-
 import org.eclipse.emf.common.util.URI;
 import org.eclipse.emf.ecore.resource.Resource;
 import org.eclipse.emf.ecore.resource.ResourceSet;
 import org.eclipse.emf.transaction.TransactionalEditingDomain;
-import org.eclipse.emf.workspace.util.WorkspaceSynchronizer;
-import org.eclipse.emf.workspace.util.WorkspaceSynchronizer.Delegate;
 import org.eclipse.xtext.resource.IResourceDescription;
 import org.eclipse.xtext.resource.IResourceDescription.Manager;
 import org.eclipse.xtext.resource.IResourceServiceProvider;
 
-import com.google.common.cache.CacheBuilder;
-import com.google.common.cache.CacheLoader;
-import com.google.common.cache.LoadingCache;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 
@@ -34,52 +27,21 @@ import com.google.inject.Singleton;
  * 
  */
 @Singleton
-public class URI2ResourceDescriptionCache implements Delegate {
+public class URI2ResourceDescriptionCache {
 
-	private static final String DOMAIN_ID = "ResourceCache";
+	private static final String DOMAIN_ID = "org.yakindu.sct.domain";
 
 	@Inject
 	private IResourceServiceProvider.Registry serviceProviderRegistry;
 
-	private LoadingCache<String, IResourceDescription> cache;
-
-	private WorkspaceSynchronizer workspaceSynchronizer;
-
-	public URI2ResourceDescriptionCache() {
-		cache = CacheBuilder.newBuilder().build(new CacheLoader<String, IResourceDescription>() {
-			@Override
-			public IResourceDescription load(String key) throws Exception {
-				return getInternal(URI.createURI(key));
-			}
-		});
-		TransactionalEditingDomain editingDomain = getEditingDomain();
-		workspaceSynchronizer = new WorkspaceSynchronizer(editingDomain, this);
-	}
-
 	protected TransactionalEditingDomain getEditingDomain() {
 		TransactionalEditingDomain editingDomain = TransactionalEditingDomain.Registry.INSTANCE
 				.getEditingDomain(DOMAIN_ID);
-		if (editingDomain == null) {
-			editingDomain = TransactionalEditingDomain.Factory.INSTANCE.createEditingDomain();
-			editingDomain.setID(DOMAIN_ID);
-			TransactionalEditingDomain.Registry.INSTANCE.add(DOMAIN_ID, editingDomain);
-		}
 		return editingDomain;
 	}
 
 	public IResourceDescription get(URI uri) {
-		try {
-			IResourceDescription descrpition = cache.get(uri.toString());
-			return descrpition;
-		} catch (ExecutionException e) {
-			e.printStackTrace();
-		}
-		return null;
-
-	}
-
-	protected IResourceDescription getInternal(URI uri) {
-		ResourceSet set = getResourceSet();
+		ResourceSet set = getEditingDomain().getResourceSet();
 		Resource resource = set.getResource(uri, true);
 		if (resource != null) {
 			IResourceServiceProvider serviceProvider = serviceProviderRegistry.getResourceServiceProvider(uri);
@@ -93,34 +55,4 @@ public class URI2ResourceDescriptionCache implements Delegate {
 		}
 		return null;
 	}
-
-	protected ResourceSet getResourceSet() {
-		return getEditingDomain().getResourceSet();
-	}
-
-	@Override
-	public boolean handleResourceDeleted(Resource resource) {
-		cache.invalidate(resource.getURI().toString());
-		return true;
-	}
-
-	@Override
-	public boolean handleResourceMoved(Resource resource, URI newURI) {
-		cache.invalidate(resource.getURI().toString());
-		return true;
-	}
-
-	@Override
-	public boolean handleResourceChanged(Resource resource) {
-		cache.invalidate(resource.getURI().toString());
-		return true;
-	}
-
-	@Override
-	public void dispose() {
-		if (workspaceSynchronizer != null)
-			workspaceSynchronizer.dispose();
-		cache.invalidateAll();
-	}
-
 }

+ 8 - 0
plugins/org.yakindu.sct.ui.editor/plugin.xml

@@ -866,5 +866,13 @@
       </factory>
    </extension>
   <!-- Added default templates -->
+  
+    <!-- Shared Editing Domain-->
+     <extension
+         point="org.eclipse.emf.transaction.editingDomains">
+      <editingDomain
+            factory="org.yakindu.sct.ui.editor.partitioning.SharedEditingDomainFactory"
+            id="org.yakindu.sct.domain"/>
+   </extension>
    
 </plugin>

+ 5 - 46
plugins/org.yakindu.sct.ui.editor/src/org/yakindu/sct/ui/editor/partitioning/DiagramPartitioningUtil.java

@@ -10,7 +10,6 @@
  */
 package org.yakindu.sct.ui.editor.partitioning;
 
-import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -20,13 +19,11 @@ import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.runtime.Assert;
 import org.eclipse.emf.common.util.TreeIterator;
-import org.eclipse.emf.common.util.URI;
 import org.eclipse.emf.ecore.EObject;
 import org.eclipse.emf.ecore.resource.Resource;
 import org.eclipse.emf.ecore.util.EcoreUtil;
 import org.eclipse.emf.transaction.TransactionalEditingDomain;
 import org.eclipse.emf.workspace.util.WorkspaceSynchronizer;
-import org.eclipse.gmf.runtime.diagram.core.DiagramEditingDomainFactory;
 import org.eclipse.gmf.runtime.diagram.ui.parts.IDiagramEditorInput;
 import org.eclipse.gmf.runtime.notation.BooleanValueStyle;
 import org.eclipse.gmf.runtime.notation.Diagram;
@@ -45,7 +42,6 @@ import org.eclipse.ui.part.FileEditorInput;
 import org.yakindu.sct.model.sgraph.CompositeElement;
 import org.yakindu.sct.model.sgraph.State;
 import org.yakindu.sct.model.sgraph.Statechart;
-import org.yakindu.sct.model.sgraph.resource.AbstractSCTResource;
 import org.yakindu.sct.ui.editor.editor.StatechartDiagramEditor;
 import org.yakindu.sct.ui.editor.utils.GMFNotationUtil;
 
@@ -59,7 +55,7 @@ public class DiagramPartitioningUtil {
 	/** GMFs notation {@link Style} id **/
 	public static final String INLINE_STYLE = "isInline";
 
-	private static final String DOMAIN_ID = "StatechartDomain";
+	private static final String DOMAIN_ID = "org.yakindu.sct.domain";
 
 	private DiagramPartitioningUtil() {
 	}
@@ -84,50 +80,14 @@ public class DiagramPartitioningUtil {
 	}
 
 	/**
-	 * Returns the Shared Editing Domain that is used for all Editors acting on
-	 * the same {@link IResource}
+	 * Returns the Shared Editing Domain that is used for all Editors acting on the
+	 * same {@link IResource}
 	 * 
 	 * @return the {@link TransactionalEditingDomain}
 	 */
 	public static synchronized TransactionalEditingDomain getSharedDomain() {
-		TransactionalEditingDomain editingDomain = TransactionalEditingDomain.Registry.INSTANCE
+		return TransactionalEditingDomain.Registry.INSTANCE
 				.getEditingDomain(DOMAIN_ID);
-		if (editingDomain == null) {
-			editingDomain = DiagramEditingDomainFactory.getInstance().createEditingDomain();
-			editingDomain.setID(DOMAIN_ID);
-			TransactionalEditingDomain.Registry.INSTANCE.add(DOMAIN_ID, editingDomain);
-
-			new WorkspaceSynchronizer(editingDomain, new WorkspaceSynchronizer.Delegate() {
-				public boolean handleResourceDeleted(Resource resource) {
-					resource.unload();
-					return true;
-				}
-				public boolean handleResourceMoved(Resource resource, URI newURI) {
-					resource.unload();
-					return true;
-				}
-				public boolean handleResourceChanged(Resource resource) {
-					if (resource instanceof AbstractSCTResource) {
-						// do not unload GMF resources as it might be the one
-						// underlying the currently opened editor
-						return true;
-					}
-					resource.unload();
-					try {
-						resource.load(resource.getResourceSet().getLoadOptions());
-					} catch (IOException e) {
-						e.printStackTrace();
-					}
-
-					return true;
-				}
-
-				public void dispose() {
-					// nothing to dispose (especially as I am shared)
-				}
-			});
-		}
-		return editingDomain;
 	}
 
 	/**
@@ -203,8 +163,7 @@ public class DiagramPartitioningUtil {
 	}
 
 	/**
-	 * Forces the user to close all opened editors for subdiagrams that are
-	 * inlined.
+	 * Forces the user to close all opened editors for subdiagrams that are inlined.
 	 * 
 	 * @return true if all editors were closed, false otherwise
 	 */

+ 111 - 0
plugins/org.yakindu.sct.ui.editor/src/org/yakindu/sct/ui/editor/partitioning/SharedEditingDomainFactory.java

@@ -0,0 +1,111 @@
+/** 
+ * Copyright (c) 2017 committers of YAKINDU 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:
+ * committers of YAKINDU - initial API and implementation
+ *
+*/
+package org.yakindu.sct.ui.editor.partitioning;
+
+import java.io.IOException;
+
+import org.eclipse.emf.common.notify.Adapter;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.emf.workspace.util.WorkspaceSynchronizer;
+import org.eclipse.gmf.runtime.diagram.core.DiagramEditingDomainFactory;
+import org.eclipse.gmf.runtime.emf.core.util.CrossReferenceAdapter;
+import org.yakindu.sct.model.sgraph.resource.AbstractSCTResource;
+
+/**
+ * 
+ * @author andreas muelder - Initial contribution and API
+ * 
+ */
+public class SharedEditingDomainFactory extends DiagramEditingDomainFactory
+		implements TransactionalEditingDomain.Factory {
+
+	public static final String DOMAIN_ID = "org.yakindu.sct.domain";
+
+	@Override
+	public TransactionalEditingDomain createEditingDomain() {
+		TransactionalEditingDomain domain = super.createEditingDomain();
+		setup(domain);
+		return domain;
+	}
+
+	@Override
+	public TransactionalEditingDomain createEditingDomain(ResourceSet rset) {
+		TransactionalEditingDomain domain = super.createEditingDomain(rset);
+		setup(domain);
+		return domain;
+	}
+
+	@Override
+	public TransactionalEditingDomain getEditingDomain(ResourceSet rset) {
+		TransactionalEditingDomain domain = super.createEditingDomain(rset);
+		setup(domain);
+		return domain;
+	}
+
+	protected void setup(TransactionalEditingDomain editingDomain) {
+		editingDomain.setID(DOMAIN_ID);
+		replaceCrossReferenceAdapterWithNonResolvingAdapter(editingDomain);
+		new WorkspaceSynchronizer(editingDomain, new WorkspaceSynchronizer.Delegate() {
+			public boolean handleResourceDeleted(Resource resource) {
+				resource.unload();
+				return true;
+			}
+
+			public boolean handleResourceMoved(Resource resource, URI newURI) {
+				resource.unload();
+				return true;
+			}
+
+			public boolean handleResourceChanged(Resource resource) {
+				if (resource instanceof AbstractSCTResource) {
+					// do not unload GMF resources as it might be the one
+					// underlying the currently opened editor
+					return true;
+				}
+				resource.unload();
+				try {
+					resource.load(resource.getResourceSet().getLoadOptions());
+				} catch (IOException e) {
+					e.printStackTrace();
+				}
+				return true;
+			}
+
+			public void dispose() {
+				// nothing to dispose (especially as I am shared)
+			}
+		});
+	}
+
+	protected void replaceCrossReferenceAdapterWithNonResolvingAdapter(final TransactionalEditingDomain domain) {
+		final CrossReferenceAdapter adapter = getCrossReferenceAdapter(domain);
+		if (null != adapter) {
+			adapter.unsetTarget(domain.getResourceSet());
+
+			domain.getResourceSet().eAdapters().remove(adapter);
+			domain.getResourceSet().eAdapters().add(new CrossReferenceAdapter(false));
+		}
+	}
+
+	protected CrossReferenceAdapter getCrossReferenceAdapter(final TransactionalEditingDomain domain) {
+		final EList<Adapter> eAdapters = domain.getResourceSet().eAdapters();
+		for (final Adapter adapter : eAdapters) {
+			if (adapter instanceof CrossReferenceAdapter) {
+				return (CrossReferenceAdapter) adapter;
+			}
+		}
+		return null;
+	}
+}

+ 18 - 10
plugins/org.yakindu.sct.ui.editor/src/org/yakindu/sct/ui/editor/validation/LiveValidationListener.java

@@ -34,6 +34,8 @@ public class LiveValidationListener extends ResourceSetListenerImpl {
 	@Inject
 	private ValidationJob validationJob;
 
+	private Resource resource;
+
 	@Override
 	public void resourceSetChanged(ResourceSetChangeEvent event) {
 		for (Notification notification : event.getNotifications()) {
@@ -42,22 +44,27 @@ public class LiveValidationListener extends ResourceSetListenerImpl {
 					&& notification.getEventType() != Notification.RESOLVE) {
 				EObject eObject = (EObject) notification.getNotifier();
 				if (eObject.eClass().getEPackage() == SGraphPackage.eINSTANCE) {
-					validationJob.cancel();
-					if (liveValidationEnabled()) {
-						validationJob.schedule(DELAY);
-						break;
-					}
+					rescheduleJob();
+					break;
 				} else
 					for (EClass eClass : eObject.eClass().getEAllSuperTypes()) {
 						if (SGraphPackage.eINSTANCE == eClass.getEPackage()) {
-							validationJob.cancel();
-							if (liveValidationEnabled()) {
-								validationJob.schedule(DELAY);
-								return;
-							}
+							rescheduleJob();
+							return;
 						}
 					}
 			}
+			else if (notification.getNotifier() instanceof Resource && this.resource != null
+					&& !this.resource.equals(notification.getNotifier())) {
+				rescheduleJob();
+			}
+		}
+	}
+
+	protected void rescheduleJob() {
+		validationJob.cancel();
+		if (liveValidationEnabled()) {
+			validationJob.schedule(DELAY);
 		}
 	}
 
@@ -73,6 +80,7 @@ public class LiveValidationListener extends ResourceSetListenerImpl {
 	}
 
 	public void setResource(Resource resource) {
+		this.resource = resource;
 		validationJob.setResource(resource);
 		validationJob.setRule(WorkspaceSynchronizer.getFile(resource));
 	}