From db9e62750e0f5933b0b4acd0f30cdd33d8fead98 Mon Sep 17 00:00:00 2001 From: Lorenzo Bettini Date: Thu, 23 Jul 2020 10:41:05 +0200 Subject: [PATCH 1/9] 217: experiment with bold font Task-Url: http://github.com/LorenzoBettini/edelta/issues/217 --- .../ui/labeling/EdeltaLabelProvider.java | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/edelta.parent/edelta.ui/src/edelta/ui/labeling/EdeltaLabelProvider.java b/edelta.parent/edelta.ui/src/edelta/ui/labeling/EdeltaLabelProvider.java index 62c1f9782..df0073ebf 100644 --- a/edelta.parent/edelta.ui/src/edelta/ui/labeling/EdeltaLabelProvider.java +++ b/edelta.parent/edelta.ui/src/edelta/ui/labeling/EdeltaLabelProvider.java @@ -6,10 +6,15 @@ import static com.google.common.collect.Iterables.filter; import static org.eclipse.xtext.xbase.lib.IterableExtensions.head; +import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.ENamedElement; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider; import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.jface.viewers.StyledString; +import org.eclipse.jface.viewers.StyledString.Styler; +import org.eclipse.swt.graphics.TextStyle; import org.eclipse.xtext.common.types.JvmOperation; import org.eclipse.xtext.xbase.annotations.ui.labeling.XbaseWithAnnotationsLabelProvider; import org.eclipse.xtext.xbase.jvmmodel.IJvmModelAssociations; @@ -31,6 +36,13 @@ public class EdeltaLabelProvider extends XbaseWithAnnotationsLabelProvider { private AdapterFactoryLabelProvider delegate; + private static final Styler BOLD_FONT_STYLER = new Styler() { + @Override + public void applyStyles(final TextStyle textStyle) { + textStyle.font = JFaceResources.getFontRegistry().getBold("Edelta"); + } + }; + @Inject public EdeltaLabelProvider(final AdapterFactoryLabelProvider delegate) { super(delegate); @@ -53,14 +65,17 @@ public ImageDescriptor image(final EdeltaModifyEcoreOperation m) { return this.imageDescriptor(this.inferredJavaMethod(m)); } - public String text(final ENamedElement e) { + public Object text(final ENamedElement e) { // delegate to the default Ecore edit label provider // for Ecore model elements. - return delegate.getText(e); + final var text = delegate.getText(e); + if (e instanceof EClass) { + return new StyledString(text, BOLD_FONT_STYLER); + } + return text; } private JvmOperation inferredJavaMethod(final EObject e) { - return head(filter( - jvmModelAssociations.getJvmElements(e), JvmOperation.class)); + return head(filter(jvmModelAssociations.getJvmElements(e), JvmOperation.class)); } } From d1c919715b745438ae29b1283cf25b48b26e86e1 Mon Sep 17 00:00:00 2001 From: Lorenzo Bettini Date: Thu, 23 Jul 2020 10:54:24 +0200 Subject: [PATCH 2/9] 217: resource listener gets the derived state helper Task-Url: http://github.com/LorenzoBettini/edelta/issues/217 --- .../tests/EdeltaInterpreterResourceListenerTest.xtend | 6 ++++-- .../tests/EdeltaInterpreterResourceListenerTest.java | 9 ++++++--- .../edelta/src/edelta/interpreter/EdeltaInterpreter.java | 2 +- .../interpreter/EdeltaInterpreterResourceListener.java | 5 +++-- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/edelta.parent/edelta.tests/src/edelta/tests/EdeltaInterpreterResourceListenerTest.xtend b/edelta.parent/edelta.tests/src/edelta/tests/EdeltaInterpreterResourceListenerTest.xtend index 2b5e110cc..d99914134 100644 --- a/edelta.parent/edelta.tests/src/edelta/tests/EdeltaInterpreterResourceListenerTest.xtend +++ b/edelta.parent/edelta.tests/src/edelta/tests/EdeltaInterpreterResourceListenerTest.xtend @@ -28,6 +28,7 @@ import org.junit.runner.RunWith import static org.assertj.core.api.Assertions.assertThat import static org.mockito.Mockito.* +import edelta.resource.derivedstate.EdeltaDerivedStateHelper @RunWith(XtextRunner) @InjectWith(EdeltaInjectorProvider) @@ -44,6 +45,7 @@ class EdeltaInterpreterResourceListenerTest extends EdeltaAbstractTest { @Inject IResourceScopeCache cache @Inject EdeltaInterpreterDiagnosticHelper diagnosticHelper + @Inject EdeltaDerivedStateHelper derivedStateHelper var EdeltaInterpreterResourceListener listener var EPackage ePackage var Resource resource @@ -59,9 +61,9 @@ class EdeltaInterpreterResourceListenerTest extends EdeltaAbstractTest { ] ] resource = "".parse.eResource - enamedElementXExpressionMap = new EdeltaENamedElementXExpressionMap + enamedElementXExpressionMap = derivedStateHelper.getEnamedElementXExpressionMap(resource) listener = new EdeltaInterpreterResourceListener( - cache, resource, enamedElementXExpressionMap, diagnosticHelper + cache, resource, derivedStateHelper, diagnosticHelper ) stringProvider = spy(new SpiedProvider) ePackage.eAdapters += listener diff --git a/edelta.parent/edelta.tests/xtend-gen/edelta/tests/EdeltaInterpreterResourceListenerTest.java b/edelta.parent/edelta.tests/xtend-gen/edelta/tests/EdeltaInterpreterResourceListenerTest.java index 48f9dad60..0b3ecf399 100644 --- a/edelta.parent/edelta.tests/xtend-gen/edelta/tests/EdeltaInterpreterResourceListenerTest.java +++ b/edelta.parent/edelta.tests/xtend-gen/edelta/tests/EdeltaInterpreterResourceListenerTest.java @@ -6,6 +6,7 @@ import edelta.interpreter.EdeltaInterpreterDiagnostic; import edelta.interpreter.EdeltaInterpreterDiagnosticHelper; import edelta.interpreter.EdeltaInterpreterResourceListener; +import edelta.resource.derivedstate.EdeltaDerivedStateHelper; import edelta.resource.derivedstate.EdeltaENamedElementXExpressionMap; import edelta.tests.EdeltaAbstractTest; import edelta.tests.EdeltaInjectorProvider; @@ -61,6 +62,9 @@ public String get() { @Inject private EdeltaInterpreterDiagnosticHelper diagnosticHelper; + @Inject + private EdeltaDerivedStateHelper derivedStateHelper; + private EdeltaInterpreterResourceListener listener; private EPackage ePackage; @@ -88,10 +92,9 @@ public void setup() { EPackage _doubleArrow = ObjectExtensions.operator_doubleArrow(_createEPackage, _function); this.ePackage = _doubleArrow; this.resource = this._parseHelper.parse("").eResource(); - EdeltaENamedElementXExpressionMap _edeltaENamedElementXExpressionMap = new EdeltaENamedElementXExpressionMap(); - this.enamedElementXExpressionMap = _edeltaENamedElementXExpressionMap; + this.enamedElementXExpressionMap = this.derivedStateHelper.getEnamedElementXExpressionMap(this.resource); EdeltaInterpreterResourceListener _edeltaInterpreterResourceListener = new EdeltaInterpreterResourceListener( - this.cache, this.resource, this.enamedElementXExpressionMap, this.diagnosticHelper); + this.cache, this.resource, this.derivedStateHelper, this.diagnosticHelper); this.listener = _edeltaInterpreterResourceListener; EdeltaInterpreterResourceListenerTest.SpiedProvider _spiedProvider = new EdeltaInterpreterResourceListenerTest.SpiedProvider(); this.stringProvider = Mockito.>spy(_spiedProvider); diff --git a/edelta.parent/edelta/src/edelta/interpreter/EdeltaInterpreter.java b/edelta.parent/edelta/src/edelta/interpreter/EdeltaInterpreter.java index 3e3306533..18df36379 100644 --- a/edelta.parent/edelta/src/edelta/interpreter/EdeltaInterpreter.java +++ b/edelta.parent/edelta/src/edelta/interpreter/EdeltaInterpreter.java @@ -141,7 +141,7 @@ public void evaluateModifyEcoreOperations(final EdeltaProgram program, final Ede edeltaInterpreterHelper.filterOperations(program.getModifyEcoreOperations()); final var eResource = program.eResource(); listener = new EdeltaInterpreterResourceListener(cache, eResource, - derivedStateHelper.getEnamedElementXExpressionMap(eResource), + derivedStateHelper, diagnosticHelper); try { addResourceListener(copiedEPackages); diff --git a/edelta.parent/edelta/src/edelta/interpreter/EdeltaInterpreterResourceListener.java b/edelta.parent/edelta/src/edelta/interpreter/EdeltaInterpreterResourceListener.java index 407c505f4..3d72adaa9 100644 --- a/edelta.parent/edelta/src/edelta/interpreter/EdeltaInterpreterResourceListener.java +++ b/edelta.parent/edelta/src/edelta/interpreter/EdeltaInterpreterResourceListener.java @@ -18,6 +18,7 @@ import edelta.edelta.EdeltaEcoreReferenceExpression; import edelta.lib.EdeltaLibrary; +import edelta.resource.derivedstate.EdeltaDerivedStateHelper; import edelta.resource.derivedstate.EdeltaENamedElementXExpressionMap; import edelta.util.EdeltaModelUtil; import edelta.validation.EdeltaValidator; @@ -48,11 +49,11 @@ public class EdeltaInterpreterResourceListener extends EContentAdapter { private EdeltaLibrary lib = new EdeltaLibrary(); public EdeltaInterpreterResourceListener(IResourceScopeCache cache, Resource resource, - EdeltaENamedElementXExpressionMap enamedElementXExpressionMap, + EdeltaDerivedStateHelper derivedStateHelper, EdeltaInterpreterDiagnosticHelper diagnosticHelper) { this.cache = cache; this.resource = resource; - this.enamedElementXExpressionMap = enamedElementXExpressionMap; + this.enamedElementXExpressionMap = derivedStateHelper.getEnamedElementXExpressionMap(resource); this.diagnosticHelper = diagnosticHelper; } From 4204fbe7f86f5595ee80b27ebe43490d987d99d9 Mon Sep 17 00:00:00 2001 From: Lorenzo Bettini Date: Thu, 23 Jul 2020 11:32:54 +0200 Subject: [PATCH 3/9] 217: first implementation of modified elements Task-Url: http://github.com/LorenzoBettini/edelta/issues/217 --- ...deltaInterpreterResourceListenerTest.xtend | 14 +++++++++ ...EdeltaInterpreterResourceListenerTest.java | 13 ++++++++ .../EdeltaInterpreterResourceListener.java | 30 +++++++++++++++++-- .../derivedstate/EdeltaDerivedState.java | 7 +++++ .../EdeltaDerivedStateHelper.java | 4 +++ .../derivedstate/EdeltaModifiedElements.java | 21 +++++++++++++ 6 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 edelta.parent/edelta/src/edelta/resource/derivedstate/EdeltaModifiedElements.java diff --git a/edelta.parent/edelta.tests/src/edelta/tests/EdeltaInterpreterResourceListenerTest.xtend b/edelta.parent/edelta.tests/src/edelta/tests/EdeltaInterpreterResourceListenerTest.xtend index d99914134..e1c674a36 100644 --- a/edelta.parent/edelta.tests/src/edelta/tests/EdeltaInterpreterResourceListenerTest.xtend +++ b/edelta.parent/edelta.tests/src/edelta/tests/EdeltaInterpreterResourceListenerTest.xtend @@ -29,6 +29,7 @@ import org.junit.runner.RunWith import static org.assertj.core.api.Assertions.assertThat import static org.mockito.Mockito.* import edelta.resource.derivedstate.EdeltaDerivedStateHelper +import edelta.resource.derivedstate.EdeltaModifiedElements @RunWith(XtextRunner) @InjectWith(EdeltaInjectorProvider) @@ -50,6 +51,7 @@ class EdeltaInterpreterResourceListenerTest extends EdeltaAbstractTest { var EPackage ePackage var Resource resource var EdeltaENamedElementXExpressionMap enamedElementXExpressionMap + var EdeltaModifiedElements modifiedElements var Provider stringProvider @Before @@ -62,6 +64,7 @@ class EdeltaInterpreterResourceListenerTest extends EdeltaAbstractTest { ] resource = "".parse.eResource enamedElementXExpressionMap = derivedStateHelper.getEnamedElementXExpressionMap(resource) + modifiedElements = derivedStateHelper.getModifiedElements(resource) listener = new EdeltaInterpreterResourceListener( cache, resource, derivedStateHelper, diagnosticHelper ) @@ -261,6 +264,17 @@ class EdeltaInterpreterResourceListenerTest extends EdeltaAbstractTest { assertThat(resource.validate).hasSize(1) } + @Test + def void testModifiedElementsIsUpdatedWhenNameIsChanged() { + val currentExpression = mock(XExpression) + listener.setCurrentExpression(currentExpression) + val element = ePackage.EClassifiers.get(0) + // change the name + element.name = "Modified" + assertThat(modifiedElements) + .containsExactlyInAnyOrder(element, ePackage) + } + def createEObjectDiagnosticMock(EObject problematicObject) { mock(EObjectDiagnosticImpl) => [ when(getProblematicObject).thenReturn(problematicObject) diff --git a/edelta.parent/edelta.tests/xtend-gen/edelta/tests/EdeltaInterpreterResourceListenerTest.java b/edelta.parent/edelta.tests/xtend-gen/edelta/tests/EdeltaInterpreterResourceListenerTest.java index 0b3ecf399..925053156 100644 --- a/edelta.parent/edelta.tests/xtend-gen/edelta/tests/EdeltaInterpreterResourceListenerTest.java +++ b/edelta.parent/edelta.tests/xtend-gen/edelta/tests/EdeltaInterpreterResourceListenerTest.java @@ -8,6 +8,7 @@ import edelta.interpreter.EdeltaInterpreterResourceListener; import edelta.resource.derivedstate.EdeltaDerivedStateHelper; import edelta.resource.derivedstate.EdeltaENamedElementXExpressionMap; +import edelta.resource.derivedstate.EdeltaModifiedElements; import edelta.tests.EdeltaAbstractTest; import edelta.tests.EdeltaInjectorProvider; import edelta.validation.EdeltaValidator; @@ -73,6 +74,8 @@ public String get() { private EdeltaENamedElementXExpressionMap enamedElementXExpressionMap; + private EdeltaModifiedElements modifiedElements; + private Provider stringProvider; @Before @@ -93,6 +96,7 @@ public void setup() { this.ePackage = _doubleArrow; this.resource = this._parseHelper.parse("").eResource(); this.enamedElementXExpressionMap = this.derivedStateHelper.getEnamedElementXExpressionMap(this.resource); + this.modifiedElements = this.derivedStateHelper.getModifiedElements(this.resource); EdeltaInterpreterResourceListener _edeltaInterpreterResourceListener = new EdeltaInterpreterResourceListener( this.cache, this.resource, this.derivedStateHelper, this.diagnosticHelper); this.listener = _edeltaInterpreterResourceListener; @@ -293,6 +297,15 @@ public void testEClassCycleWhenAddingSuperType() { Assertions.assertThat(this._validationTestHelper.validate(this.resource)).hasSize(1); } + @Test + public void testModifiedElementsIsUpdatedWhenNameIsChanged() { + final XExpression currentExpression = Mockito.mock(XExpression.class); + this.listener.setCurrentExpression(currentExpression); + final EClassifier element = this.ePackage.getEClassifiers().get(0); + element.setName("Modified"); + Assertions.assertThat(this.modifiedElements).containsExactlyInAnyOrder(element, this.ePackage); + } + public EObjectDiagnosticImpl createEObjectDiagnosticMock(final EObject problematicObject) { EObjectDiagnosticImpl _mock = Mockito.mock(EObjectDiagnosticImpl.class); final Procedure1 _function = (EObjectDiagnosticImpl it) -> { diff --git a/edelta.parent/edelta/src/edelta/interpreter/EdeltaInterpreterResourceListener.java b/edelta.parent/edelta/src/edelta/interpreter/EdeltaInterpreterResourceListener.java index 3d72adaa9..377a460e7 100644 --- a/edelta.parent/edelta/src/edelta/interpreter/EdeltaInterpreterResourceListener.java +++ b/edelta.parent/edelta/src/edelta/interpreter/EdeltaInterpreterResourceListener.java @@ -2,11 +2,14 @@ import static org.eclipse.emf.ecore.EcorePackage.Literals.*; +import java.util.HashSet; import java.util.List; +import java.util.Set; import org.eclipse.emf.common.notify.Notification; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.ENamedElement; +import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.Resource.Diagnostic; @@ -20,6 +23,7 @@ import edelta.lib.EdeltaLibrary; import edelta.resource.derivedstate.EdeltaDerivedStateHelper; import edelta.resource.derivedstate.EdeltaENamedElementXExpressionMap; +import edelta.resource.derivedstate.EdeltaModifiedElements; import edelta.util.EdeltaModelUtil; import edelta.validation.EdeltaValidator; @@ -48,12 +52,15 @@ public class EdeltaInterpreterResourceListener extends EContentAdapter { private EdeltaLibrary lib = new EdeltaLibrary(); + private EdeltaModifiedElements modifiedElements; + public EdeltaInterpreterResourceListener(IResourceScopeCache cache, Resource resource, EdeltaDerivedStateHelper derivedStateHelper, EdeltaInterpreterDiagnosticHelper diagnosticHelper) { this.cache = cache; this.resource = resource; this.enamedElementXExpressionMap = derivedStateHelper.getEnamedElementXExpressionMap(resource); + this.modifiedElements = derivedStateHelper.getModifiedElements(resource); this.diagnosticHelper = diagnosticHelper; } @@ -61,12 +68,13 @@ public EdeltaInterpreterResourceListener(IResourceScopeCache cache, Resource res public void notifyChanged(Notification notification) { super.notifyChanged(notification); final Object feature = notification.getFeature(); + final Object notifier = notification.getNotifier(); + final Object newValue = notification.getNewValue(); if (feature == ENAMED_ELEMENT__NAME) { enamedElementXExpressionMap.put( - (ENamedElement) notification.getNotifier(), + (ENamedElement) notifier, currentExpression); } else { - final Object newValue = notification.getNewValue(); if (notification.getEventType() == Notification.ADD && newValue instanceof ENamedElement) { enamedElementXExpressionMap.put( @@ -78,11 +86,29 @@ public void notifyChanged(Notification notification) { checkCycles(feature, newValue); } } + updateModifiedelements(notifier, new HashSet<>()); + updateModifiedelements(newValue, new HashSet<>()); cache.clear(resource); clearIssues(resource.getErrors()); clearIssues(resource.getWarnings()); } + private void updateModifiedelements(Object element, Set seen) { + /* + * we have to avoid stack overflows in case of cycles; we break the cycle for + * supertype hierarchy, but when doing so we get another notification and in + * that case the cycle it's still there + */ + if (element instanceof ENamedElement) { + final var enamedElement = (ENamedElement) element; + if (seen.contains(enamedElement)) + return; + seen.add(enamedElement); + modifiedElements.add(enamedElement); + updateModifiedelements(enamedElement.eContainer(), seen); + } + } + private void checkCycles(final Object feature, final Object newValue) { if (feature == EPACKAGE__ESUBPACKAGES) { EPackage subPackage = (EPackage) newValue; diff --git a/edelta.parent/edelta/src/edelta/resource/derivedstate/EdeltaDerivedState.java b/edelta.parent/edelta/src/edelta/resource/derivedstate/EdeltaDerivedState.java index 70d0f89ed..35e90ff3e 100644 --- a/edelta.parent/edelta/src/edelta/resource/derivedstate/EdeltaDerivedState.java +++ b/edelta.parent/edelta/src/edelta/resource/derivedstate/EdeltaDerivedState.java @@ -15,6 +15,7 @@ public class EdeltaDerivedState extends AdapterImpl { private EdeltaEcoreReferenceExpressionStateMap ecoreReferenceExpressionStateMap = new EdeltaEcoreReferenceExpressionStateMap(); private EdeltaENamedElementXExpressionMap enamedElementXExpressionMap = new EdeltaENamedElementXExpressionMap(); private EdeltaUnresolvedEcoreReferences unresolvedEcoreReferences = new EdeltaUnresolvedEcoreReferences(); + private EdeltaModifiedElements modifiedElements = new EdeltaModifiedElements(); @Override public boolean isAdapterForType(final Object type) { @@ -41,11 +42,17 @@ public EdeltaUnresolvedEcoreReferences getUnresolvedEcoreReferences() { return unresolvedEcoreReferences; } + public EdeltaModifiedElements getModifiedElements() { + return modifiedElements; + } + public void clear() { copiedEPackagesMap.clear(); ecoreReferenceStateMap.clear(); ecoreReferenceExpressionStateMap.clear(); enamedElementXExpressionMap.clear(); unresolvedEcoreReferences.clear(); + modifiedElements.clear(); } + } \ No newline at end of file diff --git a/edelta.parent/edelta/src/edelta/resource/derivedstate/EdeltaDerivedStateHelper.java b/edelta.parent/edelta/src/edelta/resource/derivedstate/EdeltaDerivedStateHelper.java index f342650c1..6de3f4017 100644 --- a/edelta.parent/edelta/src/edelta/resource/derivedstate/EdeltaDerivedStateHelper.java +++ b/edelta.parent/edelta/src/edelta/resource/derivedstate/EdeltaDerivedStateHelper.java @@ -158,4 +158,8 @@ public void setAccessibleElements(EdeltaEcoreReferenceExpression ecoreRefExp, .setAccessibleElements(accessibleElements); } + public EdeltaModifiedElements getModifiedElements(Resource resource) { + return getOrInstallAdapter(resource).getModifiedElements(); + } + } diff --git a/edelta.parent/edelta/src/edelta/resource/derivedstate/EdeltaModifiedElements.java b/edelta.parent/edelta/src/edelta/resource/derivedstate/EdeltaModifiedElements.java new file mode 100644 index 000000000..33fe4a34e --- /dev/null +++ b/edelta.parent/edelta/src/edelta/resource/derivedstate/EdeltaModifiedElements.java @@ -0,0 +1,21 @@ +/** + * + */ +package edelta.resource.derivedstate; + +import java.util.HashSet; + +import org.eclipse.emf.ecore.ENamedElement; + +/** + * Keeps track of {@link ENamedElement}s that have been modified during the + * interpretation. + * + * @author Lorenzo Bettini + * + */ +public class EdeltaModifiedElements extends HashSet { + + private static final long serialVersionUID = 1L; + +} From ea425ef5fe3309ffa025281e2b36ab8ae34f62cd Mon Sep 17 00:00:00 2001 From: Lorenzo Bettini Date: Thu, 23 Jul 2020 16:17:10 +0200 Subject: [PATCH 4/9] 217: simplified loop guard Task-Url: http://github.com/LorenzoBettini/edelta/issues/217 --- .../EdeltaInterpreterResourceListener.java | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/edelta.parent/edelta/src/edelta/interpreter/EdeltaInterpreterResourceListener.java b/edelta.parent/edelta/src/edelta/interpreter/EdeltaInterpreterResourceListener.java index 377a460e7..95d1a692c 100644 --- a/edelta.parent/edelta/src/edelta/interpreter/EdeltaInterpreterResourceListener.java +++ b/edelta.parent/edelta/src/edelta/interpreter/EdeltaInterpreterResourceListener.java @@ -2,14 +2,11 @@ import static org.eclipse.emf.ecore.EcorePackage.Literals.*; -import java.util.HashSet; import java.util.List; -import java.util.Set; import org.eclipse.emf.common.notify.Notification; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.ENamedElement; -import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.Resource.Diagnostic; @@ -86,26 +83,23 @@ public void notifyChanged(Notification notification) { checkCycles(feature, newValue); } } - updateModifiedelements(notifier, new HashSet<>()); - updateModifiedelements(newValue, new HashSet<>()); + updateModifiedElements(notifier); + updateModifiedElements(newValue); cache.clear(resource); clearIssues(resource.getErrors()); clearIssues(resource.getWarnings()); } - private void updateModifiedelements(Object element, Set seen) { + private void updateModifiedElements(Object element) { /* - * we have to avoid stack overflows in case of cycles; we break the cycle for - * supertype hierarchy, but when doing so we get another notification and in - * that case the cycle it's still there + * we have to avoid stack overflows, by checking the result of add in case of + * cycles; we break the cycle for supertype hierarchy, but when doing so we get + * another notification and in that case the cycle it's still there */ if (element instanceof ENamedElement) { final var enamedElement = (ENamedElement) element; - if (seen.contains(enamedElement)) - return; - seen.add(enamedElement); - modifiedElements.add(enamedElement); - updateModifiedelements(enamedElement.eContainer(), seen); + if (modifiedElements.add(enamedElement)) + updateModifiedElements(enamedElement.eContainer()); } } From 9491f31d82829236cf212cd8d79320b2474c7949 Mon Sep 17 00:00:00 2001 From: Lorenzo Bettini Date: Thu, 23 Jul 2020 16:22:01 +0200 Subject: [PATCH 5/9] 217: handle notification.isTouch Task-Url: http://github.com/LorenzoBettini/edelta/issues/217 --- .../tests/EdeltaInterpreterResourceListenerTest.xtend | 6 ++++++ .../tests/EdeltaInterpreterResourceListenerTest.java | 7 +++++++ .../interpreter/EdeltaInterpreterResourceListener.java | 6 ++++-- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/edelta.parent/edelta.tests/src/edelta/tests/EdeltaInterpreterResourceListenerTest.xtend b/edelta.parent/edelta.tests/src/edelta/tests/EdeltaInterpreterResourceListenerTest.xtend index e1c674a36..53344df85 100644 --- a/edelta.parent/edelta.tests/src/edelta/tests/EdeltaInterpreterResourceListenerTest.xtend +++ b/edelta.parent/edelta.tests/src/edelta/tests/EdeltaInterpreterResourceListenerTest.xtend @@ -275,6 +275,12 @@ class EdeltaInterpreterResourceListenerTest extends EdeltaAbstractTest { .containsExactlyInAnyOrder(element, ePackage) } + @Test + def void testModifiedElementsIsEmptyWhenNothingIsChanged() { + ePackage.eAdapters -= listener + assertThat(modifiedElements).isEmpty + } + def createEObjectDiagnosticMock(EObject problematicObject) { mock(EObjectDiagnosticImpl) => [ when(getProblematicObject).thenReturn(problematicObject) diff --git a/edelta.parent/edelta.tests/xtend-gen/edelta/tests/EdeltaInterpreterResourceListenerTest.java b/edelta.parent/edelta.tests/xtend-gen/edelta/tests/EdeltaInterpreterResourceListenerTest.java index 925053156..7284de9cf 100644 --- a/edelta.parent/edelta.tests/xtend-gen/edelta/tests/EdeltaInterpreterResourceListenerTest.java +++ b/edelta.parent/edelta.tests/xtend-gen/edelta/tests/EdeltaInterpreterResourceListenerTest.java @@ -306,6 +306,13 @@ public void testModifiedElementsIsUpdatedWhenNameIsChanged() { Assertions.assertThat(this.modifiedElements).containsExactlyInAnyOrder(element, this.ePackage); } + @Test + public void testModifiedElementsIsEmptyWhenNothingIsChanged() { + EList _eAdapters = this.ePackage.eAdapters(); + _eAdapters.remove(this.listener); + Assertions.assertThat(this.modifiedElements).isEmpty(); + } + public EObjectDiagnosticImpl createEObjectDiagnosticMock(final EObject problematicObject) { EObjectDiagnosticImpl _mock = Mockito.mock(EObjectDiagnosticImpl.class); final Procedure1 _function = (EObjectDiagnosticImpl it) -> { diff --git a/edelta.parent/edelta/src/edelta/interpreter/EdeltaInterpreterResourceListener.java b/edelta.parent/edelta/src/edelta/interpreter/EdeltaInterpreterResourceListener.java index 95d1a692c..aa48b360e 100644 --- a/edelta.parent/edelta/src/edelta/interpreter/EdeltaInterpreterResourceListener.java +++ b/edelta.parent/edelta/src/edelta/interpreter/EdeltaInterpreterResourceListener.java @@ -83,8 +83,10 @@ public void notifyChanged(Notification notification) { checkCycles(feature, newValue); } } - updateModifiedElements(notifier); - updateModifiedElements(newValue); + if (!notification.isTouch()) { + updateModifiedElements(notifier); + updateModifiedElements(newValue); + } cache.clear(resource); clearIssues(resource.getErrors()); clearIssues(resource.getWarnings()); From 96b5195868445875d6f6091062343de8e70b8d46 Mon Sep 17 00:00:00 2001 From: Lorenzo Bettini Date: Thu, 23 Jul 2020 16:25:32 +0200 Subject: [PATCH 6/9] 217: test for new class added Task-Url: http://github.com/LorenzoBettini/edelta/issues/217 --- .../tests/EdeltaInterpreterResourceListenerTest.xtend | 10 ++++++++++ .../tests/EdeltaInterpreterResourceListenerTest.java | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/edelta.parent/edelta.tests/src/edelta/tests/EdeltaInterpreterResourceListenerTest.xtend b/edelta.parent/edelta.tests/src/edelta/tests/EdeltaInterpreterResourceListenerTest.xtend index 53344df85..81b81ee71 100644 --- a/edelta.parent/edelta.tests/src/edelta/tests/EdeltaInterpreterResourceListenerTest.xtend +++ b/edelta.parent/edelta.tests/src/edelta/tests/EdeltaInterpreterResourceListenerTest.xtend @@ -266,6 +266,16 @@ class EdeltaInterpreterResourceListenerTest extends EdeltaAbstractTest { @Test def void testModifiedElementsIsUpdatedWhenNameIsChanged() { + val currentExpression = mock(XExpression) + listener.setCurrentExpression(currentExpression) + val element = ecoreFactory.createEClass + ePackage.EClassifiers += element + assertThat(modifiedElements) + .containsExactlyInAnyOrder(element, ePackage) + } + + @Test + def void testModifiedElementsIsUpdatedWhenElementIsAdded() { val currentExpression = mock(XExpression) listener.setCurrentExpression(currentExpression) val element = ePackage.EClassifiers.get(0) diff --git a/edelta.parent/edelta.tests/xtend-gen/edelta/tests/EdeltaInterpreterResourceListenerTest.java b/edelta.parent/edelta.tests/xtend-gen/edelta/tests/EdeltaInterpreterResourceListenerTest.java index 7284de9cf..eac40a52a 100644 --- a/edelta.parent/edelta.tests/xtend-gen/edelta/tests/EdeltaInterpreterResourceListenerTest.java +++ b/edelta.parent/edelta.tests/xtend-gen/edelta/tests/EdeltaInterpreterResourceListenerTest.java @@ -299,6 +299,16 @@ public void testEClassCycleWhenAddingSuperType() { @Test public void testModifiedElementsIsUpdatedWhenNameIsChanged() { + final XExpression currentExpression = Mockito.mock(XExpression.class); + this.listener.setCurrentExpression(currentExpression); + final EClass element = EdeltaInterpreterResourceListenerTest.ecoreFactory.createEClass(); + EList _eClassifiers = this.ePackage.getEClassifiers(); + _eClassifiers.add(element); + Assertions.assertThat(this.modifiedElements).containsExactlyInAnyOrder(element, this.ePackage); + } + + @Test + public void testModifiedElementsIsUpdatedWhenElementIsAdded() { final XExpression currentExpression = Mockito.mock(XExpression.class); this.listener.setCurrentExpression(currentExpression); final EClassifier element = this.ePackage.getEClassifiers().get(0); From 567909658073211c1eda1d4dfdb18f6391303dbd Mon Sep 17 00:00:00 2001 From: Lorenzo Bettini Date: Thu, 23 Jul 2020 16:47:02 +0200 Subject: [PATCH 7/9] 217: Outline shows only EPackages with modified elements Task-Url: http://github.com/LorenzoBettini/edelta/issues/217 --- .../edelta/ui/tests/EdeltaOutlineTest.xtend | 21 +++++++++++++++ .../edelta/ui/tests/EdeltaOutlineTest.java | 27 +++++++++++++++++++ .../ui/outline/EdeltaOutlineTreeProvider.java | 13 +++++---- 3 files changed, 56 insertions(+), 5 deletions(-) diff --git a/edelta.parent/edelta.ui.tests/src/edelta/ui/tests/EdeltaOutlineTest.xtend b/edelta.parent/edelta.ui.tests/src/edelta/ui/tests/EdeltaOutlineTest.xtend index 8b7d65f48..fe901c347 100644 --- a/edelta.parent/edelta.ui.tests/src/edelta/ui/tests/EdeltaOutlineTest.xtend +++ b/edelta.parent/edelta.ui.tests/src/edelta/ui/tests/EdeltaOutlineTest.xtend @@ -168,6 +168,27 @@ class EdeltaOutlineTest extends AbstractOutlineTest { ) } + @Test @Flaky + def void testOutlineWhenNoElementIsModifiedThenTheEPackageIsNotShown() { + println("*** Executing testOutlineWhenNoElementIsModified...") + // wait for build so that ecores are indexed + // and then found by the test programs + waitForBuild + + ''' + metamodel "mypackage" + + modifyEcore aModification epackage mypackage { + + } + '''.assertAllLabels( + ''' + test + aModification(EPackage) : void + ''' + ) + } + def private allOtherContents() ''' diff --git a/edelta.parent/edelta.ui.tests/xtend-gen/edelta/ui/tests/EdeltaOutlineTest.java b/edelta.parent/edelta.ui.tests/xtend-gen/edelta/ui/tests/EdeltaOutlineTest.java index 3911e4bf2..eefd1024c 100644 --- a/edelta.parent/edelta.ui.tests/xtend-gen/edelta/ui/tests/EdeltaOutlineTest.java +++ b/edelta.parent/edelta.ui.tests/xtend-gen/edelta/ui/tests/EdeltaOutlineTest.java @@ -268,6 +268,33 @@ public void testOutlineWithRemovedElementsInModifyEcore() { } } + @Test + @Flaky + public void testOutlineWhenNoElementIsModifiedThenTheEPackageIsNotShown() { + try { + InputOutput.println("*** Executing testOutlineWhenNoElementIsModified..."); + IResourcesSetupUtil.waitForBuild(); + StringConcatenation _builder = new StringConcatenation(); + _builder.append("metamodel \"mypackage\""); + _builder.newLine(); + _builder.newLine(); + _builder.append("modifyEcore aModification epackage mypackage {"); + _builder.newLine(); + _builder.newLine(); + _builder.append("}"); + _builder.newLine(); + StringConcatenation _builder_1 = new StringConcatenation(); + _builder_1.append("test"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("aModification(EPackage) : void"); + _builder_1.newLine(); + this.assertAllLabels(_builder, _builder_1); + } catch (Throwable _e) { + throw Exceptions.sneakyThrow(_e); + } + } + private CharSequence allOtherContents() { StringConcatenation _builder = new StringConcatenation(); _builder.append("MyClass"); diff --git a/edelta.parent/edelta.ui/src/edelta/ui/outline/EdeltaOutlineTreeProvider.java b/edelta.parent/edelta.ui/src/edelta/ui/outline/EdeltaOutlineTreeProvider.java index a9f480d7c..f7082ccda 100644 --- a/edelta.parent/edelta.ui/src/edelta/ui/outline/EdeltaOutlineTreeProvider.java +++ b/edelta.parent/edelta.ui/src/edelta/ui/outline/EdeltaOutlineTreeProvider.java @@ -3,7 +3,6 @@ */ package edelta.ui.outline; -import org.eclipse.emf.ecore.EPackage; import org.eclipse.xtext.ui.editor.outline.IOutlineNode; import org.eclipse.xtext.ui.editor.outline.impl.DefaultOutlineTreeProvider; @@ -24,17 +23,21 @@ public class EdeltaOutlineTreeProvider extends DefaultOutlineTreeProvider { private EdeltaDerivedStateHelper derivedStateHelper; protected void _createChildren(final IOutlineNode parentNode, final EdeltaProgram p) { - for (final EdeltaOperation o : p.getOperations()) { + for (final var o : p.getOperations()) { this.createNode(parentNode, o); } - for (final EdeltaModifyEcoreOperation o : p.getModifyEcoreOperations()) { + for (final var o : p.getModifyEcoreOperations()) { this.createNode(parentNode, o); } - for (final EPackage copiedEPackage : this.derivedStateHelper.getCopiedEPackagesMap(p.eResource()).values()) { + final var eResource = p.eResource(); + final var modifiedElements = derivedStateHelper.getModifiedElements(eResource); + for (final var ePackage : this.derivedStateHelper.getCopiedEPackagesMap(eResource).values()) { // the cool thing is that we don't need to provide // customization in the label provider for EPackage and EClass // since Xtext defaults to the .edit plugin :) - this.createNode(parentNode, copiedEPackage); + if (modifiedElements.contains(ePackage)) + this.createNode(parentNode, ePackage); + // only show EPackage with some modifications } } From 4df98da6048a396127cc7506273ce54c4d5d9fba Mon Sep 17 00:00:00 2001 From: Lorenzo Bettini Date: Thu, 23 Jul 2020 16:57:57 +0200 Subject: [PATCH 8/9] 217: Outline should highlight modified elements Task-Url: http://github.com/LorenzoBettini/edelta/issues/217 --- .../src/edelta/ui/labeling/EdeltaLabelProvider.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/edelta.parent/edelta.ui/src/edelta/ui/labeling/EdeltaLabelProvider.java b/edelta.parent/edelta.ui/src/edelta/ui/labeling/EdeltaLabelProvider.java index df0073ebf..aa76c4980 100644 --- a/edelta.parent/edelta.ui/src/edelta/ui/labeling/EdeltaLabelProvider.java +++ b/edelta.parent/edelta.ui/src/edelta/ui/labeling/EdeltaLabelProvider.java @@ -6,9 +6,9 @@ import static com.google.common.collect.Iterables.filter; import static org.eclipse.xtext.xbase.lib.IterableExtensions.head; -import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.ENamedElement; import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.resource.JFaceResources; @@ -23,6 +23,7 @@ import edelta.edelta.EdeltaModifyEcoreOperation; import edelta.edelta.EdeltaOperation; +import edelta.resource.derivedstate.EdeltaDerivedStateHelper; /** * Provides labels for EObjects. @@ -34,6 +35,9 @@ public class EdeltaLabelProvider extends XbaseWithAnnotationsLabelProvider { @Inject private IJvmModelAssociations jvmModelAssociations; + @Inject + private EdeltaDerivedStateHelper derivedStateHelper; + private AdapterFactoryLabelProvider delegate; private static final Styler BOLD_FONT_STYLER = new Styler() { @@ -69,7 +73,11 @@ public Object text(final ENamedElement e) { // delegate to the default Ecore edit label provider // for Ecore model elements. final var text = delegate.getText(e); - if (e instanceof EClass) { + if (e instanceof EPackage) { + return text; // no need to highlight EPackage + // since only the ones with modified elements are shown in the outline + } + if (derivedStateHelper.getModifiedElements(e.eResource()).contains(e)) { return new StyledString(text, BOLD_FONT_STYLER); } return text; From 2d48aba4e964ee0aa5f9d43b2473ecdd5f252de6 Mon Sep 17 00:00:00 2001 From: Lorenzo Bettini Date: Thu, 23 Jul 2020 18:32:51 +0200 Subject: [PATCH 9/9] 217: label provider test Task-Url: http://github.com/LorenzoBettini/edelta/issues/217 --- .../edelta.ui.tests/META-INF/MANIFEST.MF | 3 +- .../ui/tests/EdeltaLabelProviderTest.java | 68 +++++++++++++++++++ edelta.parent/edelta.ui/META-INF/MANIFEST.MF | 5 +- 3 files changed, 73 insertions(+), 3 deletions(-) create mode 100644 edelta.parent/edelta.ui.tests/src/edelta/ui/tests/EdeltaLabelProviderTest.java diff --git a/edelta.parent/edelta.ui.tests/META-INF/MANIFEST.MF b/edelta.parent/edelta.ui.tests/META-INF/MANIFEST.MF index de8b44800..58267e67e 100644 --- a/edelta.parent/edelta.ui.tests/META-INF/MANIFEST.MF +++ b/edelta.parent/edelta.ui.tests/META-INF/MANIFEST.MF @@ -18,7 +18,8 @@ Require-Bundle: edelta, org.eclipse.xtext.testing, org.eclipse.xtext.xbase.testing, org.eclipse.xtext.ui.testing, - org.eclipse.xtext.xbase.ui.testing + org.eclipse.xtext.xbase.ui.testing, + edelta.testing.libraries;bundle-version="0.9.0" Bundle-RequiredExecutionEnvironment: JavaSE-11 Export-Package: edelta.ui.tests;x-internal=true Import-Package: org.hamcrest.core, diff --git a/edelta.parent/edelta.ui.tests/src/edelta/ui/tests/EdeltaLabelProviderTest.java b/edelta.parent/edelta.ui.tests/src/edelta/ui/tests/EdeltaLabelProviderTest.java new file mode 100644 index 000000000..f7067a976 --- /dev/null +++ b/edelta.parent/edelta.ui.tests/src/edelta/ui/tests/EdeltaLabelProviderTest.java @@ -0,0 +1,68 @@ +package edelta.ui.tests; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.eclipse.emf.ecore.EcoreFactory; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.jface.viewers.StyledString; +import org.eclipse.xtext.testing.InjectWith; +import org.eclipse.xtext.testing.XtextRunner; +import org.eclipse.xtext.testing.util.ParseHelper; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.google.inject.Inject; + +import edelta.edelta.EdeltaProgram; +import edelta.resource.derivedstate.EdeltaDerivedStateHelper; +import edelta.ui.labeling.EdeltaLabelProvider; + +@RunWith(XtextRunner.class) +@InjectWith(EdeltaUiInjectorProvider.class) +public class EdeltaLabelProviderTest { + + @Inject + private EdeltaLabelProvider labelProvider; + + @Inject + private EdeltaDerivedStateHelper derivedStateHelper; + + @Inject + private ParseHelper parseHelper; + + private Resource resource; + + private static EcoreFactory ecoreFactory = EcoreFactory.eINSTANCE; + + @Before + public void setup() throws Exception { + resource = parseHelper.parse("").eResource(); + } + + @Test + public void testEPackageStyledString() { + var ePackage = ecoreFactory.createEPackage(); + resource.getContents().add(ePackage); + StyledString styledText = labelProvider.getStyledText(ePackage); + assertThat(styledText.getStyleRanges()).isEmpty(); + } + + @Test + public void testStyledStringWhenNotModified() { + var element = ecoreFactory.createEClass(); + resource.getContents().add(element); + StyledString styledText = labelProvider.getStyledText(element); + assertThat(styledText.getStyleRanges()).isEmpty(); + } + + @Test + public void testStyledStringWhenModified() { + var element = ecoreFactory.createEClass(); + element.setName("aclass"); + resource.getContents().add(element); + derivedStateHelper.getModifiedElements(resource).add(element); + StyledString styledText = labelProvider.getStyledText(element); + assertThat(styledText.getStyleRanges()).isNotEmpty(); + } +} diff --git a/edelta.parent/edelta.ui/META-INF/MANIFEST.MF b/edelta.parent/edelta.ui/META-INF/MANIFEST.MF index 17268a00b..d00cc06cf 100644 --- a/edelta.parent/edelta.ui/META-INF/MANIFEST.MF +++ b/edelta.parent/edelta.ui/META-INF/MANIFEST.MF @@ -27,9 +27,10 @@ Require-Bundle: edelta, Import-Package: org.apache.log4j Bundle-RequiredExecutionEnvironment: JavaSE-11 Export-Package: edelta.ui.contentassist, + edelta.ui.editor, edelta.ui.internal, + edelta.ui.labeling, edelta.ui.quickfix, - edelta.ui.wizard, - edelta.ui.editor + edelta.ui.wizard Bundle-Activator: edelta.ui.internal.EdeltaActivator Automatic-Module-Name: edelta.ui