diff options
| author | pguilet | 2017-12-13 15:29:47 +0000 |
|---|---|---|
| committer | Pierre Guilet | 2018-01-22 15:04:51 +0000 |
| commit | 7020d739907f91945c4fd8537938d61777480192 (patch) | |
| tree | ab7b634de4ef40fd6728237b0ba4f22054e5fd14 | |
| parent | 0166c3c29a3b1d980e169a79129d6aae8a0a38b8 (diff) | |
| download | org.eclipse.sirius-7020d739907f91945c4fd8537938d61777480192.tar.gz org.eclipse.sirius-7020d739907f91945c4fd8537938d61777480192.tar.xz org.eclipse.sirius-7020d739907f91945c4fd8537938d61777480192.zip | |
[471900] Support quick navigation to service method implementation
Hitting F3 when cursor is on a VSM service from AQL or Service
interpreter expression will have
the following effects:
- if only one Java class contains the service, it is directly opened
with Java editor.
- if many classes contains the service, a wizard allows to choose which
one
is opened.
Bug: 471900
Change-Id: I5bb9465b71f03fde161de6dda23b206a53b67a14
Signed-off-by: pguilet <pierre.guilet@obeo.fr>
23 files changed, 1265 insertions, 55 deletions
diff --git a/plugins/org.eclipse.sirius.common.acceleo.aql/META-INF/MANIFEST.MF b/plugins/org.eclipse.sirius.common.acceleo.aql/META-INF/MANIFEST.MF index 90403fe726..a7824e33b4 100644 --- a/plugins/org.eclipse.sirius.common.acceleo.aql/META-INF/MANIFEST.MF +++ b/plugins/org.eclipse.sirius.common.acceleo.aql/META-INF/MANIFEST.MF @@ -18,5 +18,6 @@ Export-Package: org.eclipse.sirius.common.acceleo.aql.business;version="3.0.0", org.eclipse.sirius.common.acceleo.aql.business.internal;x-internal:=true;version="3.0.0" Bundle-ActivationPolicy: lazy Import-Package: org.eclipse.acceleo.query.runtime;version="[5.0.0,6.0.0)", + org.eclipse.acceleo.query.runtime.impl, org.eclipse.acceleo.query.validation.type;version="[5.0.0,6.0.0)" Bundle-Localization: plugin diff --git a/plugins/org.eclipse.sirius.common.acceleo.aql/src/org/eclipse/sirius/common/acceleo/aql/business/internal/AQLSiriusInterpreter.java b/plugins/org.eclipse.sirius.common.acceleo.aql/src/org/eclipse/sirius/common/acceleo/aql/business/internal/AQLSiriusInterpreter.java index b838287163..af4c17fc0b 100644 --- a/plugins/org.eclipse.sirius.common.acceleo.aql/src/org/eclipse/sirius/common/acceleo/aql/business/internal/AQLSiriusInterpreter.java +++ b/plugins/org.eclipse.sirius.common.acceleo.aql/src/org/eclipse/sirius/common/acceleo/aql/business/internal/AQLSiriusInterpreter.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2015, 2016 Obeo. + * Copyright (c) 2015, 2017 Obeo. * 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 @@ -10,6 +10,7 @@ *******************************************************************************/ package org.eclipse.sirius.common.acceleo.aql.business.internal; +import java.lang.reflect.Method; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collection; @@ -39,6 +40,7 @@ import org.eclipse.acceleo.query.runtime.QueryParsing; import org.eclipse.acceleo.query.runtime.QueryValidation; import org.eclipse.acceleo.query.runtime.ServiceUtils; import org.eclipse.acceleo.query.runtime.ValidationMessageLevel; +import org.eclipse.acceleo.query.runtime.impl.JavaMethodService; import org.eclipse.acceleo.query.validation.type.ClassType; import org.eclipse.acceleo.query.validation.type.EClassifierType; import org.eclipse.acceleo.query.validation.type.ICollectionType; @@ -65,6 +67,7 @@ import org.eclipse.sirius.common.tools.api.interpreter.EPackageLoadingCallback; import org.eclipse.sirius.common.tools.api.interpreter.EvaluationException; import org.eclipse.sirius.common.tools.api.interpreter.IInterpreterContext; import org.eclipse.sirius.common.tools.api.interpreter.IInterpreterStatus; +import org.eclipse.sirius.common.tools.api.interpreter.IJavaAwareInterpreter; import org.eclipse.sirius.common.tools.api.interpreter.InterpreterStatusFactory; import org.eclipse.sirius.common.tools.api.interpreter.ValidationResult; import org.eclipse.sirius.common.tools.api.interpreter.VariableType; @@ -77,12 +80,12 @@ import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; /** - * A Sirius interpreter using the Acceleo Query Language. It only supports - * expressions which are not using implicit variables. + * A Sirius interpreter using the Acceleo Query Language. It only supports expressions which are not using implicit + * variables. * * @author cedric */ -public class AQLSiriusInterpreter extends AcceleoAbstractInterpreter { +public class AQLSiriusInterpreter extends AcceleoAbstractInterpreter implements IJavaAwareInterpreter { private LoadingCache<String, AstResult> parsedExpressions; @@ -314,11 +317,9 @@ public class AQLSiriusInterpreter extends AcceleoAbstractInterpreter { for (IType type : aqlValidationResult.getPossibleTypes(aqlValidationResult.getAstResult().getAst())) { IType actualType = type; /* - * Sirius has no notion of "multiple" or "collection" type in - * its typesystem and will unwrap the collection when using its - * result as the root of a new expression. It seems better to - * return the type information than hide which leads to a - * fall-back to EObject. + * Sirius has no notion of "multiple" or "collection" type in its typesystem and will unwrap the + * collection when using its result as the root of a new expression. It seems better to return the type + * information than hide which leads to a fall-back to EObject. */ if (type instanceof ICollectionType) { actualType = ((ICollectionType) type).getCollectionType(); @@ -354,6 +355,20 @@ public class AQLSiriusInterpreter extends AcceleoAbstractInterpreter { return result; } + @Override + public Collection<Method> getImplementation(String serviceCall) { + javaExtensions.reloadIfNeeded(); + Set<org.eclipse.acceleo.query.runtime.IService> registeredServices = queryEnvironment.getLookupEngine().getRegisteredServices(); + List<Method> results = new ArrayList<Method>(); + registeredServices.iterator().forEachRemaining(s -> { + if (s instanceof JavaMethodService) { + results.add(((JavaMethodService) s).getMethod()); + } + }); + + return results; + } + /** * return the cross reference provider used by this interpreter instance. * @@ -380,10 +395,8 @@ public class AQLSiriusInterpreter extends AcceleoAbstractInterpreter { */ public IQueryEnvironment getQueryEnvironment() { /* - * The JavaExtensionManager might impact the query environment when - * loading classes. We trigger the reload before returning the - * IQueryEnvironment so that it is properly configured with EPackages - * and imports. + * The JavaExtensionManager might impact the query environment when loading classes. We trigger the reload + * before returning the IQueryEnvironment so that it is properly configured with EPackages and imports. */ this.javaExtensions.reloadIfNeeded(); diff --git a/plugins/org.eclipse.sirius.common/src/org/eclipse/sirius/common/tools/api/interpreter/IJavaAwareInterpreter.java b/plugins/org.eclipse.sirius.common/src/org/eclipse/sirius/common/tools/api/interpreter/IJavaAwareInterpreter.java new file mode 100644 index 0000000000..5668f38d8d --- /dev/null +++ b/plugins/org.eclipse.sirius.common/src/org/eclipse/sirius/common/tools/api/interpreter/IJavaAwareInterpreter.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2017 Obeo + * 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: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.common.tools.api.interpreter; + +import java.lang.reflect.Method; +import java.util.Collection; + +/** + * Interface used by interpreters capable of interpreting JAVA services. + * + * @author <a href="mailto:pierre.guilet@obeo.fr">Pierre Guilet</a> + * + */ +public interface IJavaAwareInterpreter { + /** + * Returns the concrete methods which implement the service identified by the given expression. + * + * @param serviceCall + * the service call from which we want to extract corresponding {@link Method} if such elements exist. + * @return the concrete methods which implement the service identified by the given expression. An empty list if no + * such element exists. + */ + Collection<Method> getImplementation(String serviceCall); +} diff --git a/plugins/org.eclipse.sirius.common/src/org/eclipse/sirius/common/tools/internal/interpreter/IService.java b/plugins/org.eclipse.sirius.common/src/org/eclipse/sirius/common/tools/internal/interpreter/IService.java index a432b3e779..551ddd8433 100644 --- a/plugins/org.eclipse.sirius.common/src/org/eclipse/sirius/common/tools/internal/interpreter/IService.java +++ b/plugins/org.eclipse.sirius.common/src/org/eclipse/sirius/common/tools/internal/interpreter/IService.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2013 THALES GLOBAL SERVICES. + * Copyright (c) 2013, 2017 THALES GLOBAL SERVICES. * 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 @@ -10,6 +10,9 @@ *******************************************************************************/ package org.eclipse.sirius.common.tools.internal.interpreter; +import java.lang.reflect.Method; +import java.util.Collection; + import org.eclipse.sirius.common.tools.api.interpreter.EvaluationException; /** @@ -30,8 +33,7 @@ public interface IService { * * @param target * a potential target object on which to invoke the service. - * @return <code>true</code> iff this service can be invoked on the - * specified target object. + * @return <code>true</code> iff this service can be invoked on the specified target object. */ boolean appliesTo(Object[] target); @@ -45,4 +47,11 @@ public interface IService { * if an error occurred during the invocation of the service. */ Object call(Object[] target) throws EvaluationException; + + /** + * Returns the concrete methods which implement this service. + * + * @return the concrete methods which implement this service. + */ + Collection<Method> getImplementations(); } diff --git a/plugins/org.eclipse.sirius.common/src/org/eclipse/sirius/common/tools/internal/interpreter/MonomorphicService.java b/plugins/org.eclipse.sirius.common/src/org/eclipse/sirius/common/tools/internal/interpreter/MonomorphicService.java index e10af9c201..9120edbc37 100644 --- a/plugins/org.eclipse.sirius.common/src/org/eclipse/sirius/common/tools/internal/interpreter/MonomorphicService.java +++ b/plugins/org.eclipse.sirius.common/src/org/eclipse/sirius/common/tools/internal/interpreter/MonomorphicService.java @@ -14,6 +14,8 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.text.MessageFormat; import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.List; import org.eclipse.sirius.common.tools.Messages; @@ -44,6 +46,7 @@ class MonomorphicService implements IMonomorphicService { Preconditions.checkArgument(ServiceInterpreter.isValidServiceMethod(serviceMethod)); } + @Override public String getName() { return serviceMethod.getName(); } @@ -65,6 +68,7 @@ class MonomorphicService implements IMonomorphicService { return apply; } + @Override public Object call(Object[] target) throws EvaluationException { Object result = null; try { @@ -105,4 +109,9 @@ class MonomorphicService implements IMonomorphicService { return parametersTypes; } + @Override + public Collection<Method> getImplementations() { + return Collections.singleton(this.serviceMethod); + } + } diff --git a/plugins/org.eclipse.sirius.common/src/org/eclipse/sirius/common/tools/internal/interpreter/PolymorphicService.java b/plugins/org.eclipse.sirius.common/src/org/eclipse/sirius/common/tools/internal/interpreter/PolymorphicService.java index 599c0e37f8..8260f5e080 100644 --- a/plugins/org.eclipse.sirius.common/src/org/eclipse/sirius/common/tools/internal/interpreter/PolymorphicService.java +++ b/plugins/org.eclipse.sirius.common/src/org/eclipse/sirius/common/tools/internal/interpreter/PolymorphicService.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2013 THALES GLOBAL SERVICES. + * Copyright (c) 2013, 2017 THALES GLOBAL SERVICES. * 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 @@ -10,7 +10,9 @@ *******************************************************************************/ package org.eclipse.sirius.common.tools.internal.interpreter; +import java.lang.reflect.Method; import java.text.MessageFormat; +import java.util.Collection; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; @@ -24,8 +26,8 @@ import com.google.common.collect.Iterables; import com.google.common.collect.Lists; /** - * A service which corresponds to more than one Java method. Which of the - * methods will actually be invoked will depend on the target object. + * A service which corresponds to more than one Java method. Which of the methods will actually be invoked will depend + * on the target object. * * @author pcdavid */ @@ -83,4 +85,13 @@ class PolymorphicService implements IPolymorphicService { public Set<IMonomorphicService> getImplementers() { return implementers; } + + @Override + public Collection<Method> getImplementations() { + Collection<Method> result = Lists.newArrayList(); + for (IMonomorphicService svc : this.implementers) { + result.addAll(svc.getImplementations()); + } + return result; + } } diff --git a/plugins/org.eclipse.sirius.common/src/org/eclipse/sirius/common/tools/internal/interpreter/ServiceInterpreter.java b/plugins/org.eclipse.sirius.common/src/org/eclipse/sirius/common/tools/internal/interpreter/ServiceInterpreter.java index 5b3f5b97a3..f924d4bf43 100644 --- a/plugins/org.eclipse.sirius.common/src/org/eclipse/sirius/common/tools/internal/interpreter/ServiceInterpreter.java +++ b/plugins/org.eclipse.sirius.common/src/org/eclipse/sirius/common/tools/internal/interpreter/ServiceInterpreter.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2013 THALES GLOBAL SERVICES. + * Copyright (c) 2013, 2017 THALES GLOBAL SERVICES. * 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 @@ -14,6 +14,7 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.text.MessageFormat; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.regex.Pattern; @@ -26,6 +27,7 @@ import org.eclipse.sirius.common.tools.api.interpreter.EvaluationException; import org.eclipse.sirius.common.tools.api.interpreter.IInterpreter; import org.eclipse.sirius.common.tools.api.interpreter.IInterpreterContext; import org.eclipse.sirius.common.tools.api.interpreter.IInterpreterProvider; +import org.eclipse.sirius.common.tools.api.interpreter.IJavaAwareInterpreter; import org.eclipse.sirius.common.tools.api.interpreter.JavaExtensionsManager; import org.eclipse.sirius.common.tools.api.interpreter.ValidationResult; import org.eclipse.sirius.ext.base.Option; @@ -35,12 +37,11 @@ import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; /** - * A specialized interpreter which can only directly invoke Java service - * methods. + * A specialized interpreter which can only directly invoke Java service methods. * * @author pcdavid */ -public class ServiceInterpreter extends VariableInterpreter implements org.eclipse.sirius.common.tools.api.interpreter.IInterpreter, IInterpreterProvider { +public class ServiceInterpreter extends VariableInterpreter implements IJavaAwareInterpreter, org.eclipse.sirius.common.tools.api.interpreter.IInterpreter, IInterpreterProvider { /** The Service interpreter prefix. */ public static final String PREFIX = "service:"; //$NON-NLS-1$ @@ -59,8 +60,7 @@ public class ServiceInterpreter extends VariableInterpreter implements org.eclip private final Map<String, PolymorphicService> services = new HashMap<>(); /** - * Used to retrieve the services instances we create so that we can - * un-register those. + * Used to retrieve the services instances we create so that we can un-register those. */ private final Multimap<String, PolymorphicService> qualifiedNameToServices = HashMultimap.create(); @@ -135,7 +135,8 @@ public class ServiceInterpreter extends VariableInterpreter implements org.eclip if (objectReceiver instanceof EObject) { receiver = (EObject) objectReceiver; } else { - throw new EvaluationException(MessageFormat.format(Messages.ServiceInterpreter_invalidReceiver, serviceCall, objectReceiver != null ? objectReceiver.getClass().getName() : "null")); //$NON-NLS-1$ + throw new EvaluationException( + MessageFormat.format(Messages.ServiceInterpreter_invalidReceiver, serviceCall, objectReceiver != null ? objectReceiver.getClass().getName() : "null")); //$NON-NLS-1$ } } int indexOfParenthesis = serviceCall.indexOf("("); //$NON-NLS-1$ @@ -166,6 +167,19 @@ public class ServiceInterpreter extends VariableInterpreter implements org.eclip } @Override + public Collection<Method> getImplementation(String serviceCall) { + javaExtensions.reloadIfNeeded(); + String serviceName = serviceCall; + + if (services.containsKey(serviceName)) { + IService service = services.get(serviceName); + return service.getImplementations(); + } + + return Collections.emptyList(); + } + + @Override public void addImport(String dependency) { javaExtensions.addImport(dependency); } @@ -202,8 +216,7 @@ public class ServiceInterpreter extends VariableInterpreter implements org.eclip } /** - * Checks whether a Java method can be used as a service (in the sense of - * this interpreter). + * Checks whether a Java method can be used as a service (in the sense of this interpreter). * * @param m * the method to test. @@ -261,9 +274,8 @@ public class ServiceInterpreter extends VariableInterpreter implements org.eclip */ public Map<String, IService> getServices() { /* - * The callback registered to the java extension manager might update - * this.services depending on what is loaded. We make sure any pending - * reload is done before returning this list. + * The callback registered to the java extension manager might update this.services depending on what is loaded. + * We make sure any pending reload is done before returning this list. */ javaExtensions.reloadIfNeeded(); diff --git a/plugins/org.eclipse.sirius.diagram/src/org/eclipse/sirius/diagram/Messages.java b/plugins/org.eclipse.sirius.diagram/src/org/eclipse/sirius/diagram/Messages.java index e1bebc3315..05cbab665c 100644 --- a/plugins/org.eclipse.sirius.diagram/src/org/eclipse/sirius/diagram/Messages.java +++ b/plugins/org.eclipse.sirius.diagram/src/org/eclipse/sirius/diagram/Messages.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2015 Obeo. + * Copyright (c) 2015, 2017 Obeo. * 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 diff --git a/plugins/org.eclipse.sirius.editor.diagram/src-gen/org/eclipse/sirius/diagram/editor/properties/sections/description/diagramdescription/DiagramDescriptionPreconditionExpressionPropertySection.java b/plugins/org.eclipse.sirius.editor.diagram/src-gen/org/eclipse/sirius/diagram/editor/properties/sections/description/diagramdescription/DiagramDescriptionPreconditionExpressionPropertySection.java index cb1c833b3e..042e47804d 100644 --- a/plugins/org.eclipse.sirius.editor.diagram/src-gen/org/eclipse/sirius/diagram/editor/properties/sections/description/diagramdescription/DiagramDescriptionPreconditionExpressionPropertySection.java +++ b/plugins/org.eclipse.sirius.editor.diagram/src-gen/org/eclipse/sirius/diagram/editor/properties/sections/description/diagramdescription/DiagramDescriptionPreconditionExpressionPropertySection.java @@ -14,6 +14,7 @@ package org.eclipse.sirius.diagram.editor.properties.sections.description.diagra import org.eclipse.emf.ecore.EAttribute; import org.eclipse.sirius.diagram.description.DescriptionPackage; import org.eclipse.sirius.editor.editorPlugin.SiriusEditor; +import org.eclipse.sirius.editor.internal.navigation.NavigationByKeyListener; import org.eclipse.sirius.editor.properties.sections.common.AbstractTextWithButtonPropertySection; import org.eclipse.sirius.editor.tools.api.assist.TypeContentProposalProvider; import org.eclipse.sirius.editor.tools.internal.presentation.TextWithContentProposalDialog; @@ -41,6 +42,7 @@ public class DiagramDescriptionPreconditionExpressionPropertySection extends Abs /** * @see org.eclipse.ui.views.properties.tabbed.view.ITabbedPropertySection#refresh() */ + @Override public void refresh() { super.refresh(); @@ -53,6 +55,7 @@ public class DiagramDescriptionPreconditionExpressionPropertySection extends Abs /** * @see org.eclipse.sirius.diagram.editor.properties.sections.AbstractTextWithButtonPropertySection#getDefaultLabelText() */ + @Override protected String getDefaultLabelText() { return "PreconditionExpression"; //$NON-NLS-1$ } @@ -60,6 +63,7 @@ public class DiagramDescriptionPreconditionExpressionPropertySection extends Abs /** * @see org.eclipse.sirius.diagram.editor.properties.sections.AbstractTextWithButtonPropertySection#getLabelText() */ + @Override protected String getLabelText() { String labelText; labelText = super.getLabelText() + ":"; //$NON-NLS-1$ @@ -72,6 +76,7 @@ public class DiagramDescriptionPreconditionExpressionPropertySection extends Abs /** * @see org.eclipse.sirius.diagram.editor.properties.sections.AbstractTextWithButtonPropertySection#getFeature() */ + @Override public EAttribute getFeature() { return DescriptionPackage.eINSTANCE.getDiagramDescription_PreconditionExpression(); } @@ -79,6 +84,7 @@ public class DiagramDescriptionPreconditionExpressionPropertySection extends Abs /** * @see org.eclipse.sirius.diagram.editor.properties.sections.AbstractTextWithButtonPropertySection#getFeatureValue(String) */ + @Override protected Object getFeatureValue(String newText) { return newText; } @@ -86,6 +92,7 @@ public class DiagramDescriptionPreconditionExpressionPropertySection extends Abs /** * @see org.eclipse.sirius.diagram.editor.properties.sections.AbstractTextWithButtonPropertySection#isEqual(String) */ + @Override protected boolean isEqual(String newText) { return getFeatureAsText().equals(newText); } @@ -93,6 +100,7 @@ public class DiagramDescriptionPreconditionExpressionPropertySection extends Abs /** * {@inheritDoc} */ + @Override public void createControls(Composite parent, TabbedPropertySheetPage tabbedPropertySheetPage) { super.createControls(parent, tabbedPropertySheetPage); /* @@ -111,6 +119,7 @@ public class DiagramDescriptionPreconditionExpressionPropertySection extends Abs help.setToolTipText(getToolTipText()); TypeContentProposalProvider.bindPluginsCompletionProcessors(this, text); + text.addKeyListener(new NavigationByKeyListener(this, text, eObject)); // Start of user code create controls @@ -121,6 +130,7 @@ public class DiagramDescriptionPreconditionExpressionPropertySection extends Abs @Override protected SelectionListener createButtonListener() { return new SelectionAdapter() { + @Override public void widgetSelected(SelectionEvent e) { TextWithContentProposalDialog dialog = new TextWithContentProposalDialog(composite.getShell(), DiagramDescriptionPreconditionExpressionPropertySection.this, text.getText()); dialog.open(); @@ -133,6 +143,7 @@ public class DiagramDescriptionPreconditionExpressionPropertySection extends Abs /** * {@inheritDoc} */ + @Override protected String getPropertyDescription() { return "The precondition is an expression preventing the creation of a diagram.\n If the precondition is set and the expression returns false on the root diagram\n element, then the diagram won't be created."; } diff --git a/plugins/org.eclipse.sirius.editor/META-INF/MANIFEST.MF b/plugins/org.eclipse.sirius.editor/META-INF/MANIFEST.MF index f2050684bd..871dba130d 100644 --- a/plugins/org.eclipse.sirius.editor/META-INF/MANIFEST.MF +++ b/plugins/org.eclipse.sirius.editor/META-INF/MANIFEST.MF @@ -22,11 +22,14 @@ Require-Bundle: org.eclipse.ui.views.properties.tabbed;bundle-version="3.5.300", org.eclipse.pde.core;bundle-version="3.8.1", org.eclipse.emf.edit.ui;bundle-version="2.8.0", org.eclipse.acceleo.ui.interpreter;bundle-version="3.7.1", - org.eclipse.jdt.core;bundle-version="3.12.3" + org.eclipse.jdt.core;bundle-version="3.12.3", + org.eclipse.jdt.ui;bundle-version="3.12.2" Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Eclipse-LazyStart: true -Export-Package: org.eclipse.sirius.editor.assist.content;version="2.0.4", +Export-Package: org.eclipse.sirius.editor;version="6.0.0", + org.eclipse.sirius.editor.assist.content;version="2.0.4", org.eclipse.sirius.editor.editorPlugin;version="2.1.0", + org.eclipse.sirius.editor.internal.navigation;version="6.0.0";x-internal:=true, org.eclipse.sirius.editor.properties;version="2.0.4", org.eclipse.sirius.editor.properties.filters.audit.templateinformationsection;version="2.0.4", org.eclipse.sirius.editor.properties.filters.common;version="2.0.4", @@ -194,22 +197,22 @@ Export-Package: org.eclipse.sirius.editor.assist.content;version="2.0.4", org.eclipse.sirius.editor.tools.api.editor;version="2.0.4", org.eclipse.sirius.editor.tools.api.menu;version="2.1.0", org.eclipse.sirius.editor.tools.api.perspectives;version="2.0.4", - org.eclipse.sirius.editor.tools.internal.actions;x-internal:=true;version="2.0.4", - org.eclipse.sirius.editor.tools.internal.assist;x-internal:=true;version="2.0.4", - org.eclipse.sirius.editor.tools.internal.color;x-internal:=true;version="2.0.4", - org.eclipse.sirius.editor.tools.internal.commands;x-internal:=true;version="3.0.0", - org.eclipse.sirius.editor.tools.internal.editor;x-internal:=true;version="2.0.4", - org.eclipse.sirius.editor.tools.internal.marker;x-internal:=true;version="2.0.4", - org.eclipse.sirius.editor.tools.internal.menu;x-internal:=true;version="2.1.0", - org.eclipse.sirius.editor.tools.internal.menu.child;x-internal:=true;version="2.1.0", - org.eclipse.sirius.editor.tools.internal.menu.refactoring;x-internal:=true;version="2.1.0", - org.eclipse.sirius.editor.tools.internal.menu.refactoring.border;x-internal:=true;version="2.0.4", - org.eclipse.sirius.editor.tools.internal.outline;x-internal:=true;version="3.0.0", - org.eclipse.sirius.editor.tools.internal.perspectives;x-internal:=true;version="2.0.4", - org.eclipse.sirius.editor.tools.internal.presentation;x-internal:=true;version="2.1.0", - org.eclipse.sirius.editor.tools.internal.property.filter;x-internal:=true;version="2.0.4", - org.eclipse.sirius.editor.tools.internal.property.section;x-internal:=true;version="2.0.4", - org.eclipse.sirius.editor.tools.internal.wizards;x-internal:=true;version="2.0.4", + org.eclipse.sirius.editor.tools.internal.actions;version="2.0.4";x-internal:=true, + org.eclipse.sirius.editor.tools.internal.assist;version="2.0.4";x-internal:=true, + org.eclipse.sirius.editor.tools.internal.color;version="2.0.4";x-internal:=true, + org.eclipse.sirius.editor.tools.internal.commands;version="3.0.0";x-internal:=true, + org.eclipse.sirius.editor.tools.internal.editor;version="2.0.4";x-internal:=true, + org.eclipse.sirius.editor.tools.internal.marker;version="2.0.4";x-internal:=true, + org.eclipse.sirius.editor.tools.internal.menu;version="2.1.0";x-internal:=true, + org.eclipse.sirius.editor.tools.internal.menu.child;version="2.1.0";x-internal:=true, + org.eclipse.sirius.editor.tools.internal.menu.refactoring;version="2.1.0";x-internal:=true, + org.eclipse.sirius.editor.tools.internal.menu.refactoring.border;version="2.0.4";x-internal:=true, + org.eclipse.sirius.editor.tools.internal.outline;version="3.0.0";x-internal:=true, + org.eclipse.sirius.editor.tools.internal.perspectives;version="2.0.4";x-internal:=true, + org.eclipse.sirius.editor.tools.internal.presentation;version="2.1.0";x-internal:=true, + org.eclipse.sirius.editor.tools.internal.property.filter;version="2.0.4";x-internal:=true, + org.eclipse.sirius.editor.tools.internal.property.section;version="2.0.4";x-internal:=true, + org.eclipse.sirius.editor.tools.internal.wizards;version="2.0.4";x-internal:=true, org.eclipse.sirius.editor.utils;version="2.1.0", org.eclipse.sirius.editor.wizards;version="2.0.4" Bundle-ActivationPolicy: lazy diff --git a/plugins/org.eclipse.sirius.editor/plugin.properties b/plugins/org.eclipse.sirius.editor/plugin.properties index cfce8dbe52..91fb0c7c43 100644 --- a/plugins/org.eclipse.sirius.editor/plugin.properties +++ b/plugins/org.eclipse.sirius.editor/plugin.properties @@ -362,4 +362,7 @@ properties.TextWidgetConditionalStyle = 2000 properties.TextWidgetStyle = 1000 properties.WidgetStyle = 1000 +ServiceNavigator_targetInitialization_error=The service from expression {0} could not be opened with a Java editor. Make sure the service exists and its class is defined in the VSM as Java extension. +ServiceNavigator_serviceNavigationDialog_title=Service navigation +ServiceNavigator_serviceNavigationDialog_description=Select the class containing the service to edit. #End of user code specific keys diff --git a/plugins/org.eclipse.sirius.editor/src-gen/org/eclipse/sirius/editor/editorPlugin/SiriusEditorPlugin.java b/plugins/org.eclipse.sirius.editor/src-gen/org/eclipse/sirius/editor/editorPlugin/SiriusEditorPlugin.java index 22346c5a11..1d0d210cc0 100644 --- a/plugins/org.eclipse.sirius.editor/src-gen/org/eclipse/sirius/editor/editorPlugin/SiriusEditorPlugin.java +++ b/plugins/org.eclipse.sirius.editor/src-gen/org/eclipse/sirius/editor/editorPlugin/SiriusEditorPlugin.java @@ -1,9 +1,10 @@ /******************************************************************************* - * Copyright (c) 2007, 2013 THALES GLOBAL SERVICES. + * Copyright (c) 2007, 2017 THALES GLOBAL SERVICES. * 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: * Obeo - initial API and implementation *******************************************************************************/ @@ -14,6 +15,7 @@ import java.util.LinkedHashSet; // Start of user code imports import java.util.Set; +import java.util.function.Supplier; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.emf.common.EMFPlugin; @@ -22,6 +24,9 @@ import org.eclipse.emf.common.util.ResourceLocator; import org.eclipse.emf.ecore.EPackage.Registry; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.resource.ImageRegistry; +import org.eclipse.sirius.editor.internal.navigation.INavigatorFromVSMExpression; +import org.eclipse.sirius.editor.internal.navigation.NavigationFromVSMExpressionRegistry; +import org.eclipse.sirius.editor.internal.navigation.ServiceNavigator; import org.eclipse.sirius.editor.tools.api.ecore.WorkspaceEPackageRegistry; import org.eclipse.swt.SWT; import org.eclipse.swt.SWTError; @@ -79,6 +84,7 @@ public final class SiriusEditorPlugin extends EMFPlugin { * * @return the singleton instance. */ + @Override public ResourceLocator getPluginResourceLocator() { return plugin; } @@ -184,6 +190,7 @@ public final class SiriusEditorPlugin extends EMFPlugin { * The actual implementation of the Eclipse <b>Plugin</b>. */ public static class Implementation extends EclipseUIPlugin { + /** * Creates an instance. */ @@ -196,6 +203,11 @@ public final class SiriusEditorPlugin extends EMFPlugin { } // Start of user code Implementation specifics + /** + * The {@link NavigationFromVSMExpressionRegistry} allowing to navigate to JAVA implementation from VSM expressions. + */ + private NavigationFromVSMExpressionRegistry navigationRegistry; + @Override public void start(BundleContext context) throws Exception { super.start(context); @@ -208,6 +220,14 @@ public final class SiriusEditorPlugin extends EMFPlugin { } } } + navigationRegistry = new NavigationFromVSMExpressionRegistry(); + Supplier<INavigatorFromVSMExpression> serviceNavigatorSupplier = new Supplier<INavigatorFromVSMExpression>() { + @Override + public INavigatorFromVSMExpression get() { + return new ServiceNavigator(); + } + }; + navigationRegistry.addNavigator(serviceNavigatorSupplier); } @Override @@ -217,6 +237,16 @@ public final class SiriusEditorPlugin extends EMFPlugin { workspaceEPackageRegistry.dispose(ResourcesPlugin.getWorkspace()); } workspaceEPackageRegistry = null; + navigationRegistry = null; + } + + /** + * Returns the {@link NavigationFromVSMExpressionRegistry} allowing to navigate to JAVA implementation from VSM expressions. + * + * @return the {@link NavigationFromVSMExpressionRegistry} allowing to navigate to JAVA implementation from VSM expressions. + */ + public NavigationFromVSMExpressionRegistry getNavigationRegistry() { + return navigationRegistry; } /** diff --git a/plugins/org.eclipse.sirius.editor/src/org/eclipse/sirius/editor/Messages.java b/plugins/org.eclipse.sirius.editor/src/org/eclipse/sirius/editor/Messages.java new file mode 100644 index 0000000000..7abeb9863a --- /dev/null +++ b/plugins/org.eclipse.sirius.editor/src/org/eclipse/sirius/editor/Messages.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2015, 2017 Obeo. + * 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: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.editor; + +import org.eclipse.sirius.editor.editorPlugin.SiriusEditorPlugin; +import org.eclipse.sirius.ext.base.I18N; +import org.eclipse.sirius.ext.base.I18N.TranslatableMessage; + +/** + * Helper class to obtains translated strings. + * + * @author Florian Barbin + * + */ +public final class Messages { + static { + I18N.initializeMessages(Messages.class, SiriusEditorPlugin.INSTANCE); + } + + // CHECKSTYLE:OFF + + @TranslatableMessage + public static String ServiceNavigator_targetInitialization_error; + + @TranslatableMessage + public static String ServiceNavigator_serviceNavigationDialog_title; + + @TranslatableMessage + public static String ServiceNavigator_serviceNavigationDialog_description; + + // CHECKSTYLE:ON + private Messages() { + // Prevents instanciation. + } +} diff --git a/plugins/org.eclipse.sirius.editor/src/org/eclipse/sirius/editor/internal/navigation/INavigatorFromVSMExpression.java b/plugins/org.eclipse.sirius.editor/src/org/eclipse/sirius/editor/internal/navigation/INavigatorFromVSMExpression.java new file mode 100644 index 0000000000..ccad9b9e58 --- /dev/null +++ b/plugins/org.eclipse.sirius.editor/src/org/eclipse/sirius/editor/internal/navigation/INavigatorFromVSMExpression.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright (c) 2017 Obeo + * 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: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.editor.internal.navigation; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.sirius.common.tools.api.contentassist.ContentContext; +import org.eclipse.sirius.common.tools.api.interpreter.IInterpreterContext; +import org.eclipse.sirius.editor.properties.sections.common.AbstractViewpointPropertySection; + +/** + * An {@link INavigatorFromVSMExpression} allows to navigate to any location from VSM expression content. + * + * @author <a href="mailto:pierre.guilet@obeo.fr">Pierre Guilet</a> + * + */ +public interface INavigatorFromVSMExpression { + /** + * Returns true if this navigator handles navigation from given expression and cursor position. + * + * @param propertySection + * the property section containing the VSM expression. + * + * @param targetEObject + * the {@link EObject} containing the expression from which we want to know if a navigation is available. + * @param contentContext + * the {@link ContentContext} containing the expression, the cursor position and the + * {@link IInterpreterContext}. + * @return true if this navigator handles navigation from given expression and cursor position. False otherwise. + */ + boolean doProvideNavigationFor(AbstractViewpointPropertySection propertySection, EObject targetEObject, ContentContext contentContext); + + /** + * Triggers the navigation provided by this navigator from given information. + * + * @param propertySection + * the property section containing the VSM expression. + * + * @param targetEObject + * the {@link EObject} containing the expression from which we want to know if a navigation is available. + * @param contentContext + * the {@link ContentContext} containing the expression, the cursor position and the + * {@link IInterpreterContext}. + */ + void triggerNavigation(AbstractViewpointPropertySection propertySection, EObject targetEObject, ContentContext contentContext); +} diff --git a/plugins/org.eclipse.sirius.editor/src/org/eclipse/sirius/editor/internal/navigation/NavigationByKeyListener.java b/plugins/org.eclipse.sirius.editor/src/org/eclipse/sirius/editor/internal/navigation/NavigationByKeyListener.java new file mode 100644 index 0000000000..7d7e77642c --- /dev/null +++ b/plugins/org.eclipse.sirius.editor/src/org/eclipse/sirius/editor/internal/navigation/NavigationByKeyListener.java @@ -0,0 +1,89 @@ +/******************************************************************************* + * Copyright (c) 2017 Obeo + * 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: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.editor.internal.navigation; + +import java.util.Set; +import java.util.function.Supplier; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.sirius.common.tools.api.contentassist.ContentContext; +import org.eclipse.sirius.common.tools.api.interpreter.IInterpreterContext; +import org.eclipse.sirius.editor.editorPlugin.SiriusEditorPlugin; +import org.eclipse.sirius.editor.properties.sections.common.AbstractViewpointPropertySection; +import org.eclipse.sirius.tools.api.interpreter.context.SiriusInterpreterContextFactory; +import org.eclipse.sirius.ui.tools.api.assist.ContentProposalClient; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.events.KeyListener; +import org.eclipse.swt.widgets.Text; + +/** + * Listen to F3 key hit when the cursor has focus on VSM expression and propagate the event to + * {@link INavigatorFromVSMExpression} of the current {@link NavigationFromVSMExpressionRegistry}. + * + * @author <a href="mailto:pierre.guilet@obeo.fr">Pierre Guilet</a> + * + */ +public class NavigationByKeyListener implements KeyListener { + + /** + * The VSM object edited. + */ + private EObject targetObject; + + /** + * The text widget inside the property section that contains the expression string. + */ + private Text textWidget; + + /** + * The property section displaying the VSM expression. + */ + private AbstractViewpointPropertySection propertySection; + + /** + * Constructor. + * + * @param propertySection + * the property section containing the VSM expression. + * @param textWidget + * the widget containing the VSM expression. + * @param targetObject + * the {@link EObject} containing the VSM expression. + */ + public NavigationByKeyListener(AbstractViewpointPropertySection propertySection, Text textWidget, EObject targetObject) { + this.targetObject = targetObject; + this.textWidget = textWidget; + this.propertySection = propertySection; + } + + @Override + public void keyPressed(KeyEvent e) { + if (e.keyCode == SWT.F3) { + NavigationFromVSMExpressionRegistry navigationRegistry = SiriusEditorPlugin.getPlugin().getNavigationRegistry(); + Set<Supplier<INavigatorFromVSMExpression>> navigators = navigationRegistry.getNavigators(); + for (Supplier<INavigatorFromVSMExpression> navigatorSupplier : navigators) { + INavigatorFromVSMExpression navigator = navigatorSupplier.get(); + IInterpreterContext interContext = SiriusInterpreterContextFactory.createInterpreterContext(targetObject, ((ContentProposalClient) propertySection).getFeature()); + ContentContext contentContext = new ContentContext(textWidget.getText(), textWidget.getCaretPosition(), interContext); + if (navigator.doProvideNavigationFor(propertySection, targetObject, contentContext)) { + navigator.triggerNavigation(propertySection, targetObject, contentContext); + } + } + } + } + + @Override + public void keyReleased(KeyEvent e) { + // not used + } + +} diff --git a/plugins/org.eclipse.sirius.editor/src/org/eclipse/sirius/editor/internal/navigation/NavigationFromVSMExpressionRegistry.java b/plugins/org.eclipse.sirius.editor/src/org/eclipse/sirius/editor/internal/navigation/NavigationFromVSMExpressionRegistry.java new file mode 100644 index 0000000000..a5dcec22c5 --- /dev/null +++ b/plugins/org.eclipse.sirius.editor/src/org/eclipse/sirius/editor/internal/navigation/NavigationFromVSMExpressionRegistry.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright (c) 2017 Obeo + * 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: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.editor.internal.navigation; + +import java.util.HashSet; +import java.util.Set; +import java.util.function.Supplier; + +/** + * A registry containing {@link INavigatorFromVSMExpression} allowing to navigate from VSM expression content to another location. + * + * @author <a href="mailto:pierre.guilet@obeo.fr">Pierre Guilet</a> + * + */ +public class NavigationFromVSMExpressionRegistry { + + /** + * All the registered {@link INavigatorFromVSMExpression}. + */ + private Set<Supplier<INavigatorFromVSMExpression>> navigators; + + /** + * Constructor. + */ + public NavigationFromVSMExpressionRegistry() { + navigators = new HashSet<>(); + } + + /** + * Returns all {@link INavigatorFromVSMExpression} registered. + * + * @return all {@link INavigatorFromVSMExpression} registered + */ + public Set<Supplier<INavigatorFromVSMExpression>> getNavigators() { + return navigators; + } + + /** + * Add a new {@link INavigatorFromVSMExpression} to the registry. + * + * @param navigator + * the {@link INavigatorFromVSMExpression} to add. + */ + public void addNavigator(Supplier<INavigatorFromVSMExpression> navigator) { + this.navigators.add(navigator); + } + +} diff --git a/plugins/org.eclipse.sirius.editor/src/org/eclipse/sirius/editor/internal/navigation/ServiceNavigator.java b/plugins/org.eclipse.sirius.editor/src/org/eclipse/sirius/editor/internal/navigation/ServiceNavigator.java new file mode 100644 index 0000000000..1295a363a9 --- /dev/null +++ b/plugins/org.eclipse.sirius.editor/src/org/eclipse/sirius/editor/internal/navigation/ServiceNavigator.java @@ -0,0 +1,289 @@ +/******************************************************************************* + * Copyright (c) 2017 Obeo + * 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: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.editor.internal.navigation; + +import java.lang.reflect.Method; +import java.text.MessageFormat; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.IMethod; +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.core.search.IJavaSearchConstants; +import org.eclipse.jdt.core.search.IJavaSearchScope; +import org.eclipse.jdt.core.search.SearchEngine; +import org.eclipse.jdt.internal.ui.dialogs.OpenTypeSelectionDialog; +import org.eclipse.jdt.ui.JavaUI; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.sirius.common.tools.api.contentassist.ContentContext; +import org.eclipse.sirius.common.tools.api.interpreter.CompoundInterpreter; +import org.eclipse.sirius.common.tools.api.interpreter.IInterpreter; +import org.eclipse.sirius.common.tools.api.interpreter.IInterpreterContext; +import org.eclipse.sirius.common.tools.api.interpreter.IJavaAwareInterpreter; +import org.eclipse.sirius.common.tools.internal.interpreter.ServiceInterpreter; +import org.eclipse.sirius.editor.Messages; +import org.eclipse.sirius.editor.editorPlugin.SiriusEditorPlugin; +import org.eclipse.sirius.editor.properties.sections.common.AbstractViewpointPropertySection; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.PlatformUI; + +import com.google.common.collect.Lists; + +/** + * This navigator opens the JAVA editor on all the classes containing the method corresponding to a service call in a + * VSM expression. If two classes contains two method with the same name, we focus on the first one after opening. + * + * @author <a href="mailto:pierre.guilet@obeo.fr">Pierre Guilet</a> + * + */ +@SuppressWarnings("restriction") +public class ServiceNavigator implements INavigatorFromVSMExpression { + /** + * The JAVA class representations containing the service used in a VSM expression and pointing out by the cursor. + */ + private Set<IJavaElement> navigationTargets; + + /** + * Initialize data structures. + */ + public ServiceNavigator() { + navigationTargets = new HashSet<>(); + } + + @Override + public void triggerNavigation(AbstractViewpointPropertySection propertySection, EObject targetEObject, ContentContext contentContext) { + try { + if (navigationTargets.isEmpty()) { + initializeNavigationTarget(propertySection, targetEObject, contentContext); + } + if (navigationTargets.size() == 1) { + JavaUI.openInEditor(navigationTargets.iterator().next()); + } else { + IJavaSearchScope javaSearchScope = SearchEngine.createJavaSearchScope(navigationTargets.toArray(new IJavaElement[0])); + OpenTypeSelectionDialog dialog = new OpenTypeSelectionDialog(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), true, PlatformUI.getWorkbench().getProgressService(), + javaSearchScope, IJavaSearchConstants.METHOD); + dialog.setTitle(Messages.ServiceNavigator_serviceNavigationDialog_title); + dialog.setMessage(Messages.ServiceNavigator_serviceNavigationDialog_description); + dialog.setInitialPattern("?"); + int result = dialog.open(); + if (result == IDialogConstants.OK_ID) { + Object[] types = dialog.getResult(); + Arrays.stream(types).forEach(type -> { + for (IJavaElement navigationTarget : navigationTargets) { + if (navigationTarget != null && navigationTarget.getParent().equals(type)) { + try { + JavaUI.openInEditor(navigationTarget); + } catch (PartInitException | JavaModelException e) { + SiriusEditorPlugin.getPlugin().getLog().log(new Status(IStatus.ERROR, SiriusEditorPlugin.PLUGIN_ID, + MessageFormat.format(Messages.ServiceNavigator_targetInitialization_error, contentContext.getContents()), e)); + } + } + } + }); + } + } + } catch (PartInitException | JavaModelException e) { + SiriusEditorPlugin.getPlugin().getLog() + .log(new Status(IStatus.ERROR, SiriusEditorPlugin.PLUGIN_ID, MessageFormat.format(Messages.ServiceNavigator_targetInitialization_error, contentContext.getContents()), e)); + } + } + + /** + * Initialize the {@link IJavaElement} list that are implementations of a same Java service call from a VSM + * expression. + * + * @param propertySection + * the property section containing the VSM expression. + * @param targetEObject + * the VSM object containing the expression from which we execute a navigation. + * @param contentContext + * the {@link ContentContext} containing the expression, the cursor position and the + * {@link IInterpreterContext}. + * @throws JavaModelException + * if the Java class containing the service cannot be retrieved as an {@link IJavaElement}. + */ + @SuppressWarnings("static-access") + private void initializeNavigationTarget(AbstractViewpointPropertySection propertySection, EObject targetEObject, ContentContext contentContext) throws JavaModelException { + String vsmExpression = contentContext.getContents(); + String serviceCallNameWithParenthesis = extractServiceCall(contentContext); + if (serviceCallNameWithParenthesis != null) { + String serviceCallName = serviceCallNameWithParenthesis; + int leftParenthesisIndex = serviceCallName.indexOf("("); + int rightParenthesisIndex = serviceCallName.indexOf(")"); + if (leftParenthesisIndex != -1) { + serviceCallName = serviceCallName.substring(0, leftParenthesisIndex); + } + serviceCallName = serviceCallName.trim(); + serviceCallName = serviceCallName.replaceAll("self.", ""); + if (serviceCallName.startsWith(ServiceInterpreter.PREFIX)) { + serviceCallName.replaceFirst(ServiceInterpreter.PREFIX, ""); + } + IInterpreter itp = CompoundInterpreter.INSTANCE.getInterpreterForExpression(vsmExpression); + if (itp instanceof IJavaAwareInterpreter) { + IInterpreterContext interpreterContext = contentContext.getInterpreterContext(); + Collection<String> imports = interpreterContext.getDependencies(); + for (String tempImport : imports) { + itp.addImport(tempImport); + } + Resource vsmResource = interpreterContext.getElement().eResource(); + if (vsmResource != null) { + itp.setProperty(IInterpreter.FILES, Lists.newArrayList(vsmResource.getURI().toPlatformString(true))); + } + Collection<Method> implementations = ((IJavaAwareInterpreter) itp).getImplementation(serviceCallName); + Iterator<Method> methodIte = implementations.iterator(); + while (methodIte.hasNext()) { + Method m = methodIte.next(); + if (m != null) { + Resource vsm = targetEObject.eResource(); + // CHECKSTYLE:OFF + if (vsm.getURI().isPlatformResource()) { + String projectName = vsm.getURI().segment(1); + IProject rawProject = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName); + if (rawProject != null) { + IJavaProject javaProject = JavaCore.getJavaCore().create(rawProject); + if (javaProject != null) { + IType serviceClass = javaProject.findType(m.getDeclaringClass().getName()); + if (serviceClass != null && serviceClass.exists()) { + for (IMethod jm : serviceClass.getMethods()) { + boolean onlySelfParameter = leftParenthesisIndex == -1 && rightParenthesisIndex == -1; + + if (jm.getElementName().equals(serviceCallName)) { + int methodParametersNumber = jm.getParameters().length; + long serviceParametersNumber = getServiceParametersNumber(vsmExpression, leftParenthesisIndex, rightParenthesisIndex); + if (!onlySelfParameter && methodParametersNumber == serviceParametersNumber || (onlySelfParameter && methodParametersNumber == 1)) { + navigationTargets.add(jm); + break; + } + } + } + } + } + } + } + } + } + // CHECKSTYLE:ON + } + } + } + + /** + * Extract and return the service call part from given context if such call exists. + * + * @param contentContext + * the context from which service call part must be extracted. + * @return the service call part from given context if such call exists. Null otherwise. + */ + private String extractServiceCall(ContentContext contentContext) { + String serviceName = null; + String expression = contentContext.getContents(); + boolean isServiceInterpreterUsed = expression.startsWith(ServiceInterpreter.PREFIX); + int cursorPosition = contentContext.getPosition(); + if (isServiceInterpreterUsed) { + expression = expression.replaceFirst(ServiceInterpreter.PREFIX, ""); + if (cursorPosition > ServiceInterpreter.PREFIX.length()) { + cursorPosition = cursorPosition - ServiceInterpreter.PREFIX.length(); + } + } + char[] expressionArray = expression.toCharArray(); + + int serviceCallStartPosition = -1; + int i = initSearchPosition(expressionArray, cursorPosition); + while (i >= 0 && serviceCallStartPosition == -1) { + char tempChar = expressionArray[i]; + if (tempChar == '.' || tempChar == ':' || (tempChar == ' ')) { + serviceCallStartPosition = i + 1; + } + i--; + } + if (i == -1 && isServiceInterpreterUsed) { + serviceCallStartPosition = 0; + } + int serviceCallEndPosition = -1; + int j = initSearchPosition(expressionArray, cursorPosition); + while (j < expressionArray.length && serviceCallEndPosition == -1) { + char tempChar = expressionArray[j]; + if (tempChar == ')') { + serviceCallEndPosition = j + 1; + } + j++; + } + if (serviceCallStartPosition != -1 && serviceCallEndPosition != -1) { + serviceName = expression.substring(serviceCallStartPosition, serviceCallEndPosition); + } else if (serviceCallEndPosition != -1) { + serviceCallStartPosition = expression.indexOf("."); + if (serviceCallStartPosition != -1 && serviceCallStartPosition < serviceCallEndPosition) { + serviceName = expression.substring(serviceCallStartPosition + 1, serviceCallEndPosition); + } + } + return serviceName; + } + + /** + * Return the search position from cursor position. If the cursor position is out of range of the expression array + * length, then we use as start search position the closer index. Otherwise it is the cursor position. + * + * @param expressionArray + * the expression array from which we compute a starting search position. + * @param cursorPosition + * the cursor position from which we compute a starting search position. + * @return the search position from cursor position. + */ + private int initSearchPosition(char[] expressionArray, int cursorPosition) { + int searchPosition = cursorPosition; + if (cursorPosition == -1) { + searchPosition = 0; + } else if (expressionArray.length == cursorPosition) { + searchPosition = expressionArray.length - 1; + } + return searchPosition; + } + + private long getServiceParametersNumber(String vsmExpression, int leftParenthesisIndex, int rightParenthesisIndex) { + long serviceParametersNumber; + if (rightParenthesisIndex == leftParenthesisIndex + 1) { + serviceParametersNumber = 1; + } else { + long parameterSeparatorNumber = vsmExpression.chars().filter(ch -> ch == ',').count(); + if (parameterSeparatorNumber == 0) { + serviceParametersNumber = 2; + } else { + serviceParametersNumber = parameterSeparatorNumber + 2; + } + } + return serviceParametersNumber; + } + + @Override + public boolean doProvideNavigationFor(AbstractViewpointPropertySection propertySection, EObject targetEObject, ContentContext contentContext) { + try { + initializeNavigationTarget(propertySection, targetEObject, contentContext); + } catch (JavaModelException e) { + SiriusEditorPlugin.getPlugin().getLog() + .log(new Status(IStatus.ERROR, SiriusEditorPlugin.PLUGIN_ID, MessageFormat.format(Messages.ServiceNavigator_targetInitialization_error, contentContext.getContents()), e)); + } + return !navigationTargets.isEmpty(); + } + +} diff --git a/plugins/org.eclipse.sirius.tests.swtbot/data/unit/editor/vsm/completion/BasicService2.java b/plugins/org.eclipse.sirius.tests.swtbot/data/unit/editor/vsm/completion/BasicService2.java new file mode 100644 index 0000000000..5d25694b80 --- /dev/null +++ b/plugins/org.eclipse.sirius.tests.swtbot/data/unit/editor/vsm/completion/BasicService2.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2018 Obeo + * 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: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.test.design; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EPackage; + +public class BasicService2 { + public String sampleService(EObject ctx) { + return "sampleService"; + } + + public String sampleService(EObject ctx, EObject ctx2) { + return "sampleService2"; + } +} diff --git a/plugins/org.eclipse.sirius.tests.swtbot/data/unit/editor/vsm/completion/MANIFEST.MF b/plugins/org.eclipse.sirius.tests.swtbot/data/unit/editor/vsm/completion/MANIFEST.MF index 98524feca8..3f00a637f5 100644 --- a/plugins/org.eclipse.sirius.tests.swtbot/data/unit/editor/vsm/completion/MANIFEST.MF +++ b/plugins/org.eclipse.sirius.tests.swtbot/data/unit/editor/vsm/completion/MANIFEST.MF @@ -7,7 +7,7 @@ Bundle-Activator: org.eclipse.sirius.test.design.Activator Require-Bundle: org.eclipse.ui, org.eclipse.core.runtime, org.eclipse.sirius, - org.eclipse.sirius.common.acceleo.mtl + org.eclipse.sirius.common.acceleo.mtl, + org.eclipse.sirius.sample.interactions Bundle-ActivationPolicy: lazy Bundle-RequiredExecutionEnvironment: JavaSE-1.7 -Import-Package: org.eclipse.sirius.sample.interactions diff --git a/plugins/org.eclipse.sirius.tests.swtbot/data/unit/editor/vsm/completion/ServicesWithDependencies.java b/plugins/org.eclipse.sirius.tests.swtbot/data/unit/editor/vsm/completion/ServicesWithDependencies.java index 8158a33033..dca6894dd2 100644 --- a/plugins/org.eclipse.sirius.tests.swtbot/data/unit/editor/vsm/completion/ServicesWithDependencies.java +++ b/plugins/org.eclipse.sirius.tests.swtbot/data/unit/editor/vsm/completion/ServicesWithDependencies.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016 Obeo. + * Copyright (c) 2016, 2017 Obeo. * 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 @@ -34,5 +34,4 @@ public class ServicesWithDependencies { createCallMessage.setName("testInteractionsWithServiceServiceCallOk"); return createCallMessage; } - } diff --git a/plugins/org.eclipse.sirius.tests.swtbot/data/unit/editor/vsm/completion/test.odesign b/plugins/org.eclipse.sirius.tests.swtbot/data/unit/editor/vsm/completion/test.odesign index 8aa2f0cff1..6c988976cc 100644 --- a/plugins/org.eclipse.sirius.tests.swtbot/data/unit/editor/vsm/completion/test.odesign +++ b/plugins/org.eclipse.sirius.tests.swtbot/data/unit/editor/vsm/completion/test.odesign @@ -7,6 +7,7 @@ </defaultLayer> </ownedRepresentations> <ownedJavaExtensions qualifiedClassName="org.eclipse.sirius.test.design.BasicService"/> + <ownedJavaExtensions qualifiedClassName="org.eclipse.sirius.test.design.BasicService2"/> <ownedJavaExtensions qualifiedClassName="org::eclipse::sirius::test::design::AcceleoMtlInterpreterTestModule"/> <ownedJavaExtensions qualifiedClassName="org.eclipse.sirius.test.design.ServicesWithDependencies"/> </ownedViewpoints> diff --git a/plugins/org.eclipse.sirius.tests.swtbot/src/org/eclipse/sirius/tests/swtbot/editor/vsm/ServiceNavigationTest.java b/plugins/org.eclipse.sirius.tests.swtbot/src/org/eclipse/sirius/tests/swtbot/editor/vsm/ServiceNavigationTest.java new file mode 100644 index 0000000000..17f868b1d4 --- /dev/null +++ b/plugins/org.eclipse.sirius.tests.swtbot/src/org/eclipse/sirius/tests/swtbot/editor/vsm/ServiceNavigationTest.java @@ -0,0 +1,519 @@ +/******************************************************************************* + * Copyright (c) 2018 Obeo + * 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: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.tests.swtbot.editor.vsm; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.commands.common.CommandException; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IWorkspaceDescription; +import org.eclipse.core.resources.IncrementalProjectBuilder; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.sirius.tests.support.api.EclipseTestsSupportHelper; +import org.eclipse.sirius.tests.support.api.ICondition; +import org.eclipse.sirius.tests.support.api.TestsUtil; +import org.eclipse.sirius.tests.swtbot.Activator; +import org.eclipse.sirius.tests.swtbot.support.api.editor.SWTBotSiriusHelper; +import org.eclipse.sirius.ui.tools.internal.views.modelexplorer.ModelExplorerView; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swtbot.eclipse.finder.widgets.SWTBotEditor; +import org.eclipse.swtbot.eclipse.finder.widgets.SWTBotView; +import org.eclipse.swtbot.swt.finder.SWTBot; +import org.eclipse.swtbot.swt.finder.widgets.SWTBotShell; +import org.eclipse.swtbot.swt.finder.widgets.SWTBotTable; +import org.eclipse.swtbot.swt.finder.widgets.SWTBotTableItem; +import org.eclipse.swtbot.swt.finder.widgets.SWTBotText; +import org.eclipse.swtbot.swt.finder.widgets.SWTBotTreeItem; +import org.eclipse.ui.IEditorReference; + +import com.google.common.collect.Lists; + +/** + * Test the service implementation navigation from VSM service call in + * interpreted expressions. + * + * @author <a href="mailto:pierre.guilet@obeo.fr">Pierre Guilet</a> + * + * + */ +public class ServiceNavigationTest extends AbstractContentAssistTest { + + private final class JavaEditorOpenedCondition implements ICondition { + private boolean javaEditorOpened; + + public JavaEditorOpenedCondition(boolean javaEditorOpened) { + this.javaEditorOpened = javaEditorOpened; + } + + @Override + public boolean test() throws Exception { + SWTBotEditor activeEditor = bot.activeEditor(); + IEditorReference reference = activeEditor.getReference(); + return (javaEditorOpened && "org.eclipse.jdt.ui.CompilationUnitEditor".equals(reference.getId())) + || (!javaEditorOpened && !"org.eclipse.jdt.ui.CompilationUnitEditor".equals(reference.getId())); + } + + @Override + public String getFailureMessage() { + return "Java editor has not been opened"; + } + } + + private static final String BASIC_SERVICE_JAVA = "BasicService.java"; + + private static final String BASIC_SERVICE_JAVA2 = "BasicService2.java"; + + private static final String PATH = "data/unit/editor/vsm/completion/"; + + private static final String VSM_PROJECT_NAME = "org.eclipse.sirius.test.design"; + + private static final String VSM = "test.odesign"; + + /** + * + */ + private static final String TESTED_ODESIGN_NAME = "new" + VSM; + + private SWTBotView propertiesBot; + + @Override + protected void onSetUpBeforeClosingWelcomePage() throws Exception { + super.onSetUpBeforeClosingWelcomePage(); + final IWorkspaceDescription description = ResourcesPlugin.getWorkspace().getDescription(); + description.setAutoBuilding(false); + ResourcesPlugin.getWorkspace().setDescription(description); + // Wait the end of the current build and/or refresh. + waitJobsBuildOrRefresh(); + } + + @Override + protected void onSetUpAfterOpeningDesignerPerspective() throws Exception { + setErrorCatchActive(false); + + // Load the target platform, if not already done, to allow compilation + // of the java services + TestsUtil.setTargetPlatform(); + } + + /** + * Initialize the context by copying new resources and waiting all build + * process. + * + * @exception InterruptedException + * if this thread is interrupted while waiting + * @exception OperationCanceledException + * if the progress monitor is canceled while waiting + * @exception CoreException + * In case of problem during setting workspace description to + * disable auto build. + * @throws CommandException + */ + private void initContext(List<String> nodes) throws InterruptedException, OperationCanceledException, CoreException, CommandException { + designerPerspectives.openSiriusPerspective(); + + // Copy the sample ecore model for type completion + copyFileToTestProject(Activator.PLUGIN_ID, PATH, "test.ecore"); + + // Create VSM Project. + IProject viewpointSpecificationProject = ViewpointSpecificationProjectCreationTest.createViewpointSpecificationProject(bot, VSM_PROJECT_NAME, VSM); + // Wait the end of the current build and/or refresh. + viewpointSpecificationProject.refreshLocal(IProject.DEPTH_INFINITE, new NullProgressMonitor()); + waitJobsBuildOrRefresh(); + + // Define the imports in the VSM and add Ecore dependency + String MANIFEST_MF = "MANIFEST.MF"; + EclipseTestsSupportHelper.INSTANCE.copyFile(Activator.PLUGIN_ID, PATH + MANIFEST_MF, VSM_PROJECT_NAME + "/META-INF/" + MANIFEST_MF); + EclipseTestsSupportHelper.INSTANCE.copyFile(Activator.PLUGIN_ID, PATH + VSM, VSM_PROJECT_NAME + "/description/" + TESTED_ODESIGN_NAME); + + // We open the new design used by the test. We avoid replacing the + // already existing one because sometime the refresh is not correctly + // done and tests can fail. + SWTBotView modelExplorerView = bot.viewById(ModelExplorerView.ID); + modelExplorerView.setFocus(); + SWTBotTreeItem projectNode = modelExplorerView.bot().tree().expandNode("org.eclipse.sirius.test.design"); + SWTBotTreeItem descriptionNode = projectNode.expandNode("description"); + SWTBotTreeItem designNode = descriptionNode.getNode(TESTED_ODESIGN_NAME); + designNode.doubleClick(); + + waitJobsBuildOrRefresh(); + + // Copy the Java Service file + char pathSeparator = '/'; + String package_name = VSM_PROJECT_NAME; + package_name = package_name.replace('.', pathSeparator); + String dest = VSM_PROJECT_NAME + "/src/" + package_name + pathSeparator; + EclipseTestsSupportHelper.INSTANCE.copyFile(Activator.PLUGIN_ID, PATH + BASIC_SERVICE_JAVA, dest + BASIC_SERVICE_JAVA); + EclipseTestsSupportHelper.INSTANCE.copyFile(Activator.PLUGIN_ID, PATH + BASIC_SERVICE_JAVA2, dest + BASIC_SERVICE_JAVA2); + + waitJobsBuildOrRefresh(); + + // Launch a manual build and wait the end of the workspace build + ResourcesPlugin.getWorkspace().build(IncrementalProjectBuilder.FULL_BUILD, new NullProgressMonitor()); + waitJobsBuildOrRefresh(); + + bot.activeEditor().setFocus(); + SWTBotTreeItem lastExpandNode = bot.activeEditor().bot().tree().expandNode("platform:/resource/" + VSM_PROJECT_NAME + "/description/" + TESTED_ODESIGN_NAME); + for (String node : nodes) { + lastExpandNode = lastExpandNode.expandNode(node); + } + lastExpandNode.select(); + + propertiesBot = bot.viewByTitle("Properties"); + propertiesBot.setFocus(); + SWTBotSiriusHelper.selectPropertyTabItem("General"); + } + + /** + * @param string + */ + private void expandNode(String string) { + // TODO Auto-generated method stub + + } + + /** + * @param string + */ + private void getNode(String string) { + // TODO Auto-generated method stub + + } + + /** + * There is problem on linux with this test so we are waiting build or + * refresh jobs by joining them. + */ + private void waitJobsBuildOrRefresh() throws InterruptedException, OperationCanceledException { + Job.getJobManager().join(ResourcesPlugin.FAMILY_MANUAL_BUILD, new NullProgressMonitor()); + Job.getJobManager().join(ResourcesPlugin.FAMILY_AUTO_BUILD, new NullProgressMonitor()); + Job.getJobManager().join(ResourcesPlugin.FAMILY_AUTO_REFRESH, new NullProgressMonitor()); + Job.getJobManager().join(ResourcesPlugin.FAMILY_MANUAL_REFRESH, new NullProgressMonitor()); + Job.getJobManager().join(ResourcesPlugin.FAMILY_AUTO_BUILD, new NullProgressMonitor()); + } + + /** + * Check that Java service navigation from F3 key and a VSM expression works + * in the following context: + * <ul> + * <li>The expression calls the service interpreter.</li> + * <li>The cursor is at the starting position</li> + * <li>The service called is present in two different classes</li> + * <li>The service from which the navigation is done is the first one in the + * wizard.</li> + * </ul> + * + * @exception Exception + * if a problem occurs. + */ + public void testServiceNavigationWithSameServiceInDifferentClasses() throws Exception { + List<String> expectedItemLabels = new ArrayList<>(); + expectedItemLabels.add("BasicService - org.eclipse.sirius.test.design"); + expectedItemLabels.add("BasicService2"); + testNavigation("service:sampleService()", 2, expectedItemLabels, 0, 0); + } + + /** + * Check that Java service navigation from F3 key and a VSM expression works + * in the following context: + * <ul> + * <li>The expression calls the service interpreter.</li> + * <li>The cursor is at the starting position</li> + * <li>The service called is present in two different classes</li> + * <li>The service from which the navigation is done is the second one in + * the wizard.</li> + * </ul> + * + * @exception Exception + * if a problem occurs. + */ + public void testServiceNavigationWithSameServiceInDifferentClasses2() throws Exception { + List<String> expectedItemLabels = new ArrayList<>(); + expectedItemLabels.add("BasicService - org.eclipse.sirius.test.design"); + expectedItemLabels.add("BasicService2"); + testNavigation("service:sampleService()", 2, expectedItemLabels, 1, 0); + } + + /** + * Check that Java service navigation from F3 key and a VSM expression works + * in the following context: + * <ul> + * <li>The expression calls the service interpreter.</li> + * <li>The cursor is at the 12 index position</li> + * <li>The service called is present in one class</li> + * <li>The service is automatically opened in JAVA editor.</li> + * </ul> + * + * @exception Exception + * if a problem occurs. + */ + public void testSingleServiceNavigation() throws Exception { + testNavigation("service:sampleService(self)", 1, null, -1, 12); + } + + /** + * Check that Java service navigation from F3 key and a VSM expression works + * in the following context: + * <ul> + * <li>The expression calls the AQL interpreter.</li> + * <li>The cursor is at the starting position</li> + * <li>No service should be detected at the cursor position. So nothing + * should be done.</li> + * </ul> + * + * @exception Exception + * if a problem occurs. + */ + public void testServiceNavigationWithAqlInterpreterFirstPosition() throws Exception { + testNavigation("aql:self.sampleService() and self.sampleService(self)->", 0, null, -1, 0); + } + + /** + * Check that Java service navigation from F3 key and a VSM expression works + * in the following context: + * <ul> + * <li>The expression calls the AQL interpreter.</li> + * <li>The cursor is at the last position</li> + * <li>No service should be detected at the cursor position. So nothing + * should be done.</li> + * </ul> + * + * @exception Exception + * if a problem occurs. + */ + public void testServiceNavigationWithAqlInterpreterLastPosition() throws Exception { + testNavigation("aql:self.sampleService() and self.sampleService(self)->", 0, null, -1, 55); + } + + /** + * Check that Java service navigation from F3 key and a VSM expression works + * in the following context: + * <ul> + * <li>The expression calls the AQL interpreter.</li> + * <li>The cursor is at the 27 index position</li> + * <li>No service should be detected at the cursor position. So nothing + * should be done.</li> + * </ul> + * + * @exception Exception + * if a problem occurs. + */ + public void testServiceNavigationWithAqlInterpreterMiddlePosition() throws Exception { + testNavigation("aql:self.sampleService() and self.sampleService(self)->", 0, null, -1, 27); + } + + /** + * Check that Java service navigation from F3 key and a VSM expression works + * in the following context: + * <ul> + * <li>The expression calls the AQL interpreter.</li> + * <li>The cursor is at the 13 index position</li> + * <li>The service call at cursor position is present in two different + * classes</li> + * <li>The service from which the navigation is done is the second one in + * the wizard.</li> + * </ul> + * + * @exception Exception + * if a problem occurs. + */ + public void testDualServiceNavigationWithAqlInterpreter() throws Exception { + List<String> expectedItemLabels = new ArrayList<>(); + expectedItemLabels.add("BasicService - org.eclipse.sirius.test.design"); + expectedItemLabels.add("BasicService2"); + testNavigation("aql:self.sampleService() and self.sampleService(self)->", 2, expectedItemLabels, 1, 13); + } + + /** + * Check that Java service navigation from F3 key and a VSM expression works + * in the following context: + * <ul> + * <li>The expression calls the AQL interpreter.</li> + * <li>The cursor is at the 9 index position</li> + * <li>The service call at cursor position is present in two different + * classes</li> + * <li>The service from which the navigation is done is the second one in + * the wizard.</li> + * </ul> + * + * @exception Exception + * if a problem occurs. + */ + public void testDualServiceNavigationWithAqlInterpreter2() throws Exception { + List<String> expectedItemLabels = new ArrayList<>(); + expectedItemLabels.add("BasicService - org.eclipse.sirius.test.design"); + expectedItemLabels.add("BasicService2"); + testNavigation("aql:self.sampleService() and self.sampleService(self)->", 2, expectedItemLabels, 1, 9); + } + + /** + * Check that Java service navigation from F3 key and a VSM expression works + * in the following context: + * <ul> + * <li>The expression calls the AQL interpreter.</li> + * <li>The cursor is at the 23 index position</li> + * <li>The service call at cursor position is present in two different + * classes</li> + * <li>The service from which the navigation is done is the second one in + * the wizard.</li> + * </ul> + * + * @exception Exception + * if a problem occurs. + */ + public void testDualServiceNavigationWithAqlInterpreter3() throws Exception { + List<String> expectedItemLabels = new ArrayList<>(); + expectedItemLabels.add("BasicService - org.eclipse.sirius.test.design"); + expectedItemLabels.add("BasicService2"); + testNavigation("aql:self.sampleService() and self.sampleService(self)->", 2, expectedItemLabels, 1, 23); + } + + /** + * Check that Java service navigation from F3 key and a VSM expression works + * in the following context: + * <ul> + * <li>The expression calls the AQL interpreter.</li> + * <li>The cursor is at the 38 index position</li> + * <li>The service call at cursor position is present in one class</li> + * <li>The service is automatically opened in JAVA editor.</li> + * </ul> + * + * @exception Exception + * if a problem occurs. + */ + public void testSingleServiceNavigationWithAqlInterpreter() throws Exception { + testNavigation("aql:self.sampleService() and self.sampleService(self)->", 1, null, -1, 38); + } + + /** + * Tests that Java service navigation from VSM expression is the expected + * one. + * + * @param vsmExpression + * the VSM expression used to test Java service navigation. + * @param matchingJavaServiceNumber + * the number of Java service that should be proposed for + * navigation. + * @param expectedItemLabels + * The Java service item's labels in their wizard's order. + * @param javaServiceIndex + * the index of the Java service item to open with Java editor + * when in Java service navigation wizard. + * @param cursorPosition + * the cursor position in the VSM expression before triggering + * navigation with F3 key. + * + * @throws InterruptedException + * if a problem occurs. + * @throws CoreException + * if a problem occurs. + * @throws CommandException + * if a problem occurs. + */ + protected void testNavigation(String vsmExpression, int matchingJavaServiceNumber, List<String> expectedItemLabels, int javaServiceIndex, int cursorPosition) + throws InterruptedException, CoreException, CommandException { + if (TestsUtil.shouldSkipUnreliableTests()) { + return; + } + + initContext(Lists.newArrayList("test", "VP", "Diag")); + + // Init the Precondition Expression + SWTBotText precondition = propertiesBot.bot().text(3); + precondition.setFocus(); + precondition.setText(vsmExpression); + TestsUtil.waitUntil(new ICondition() { + + @Override + public boolean test() throws Exception { + return vsmExpression.equals(precondition.getText()); + } + + @Override + public String getFailureMessage() { + return null; + } + + }); + Display.getDefault().asyncExec(() -> { + // bot.pressShortcut does not work + precondition.widget.setSelection(cursorPosition); + Event event = new Event(); + event.keyCode = SWT.F3; + precondition.widget.notifyListeners(SWT.KeyDown, event); + }); + if (matchingJavaServiceNumber > 0) { + if (matchingJavaServiceNumber > 1) { + TestsUtil.waitUntil(new ICondition() { + + @Override + public boolean test() throws Exception { + + SWTBotShell shell = null; + try { + shell = bot.shell("Service navigation"); + } catch (Exception e) { + // do nothing + } + return shell != null; + } + + @Override + public String getFailureMessage() { + return "Service navigation wizard did not open."; + } + }, 10000); + SWTBotShell shell = bot.shell("Service navigation"); + SWTBot wizardBot = shell.bot(); + SWTBotTable table = wizardBot.table(0); + TestsUtil.waitUntil(new ICondition() { + + @Override + public boolean test() throws Exception { + return table.rowCount() > 0; + } + + @Override + public String getFailureMessage() { + return "The type navigation wizard was not filled with target Java services."; + } + }, 15000); + + assertEquals("Wrong number of matching Java service implementations.", matchingJavaServiceNumber, table.rowCount()); + + if (expectedItemLabels != null) { + for (int i = 0; i < expectedItemLabels.size(); i++) { + SWTBotTableItem tableItem = table.getTableItem(i); + assertEquals("Unknown service: " + tableItem.getText(), expectedItemLabels.get(i), tableItem.getText()); + + } + } + if (javaServiceIndex >= 0) { + table.select(javaServiceIndex); + wizardBot.button("OK").click(); + } + } + TestsUtil.waitUntil(new JavaEditorOpenedCondition(true)); + + } + + if (matchingJavaServiceNumber == 0) { + TestsUtil.waitUntil(new JavaEditorOpenedCondition(false)); + } + + } +} diff --git a/plugins/org.eclipse.sirius.tests.swtbot/src/org/eclipse/sirius/tests/swtbot/suite/AllTestSuite.java b/plugins/org.eclipse.sirius.tests.swtbot/src/org/eclipse/sirius/tests/swtbot/suite/AllTestSuite.java index ddf211fb91..9070e6fb1f 100644 --- a/plugins/org.eclipse.sirius.tests.swtbot/src/org/eclipse/sirius/tests/swtbot/suite/AllTestSuite.java +++ b/plugins/org.eclipse.sirius.tests.swtbot/src/org/eclipse/sirius/tests/swtbot/suite/AllTestSuite.java @@ -36,6 +36,7 @@ import org.eclipse.sirius.tests.swtbot.editor.vsm.MetamodelPropertyTabTests; import org.eclipse.sirius.tests.swtbot.editor.vsm.MigrationOnVsmEditorReloadTest; import org.eclipse.sirius.tests.swtbot.editor.vsm.OpeningContextTest; import org.eclipse.sirius.tests.swtbot.editor.vsm.ResizeKindEditorTest; +import org.eclipse.sirius.tests.swtbot.editor.vsm.ServiceNavigationTest; import org.eclipse.sirius.tests.swtbot.editor.vsm.VSMEditorPropertiesTest; import org.eclipse.sirius.tests.swtbot.editor.vsm.VSMFieldTest; import org.eclipse.sirius.tests.swtbot.editor.vsm.ValidationEmptyNameTest; @@ -125,6 +126,7 @@ public class AllTestSuite extends TestCase { */ public static void addGerritPart1(TestSuite suite) { suite.addTest(new JUnit4TestAdapter(SWTBotBundlesReport.class)); + suite.addTestSuite(ServiceNavigationTest.class); suite.addTestSuite(ContentAssistTest.class); suite.addTestSuite(FeatureAssistTest.class); suite.addTestSuite(ResizeKindEditorTest.class); |
