Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPierre-Charles David2016-08-16 13:44:57 +0000
committerPierre-Charles David2016-08-22 15:00:12 +0000
commit10f13b75448bb9c81d401fff90013e9299eed335 (patch)
tree4de2ea620eff05d98201f59acc0ad069ed60e0e3
parent04cc6c431dcf1943ecd6ae8382c5cd591dc2fe19 (diff)
downloadorg.eclipse.sirius-10f13b75448bb9c81d401fff90013e9299eed335.tar.gz
org.eclipse.sirius-10f13b75448bb9c81d401fff90013e9299eed335.tar.xz
org.eclipse.sirius-10f13b75448bb9c81d401fff90013e9299eed335.zip
[496014] Provide an IInterpretedExpressionQuery for properties expressions
Bug: 496014 Change-Id: I5a24ea9462f5dce96963377fb7d9ebd3f84b49ab Signed-off-by: Pierre-Charles David <pierre-charles.david@obeo.fr>
-rw-r--r--plugins/org.eclipse.sirius.ui.properties/META-INF/MANIFEST.MF1
-rw-r--r--plugins/org.eclipse.sirius.ui.properties/plugin.xml6
-rw-r--r--plugins/org.eclipse.sirius.ui.properties/src/org/eclipse/sirius/ui/properties/internal/expressions/DomainClassSwitch.java207
-rw-r--r--plugins/org.eclipse.sirius.ui.properties/src/org/eclipse/sirius/ui/properties/internal/expressions/PropertiesExpressionQueryProvider.java36
-rw-r--r--plugins/org.eclipse.sirius.ui.properties/src/org/eclipse/sirius/ui/properties/internal/expressions/PropertiesInterpretedExpressionQuery.java360
-rw-r--r--plugins/org.eclipse.sirius.ui.properties/src/org/eclipse/sirius/ui/properties/internal/expressions/VSMNavigation.java208
6 files changed, 818 insertions, 0 deletions
diff --git a/plugins/org.eclipse.sirius.ui.properties/META-INF/MANIFEST.MF b/plugins/org.eclipse.sirius.ui.properties/META-INF/MANIFEST.MF
index 91db8cbd22..c9b0a8dc70 100644
--- a/plugins/org.eclipse.sirius.ui.properties/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.sirius.ui.properties/META-INF/MANIFEST.MF
@@ -37,4 +37,5 @@ Bundle-ActivationPolicy: lazy
Bundle-Localization: plugin
Export-Package: org.eclipse.sirius.ui.properties.api;version="4.1.0",
org.eclipse.sirius.ui.properties.internal;version="4.1.0";x-internal:=true,
+ org.eclipse.sirius.ui.properties.internal.expressions;version="4.1.0";x-internal:=true,
org.eclipse.sirius.ui.properties.internal.tabprovider;version="4.1.0";x-internal:=true
diff --git a/plugins/org.eclipse.sirius.ui.properties/plugin.xml b/plugins/org.eclipse.sirius.ui.properties/plugin.xml
index 358a225a93..29ac3b644c 100644
--- a/plugins/org.eclipse.sirius.ui.properties/plugin.xml
+++ b/plugins/org.eclipse.sirius.ui.properties/plugin.xml
@@ -64,4 +64,10 @@
</siriusPropertySheetPageProvider>
-->
</extension>
+ <extension
+ point="org.eclipse.sirius.interpretedExpressionQueryProvider">
+ <interpretedExpressionProvider
+ class="org.eclipse.sirius.ui.properties.internal.expressions.PropertiesExpressionQueryProvider">
+ </interpretedExpressionProvider>
+ </extension>
</plugin>
diff --git a/plugins/org.eclipse.sirius.ui.properties/src/org/eclipse/sirius/ui/properties/internal/expressions/DomainClassSwitch.java b/plugins/org.eclipse.sirius.ui.properties/src/org/eclipse/sirius/ui/properties/internal/expressions/DomainClassSwitch.java
new file mode 100644
index 0000000000..12f101056b
--- /dev/null
+++ b/plugins/org.eclipse.sirius.ui.properties/src/org/eclipse/sirius/ui/properties/internal/expressions/DomainClassSwitch.java
@@ -0,0 +1,207 @@
+/*******************************************************************************
+ * Copyright (c) 2016 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.ui.properties.internal.expressions;
+
+import java.util.Collection;
+
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.sirius.common.tools.api.interpreter.TypeName;
+import org.eclipse.sirius.ext.base.Option;
+import org.eclipse.sirius.ext.base.Options;
+import org.eclipse.sirius.properties.CustomExpression;
+import org.eclipse.sirius.properties.CustomOperation;
+import org.eclipse.sirius.properties.DynamicMappingFor;
+import org.eclipse.sirius.properties.DynamicMappingIf;
+import org.eclipse.sirius.properties.GroupDescription;
+import org.eclipse.sirius.properties.GroupStyle;
+import org.eclipse.sirius.properties.OperationDescription;
+import org.eclipse.sirius.properties.PageDescription;
+import org.eclipse.sirius.properties.PropertiesPackage;
+import org.eclipse.sirius.properties.WidgetAction;
+import org.eclipse.sirius.properties.WidgetConditionalStyle;
+import org.eclipse.sirius.properties.WidgetDescription;
+import org.eclipse.sirius.properties.WidgetStyle;
+import org.eclipse.sirius.properties.util.PropertiesSwitch;
+
+import com.google.common.collect.Sets;
+
+/**
+ * Computes the domainClass (i.e. expected type of the receiver) for any
+ * interpreted expression defined on properties views elements. Note that this
+ * does not handle element inside a properties view description which come from
+ * other Sirius package (e.g. model operations).
+ *
+ * @author pcdavid
+ */
+public class DomainClassSwitch extends PropertiesSwitch<Option<Collection<String>>> {
+ /**
+ * Constant used in switches on feature id to consider the case when the
+ * feature must not be considered.
+ */
+ private static final int DO_NOT_CONSIDER_FEATURE = -1;
+
+ /**
+ * The feature containing the Interpreted expression.
+ */
+ protected EStructuralFeature feature;
+
+ /**
+ * Indicates if the feature must be considered.
+ */
+ protected boolean considerFeature;
+
+ /**
+ * Default constructor.
+ *
+ * @param feature
+ * the feature containing the Interpreted expression
+ */
+ public DomainClassSwitch(EStructuralFeature feature) {
+ this.feature = feature;
+ }
+
+ @Override
+ public Option<Collection<String>> doSwitch(EObject theEObject) {
+ Option<Collection<String>> doSwitch = super.doSwitch(theEObject);
+ if (doSwitch != null) {
+ return doSwitch;
+ }
+ Collection<String> defaultResult = Sets.newLinkedHashSet();
+ return Options.newSome(defaultResult);
+ }
+
+ /**
+ * Changes the behavior of this switch: if true, then the feature will be
+ * considered to calculate target types; if false, then the feature will be
+ * ignored.
+ *
+ * @param considerFeature
+ * true if the feature should be considered, false otherwise
+ */
+ public void setConsiderFeature(boolean considerFeature) {
+ this.considerFeature = considerFeature;
+ }
+
+ @Override
+ public Option<Collection<String>> casePageDescription(PageDescription page) {
+ Option<Collection<String>> result = null;
+ switch (getFeatureId(page.eClass())) {
+ case PropertiesPackage.PAGE_DESCRIPTION__SEMANTIC_CANDIDATE_EXPRESSION:
+ /*
+ * A page can be activated from almost any kind of input: anything
+ * selectable from any of the representations defined in the same
+ * VSM can trigger teh evaluation of the page's
+ * semanticCandidateExpression. Technically we could compute a union
+ * of all the relevant semantic types, but in practice there is
+ * little chance that it would be more useful than just EObject.
+ */
+ Collection<String> target = Sets.newLinkedHashSet();
+ target.add(TypeName.EOBJECT_TYPENAME.getCompleteName());
+ result = Options.newSome(target);
+ break;
+ case PropertiesPackage.PAGE_DESCRIPTION__LABEL_EXPRESSION:
+ case PropertiesPackage.PAGE_DESCRIPTION__PRECONDITION_EXPRESSION:
+ case DO_NOT_CONSIDER_FEATURE:
+ result = Options.newSome(VSMNavigation.getPageDomainClass(page));
+ break;
+ default:
+ break;
+ }
+ return result;
+ }
+
+ @Override
+ public Option<Collection<String>> caseGroupDescription(GroupDescription group) {
+ Option<Collection<String>> result = null;
+ switch (getFeatureId(group.eClass())) {
+ case PropertiesPackage.GROUP_DESCRIPTION__SEMANTIC_CANDIDATE_EXPRESSION:
+ /*
+ * A Group's semanticCandidateExpression is evaluated from the
+ * target of its referencing page, which is an instance of the
+ * page's domainClass.
+ */
+ Collection<String> target = Sets.newLinkedHashSet();
+ for (PageDescription page : VSMNavigation.findReferencingPages(group)) {
+ target.addAll(VSMNavigation.getPageDomainClass(page));
+ }
+ result = Options.newSome(target);
+ break;
+ case PropertiesPackage.GROUP_DESCRIPTION__LABEL_EXPRESSION:
+ case PropertiesPackage.GROUP_DESCRIPTION__PRECONDITION_EXPRESSION:
+ case DO_NOT_CONSIDER_FEATURE:
+ result = Options.newSome(VSMNavigation.getGroupDomainClass(group));
+ break;
+ default:
+ break;
+ }
+ return result;
+ }
+
+ @Override
+ public Option<Collection<String>> caseWidgetDescription(WidgetDescription object) {
+ return VSMNavigation.getDomainClassFromContainingGroup(object);
+ }
+
+ @Override
+ public Option<Collection<String>> caseWidgetStyle(WidgetStyle object) {
+ return VSMNavigation.getDomainClassFromContainingGroup(object);
+ }
+
+ @Override
+ public Option<Collection<String>> caseWidgetConditionalStyle(WidgetConditionalStyle object) {
+ return VSMNavigation.getDomainClassFromContainingGroup(object);
+ }
+
+ @Override
+ public Option<Collection<String>> caseWidgetAction(WidgetAction object) {
+ return VSMNavigation.getDomainClassFromContainingGroup(object);
+ }
+
+ @Override
+ public Option<Collection<String>> caseGroupStyle(GroupStyle object) {
+ return VSMNavigation.getDomainClassFromContainingGroup(object);
+ }
+
+ @Override
+ public Option<Collection<String>> caseCustomExpression(CustomExpression object) {
+ return VSMNavigation.getDomainClassFromContainingGroup(object);
+ }
+
+ @Override
+ public Option<Collection<String>> caseCustomOperation(CustomOperation object) {
+ return VSMNavigation.getDomainClassFromContainingGroup(object);
+ }
+
+ @Override
+ public Option<Collection<String>> caseOperationDescription(OperationDescription object) {
+ return VSMNavigation.getDomainClassFromContainingGroup(object);
+ }
+
+ @Override
+ public Option<Collection<String>> caseDynamicMappingFor(DynamicMappingFor object) {
+ return VSMNavigation.getDomainClassFromContainingGroup(object);
+ }
+
+ @Override
+ public Option<Collection<String>> caseDynamicMappingIf(DynamicMappingIf object) {
+ return VSMNavigation.getDomainClassFromContainingGroup(object);
+ }
+
+ private int getFeatureId(EClass eClass) {
+ if (considerFeature && feature != null) {
+ return eClass.getFeatureID(feature);
+ } else {
+ return DomainClassSwitch.DO_NOT_CONSIDER_FEATURE;
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.ui.properties/src/org/eclipse/sirius/ui/properties/internal/expressions/PropertiesExpressionQueryProvider.java b/plugins/org.eclipse.sirius.ui.properties/src/org/eclipse/sirius/ui/properties/internal/expressions/PropertiesExpressionQueryProvider.java
new file mode 100644
index 0000000000..74e5143bee
--- /dev/null
+++ b/plugins/org.eclipse.sirius.ui.properties/src/org/eclipse/sirius/ui/properties/internal/expressions/PropertiesExpressionQueryProvider.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2016 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.ui.properties.internal.expressions;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.sirius.business.api.dialect.description.IInterpretedExpressionQuery;
+import org.eclipse.sirius.business.api.dialect.description.IInterpretedExpressionQueryProvider;
+import org.eclipse.sirius.ext.base.Option;
+import org.eclipse.sirius.ext.base.Options;
+
+/**
+ * An {@link IInterpretedExpressionQueryProvider} for properties view
+ * description expressions.
+ *
+ * @author pcdavid
+ */
+public class PropertiesExpressionQueryProvider implements IInterpretedExpressionQueryProvider {
+ @Override
+ public Option<IInterpretedExpressionQuery> getExpressionQueryFor(EObject context, EStructuralFeature expressionAttribute) {
+ if (VSMNavigation.isInsideViewExtensionDescription(context)) {
+ IInterpretedExpressionQuery value = new PropertiesInterpretedExpressionQuery(context, expressionAttribute);
+ return Options.newSome(value);
+ } else {
+ return Options.newNone();
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.ui.properties/src/org/eclipse/sirius/ui/properties/internal/expressions/PropertiesInterpretedExpressionQuery.java b/plugins/org.eclipse.sirius.ui.properties/src/org/eclipse/sirius/ui/properties/internal/expressions/PropertiesInterpretedExpressionQuery.java
new file mode 100644
index 0000000000..e20f75e349
--- /dev/null
+++ b/plugins/org.eclipse.sirius.ui.properties/src/org/eclipse/sirius/ui/properties/internal/expressions/PropertiesInterpretedExpressionQuery.java
@@ -0,0 +1,360 @@
+/*******************************************************************************
+ * Copyright (c) 2016 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.ui.properties.internal.expressions;
+
+import java.util.Collection;
+import java.util.Map;
+
+import org.eclipse.eef.common.api.utils.Util;
+import org.eclipse.eef.core.api.EEFExpressionUtils;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.EAttribute;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.EPackage.Registry;
+import org.eclipse.emf.ecore.EReference;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.EcorePackage;
+import org.eclipse.sirius.business.api.dialect.description.AbstractInterpretedExpressionQuery;
+import org.eclipse.sirius.business.api.dialect.description.IInterpretedExpressionQuery;
+import org.eclipse.sirius.business.api.dialect.description.IInterpretedExpressionTargetSwitch;
+import org.eclipse.sirius.business.api.dialect.description.MultiLanguagesValidator;
+import org.eclipse.sirius.business.api.query.EObjectQuery;
+import org.eclipse.sirius.business.internal.dialect.description.ToolInterpretedExpressionTargetSwitch;
+import org.eclipse.sirius.common.tools.api.interpreter.IInterpreterContext;
+import org.eclipse.sirius.common.tools.api.interpreter.TypeName;
+import org.eclipse.sirius.common.tools.api.interpreter.ValidationResult;
+import org.eclipse.sirius.common.tools.api.interpreter.VariableType;
+import org.eclipse.sirius.ext.base.Option;
+import org.eclipse.sirius.ext.base.Options;
+import org.eclipse.sirius.properties.DynamicMappingFor;
+import org.eclipse.sirius.properties.GroupDescription;
+import org.eclipse.sirius.properties.PageDescription;
+import org.eclipse.sirius.properties.PropertiesPackage;
+import org.eclipse.sirius.properties.ViewExtensionDescription;
+import org.eclipse.sirius.tools.api.interpreter.context.SiriusInterpreterContextFactory;
+import org.eclipse.sirius.ui.properties.internal.SiriusInputDescriptor;
+import org.eclipse.sirius.ui.properties.internal.SiriusToolServices;
+import org.eclipse.sirius.viewpoint.ViewpointPackage;
+import org.eclipse.sirius.viewpoint.description.DescriptionPackage;
+import org.eclipse.sirius.viewpoint.description.Extension;
+import org.eclipse.sirius.viewpoint.description.RepresentationDescription;
+import org.eclipse.sirius.viewpoint.description.tool.InitialOperation;
+import org.eclipse.sirius.viewpoint.description.tool.ToolPackage;
+import org.eclipse.sirius.viewpoint.description.validation.ValidationPackage;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+
+/**
+ * An {@code IInterpretedExpressionQuery} for expressions occuring inside
+ * properties view descriptions.
+ *
+ * @author pcdavid
+ */
+public final class PropertiesInterpretedExpressionQuery extends AbstractInterpretedExpressionQuery implements IInterpretedExpressionQuery {
+ private Collection<EPackage> packagesToImport;
+
+ /**
+ * Constructor.
+ *
+ * @param target
+ * the VSM element on which the expression appears.
+ * @param expressionAttribute
+ * the attribute of the VSM element which defines the expression
+ * (assumed to be an InterpredExpression).
+ */
+ public PropertiesInterpretedExpressionQuery(EObject target, EStructuralFeature expressionAttribute) {
+ super(target, expressionAttribute);
+ }
+
+ @Override
+ protected void initializeTargetSwitch() {
+ this.targetSwitch = new PropertiesExpressionsGlobalTargetSwitch(feature);
+ }
+
+ @Override
+ public Collection<EPackage> getPackagesToImport() {
+ /*
+ * We can't rely on the default implementation here, as it assumes we
+ * are inside a RepresentationDescription, which is not the case for
+ * properties definitions.
+ */
+ if (packagesToImport == null) {
+ packagesToImport = PropertiesInterpretedExpressionQuery.getEPackagesInScope(target);
+ }
+ return packagesToImport;
+ }
+
+ @Override
+ public Collection<String> getDependencies() {
+ /*
+ * We can't rely on the default implementation here, as it assumes we
+ * are inside a Viewpoint, which is not the case for properties
+ * definitions.
+ */
+ if (dependencies == null) {
+ Collection<String> result = Lists.newArrayList(VSMNavigation.getJavaExtensionsInVSM(target));
+ // Make sure the implicitly registered SiriusToolServices class is
+ // also visible.
+ result.add(SiriusToolServices.class.getName());
+ dependencies = result;
+ }
+ return dependencies;
+ }
+
+ private static Collection<EPackage> getEPackagesInScope(EObject target) {
+ Collection<EPackage> result = Sets.newLinkedHashSet();
+
+ boolean needsGlobalPackages = false;
+ for (RepresentationDescription desc : VSMNavigation.getRepresentationDescriptionsInVSM(target)) {
+ EList<EPackage> configured = desc.getMetamodel();
+ result.addAll(configured);
+ if (configured.isEmpty()) {
+ /*
+ * If at least one of the possible source representations has no
+ * explicitly configured metamodel, we must include the globally
+ * registered packages.
+ */
+ needsGlobalPackages = true;
+ }
+ }
+
+ if (needsGlobalPackages) {
+ result.addAll(PropertiesInterpretedExpressionQuery.getAllRegisteredEPackages(EPackage.Registry.INSTANCE));
+ }
+
+ // Also add metamodels explicitly added to the ViewExtensionDescription,
+ // if any.
+ Option<EObject> viewDescriptionOpt = new EObjectQuery(target).getFirstAncestorOfType(PropertiesPackage.Literals.VIEW_EXTENSION_DESCRIPTION);
+ if (viewDescriptionOpt.some()) {
+ ViewExtensionDescription ved = (ViewExtensionDescription) viewDescriptionOpt.get();
+ result.addAll(ved.getMetamodels());
+ }
+
+ // In all cases, we make sure the core Sirius metamodels are present...
+ result.add(EcorePackage.eINSTANCE);
+ result.add(ViewpointPackage.eINSTANCE);
+ result.add(DescriptionPackage.eINSTANCE);
+ result.add(ToolPackage.eINSTANCE);
+ result.add(ValidationPackage.eINSTANCE);
+ // ... and the properties view one too.
+ result.add(PropertiesPackage.eINSTANCE);
+
+ return result;
+ }
+
+ private static Collection<EPackage> getAllRegisteredEPackages(Registry source) {
+ Collection<EPackage> result = Sets.newLinkedHashSet();
+ for (String nsURI : Sets.newLinkedHashSet(source.keySet())) {
+ try {
+ result.add(source.getEPackage(nsURI));
+ // CHECKSTYLE:OFF
+ } catch (Throwable e) {
+ /*
+ * anything might happen here depending on the other Eclipse
+ * tools, and we've seen many time tools breaking all the
+ * others.
+ */
+ // CHECKSTYLE:ON
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public Map<String, VariableType> getAvailableVariables() {
+ if (availableVariables == null) {
+ availableVariables = Maps.newLinkedHashMap();
+ }
+ boolean isPropertiesElement = target.eClass().getEPackage() == PropertiesPackage.eINSTANCE;
+ if (isPropertiesElement) {
+ // "input" is always available.
+ availableVariables.put(EEFExpressionUtils.INPUT, VariableType.fromString(SiriusInputDescriptor.class.getName()));
+
+ if (feature == PropertiesPackage.Literals.SELECT_DESCRIPTION__CANDIDATE_DISPLAY_EXPRESSION) {
+ VariableType candidatesExpressionType = getResultType(target, PropertiesPackage.Literals.SELECT_DESCRIPTION__CANDIDATES_EXPRESSION);
+ availableVariables.put(EEFExpressionUtils.EEFSelect.CANDIDATE, candidatesExpressionType);
+ } else if (feature == PropertiesPackage.Literals.RADIO_DESCRIPTION__CANDIDATE_DISPLAY_EXPRESSION) {
+ VariableType candidatesExpressionType = getResultType(target, PropertiesPackage.Literals.RADIO_DESCRIPTION__CANDIDATES_EXPRESSION);
+ availableVariables.put(EEFExpressionUtils.EEFSelect.CANDIDATE, candidatesExpressionType);
+ } else if (feature == PropertiesPackage.Literals.REFERENCE_DESCRIPTION__DISPLAY_EXPRESSION) {
+ VariableType valueExpressionType = getResultType(target, PropertiesPackage.Literals.REFERENCE_DESCRIPTION__VALUE_EXPRESSION);
+ availableVariables.put(EEFExpressionUtils.EEFSelect.CANDIDATE, valueExpressionType);
+ } else if (feature == PropertiesPackage.Literals.DYNAMIC_MAPPING_IF__PREDICATE_EXPRESSION) {
+ if (target.eContainer() instanceof DynamicMappingFor) {
+ DynamicMappingFor forDefinition = (DynamicMappingFor) target.eContainer();
+ String iteratorName = forDefinition.getIterator();
+ if (!Util.isBlank(iteratorName)) {
+ VariableType iteratorType = getResultType(forDefinition, PropertiesPackage.Literals.DYNAMIC_MAPPING_FOR__DOMAIN_CLASS_EXPRESSION);
+ availableVariables.put(iteratorName, iteratorType);
+ }
+ }
+ }
+ return availableVariables;
+ } else {
+ return super.getAvailableVariables();
+ }
+ }
+
+ @Override
+ protected Option<EObject> getToolContext() {
+ Option<EObject> result = super.getToolContext();
+ if (!result.some()) {
+ if (target instanceof PageDescription || target instanceof GroupDescription) {
+ result = Options.newSome(target);
+ } else {
+ result = new EObjectQuery(target).getFirstAncestorOfType(ToolPackage.Literals.INITIAL_OPERATION);
+ }
+ }
+ return result;
+ }
+
+ @Override
+ protected void addVariablesFromToolContext(EObject toolContext) {
+ super.addVariablesFromToolContext(toolContext);
+ availableVariables.put(EEFExpressionUtils.INPUT, VariableType.fromString(SiriusInputDescriptor.class.getName()));
+ if (toolContext instanceof InitialOperation) {
+ EReference callbackFeature = toolContext.eContainmentFeature();
+ VariableType stringType = VariableType.fromString("java.lang.String"); //$NON-NLS-1$
+ VariableType booleanType = VariableType.fromString("java.lang.Boolean"); //$NON-NLS-1$
+ VariableType unkownType = VariableType.fromString(TypeName.EOBJECT_TYPENAME.getCompleteName());
+ if (callbackFeature == PropertiesPackage.Literals.TEXT_DESCRIPTION__INITIAL_OPERATION) {
+ availableVariables.put(EEFExpressionUtils.EEFText.NEW_VALUE, stringType);
+ } else if (callbackFeature == PropertiesPackage.Literals.CHECKBOX_DESCRIPTION__INITIAL_OPERATION) {
+ availableVariables.put(EEFExpressionUtils.EEFCheckbox.NEW_VALUE, booleanType);
+ } else if (callbackFeature == PropertiesPackage.Literals.HYPERLINK_DESCRIPTION__INITIAL_OPERATION) {
+ Option<Collection<String>> domainClass = VSMNavigation.getDomainClassFromContainingGroup(toolContext);
+ if (domainClass.some()) {
+ availableVariables.put(EEFExpressionUtils.EEFHyperlink.SELECTION, VariableType.fromStrings(domainClass.get()));
+ } else {
+ availableVariables.put(EEFExpressionUtils.EEFHyperlink.SELECTION, unkownType);
+ }
+ } else if (callbackFeature == PropertiesPackage.Literals.RADIO_DESCRIPTION__INITIAL_OPERATION) {
+ availableVariables.put(EEFExpressionUtils.EEFText.NEW_VALUE, stringType);
+ } else if (callbackFeature == PropertiesPackage.Literals.REFERENCE_DESCRIPTION__ON_CLICK_OPERATION) {
+ Option<Collection<String>> domainClass = VSMNavigation.getDomainClassFromContainingGroup(toolContext);
+ if (domainClass.some()) {
+ availableVariables.put(EEFExpressionUtils.EEFReference.SELECTION, VariableType.fromStrings(domainClass.get()));
+ } else {
+ availableVariables.put(EEFExpressionUtils.EEFHyperlink.SELECTION, unkownType);
+ }
+ availableVariables.put(EEFExpressionUtils.EEFReference.ON_CLICK_EVENT_KIND, stringType);
+ } else if (callbackFeature == PropertiesPackage.Literals.WIDGET_ACTION__INITIAL_OPERATION) {
+ Option<Collection<String>> domainClass = VSMNavigation.getDomainClassFromContainingGroup(toolContext);
+ if (domainClass.some()) {
+ availableVariables.put(EEFExpressionUtils.EEFReference.SELECTION, VariableType.fromStrings(domainClass.get()));
+ } else {
+ availableVariables.put(EEFExpressionUtils.EEFHyperlink.SELECTION, unkownType);
+ }
+ } else if (callbackFeature == PropertiesPackage.Literals.SELECT_DESCRIPTION__INITIAL_OPERATION) {
+ availableVariables.put(EEFExpressionUtils.EEFText.NEW_VALUE, stringType);
+ }
+ }
+ }
+
+ private VariableType getResultType(EObject owner, EAttribute attr) {
+ IInterpreterContext context = SiriusInterpreterContextFactory.createInterpreterContext(owner, attr);
+ ValidationResult res = MultiLanguagesValidator.getInstance().validateExpression(context, (String) owner.eGet(attr));
+ return res.getReturnTypes();
+ }
+
+ /**
+ * The switch used to compute domainClasses for expressions used in
+ * properties definitions.
+ *
+ * @author pcdavid
+ */
+ private static class PropertiesExpressionsGlobalTargetSwitch implements IInterpretedExpressionTargetSwitch {
+ /**
+ * The switch for properties-specific expressions.
+ */
+ private final DomainClassSwitch propertiesSwitch;
+
+ /**
+ * The switch we delegate to for Model Operations.
+ */
+ private final ToolInterpretedExpressionTargetSwitch delegateSwitch;
+
+ /**
+ * By default ToolInterpretedExpressionTargetSwitch assumes operations
+ * will appear inside representations or mappings, so we override
+ * getFirstContextChangingContainer() to locate the parent
+ * GroupDescription instead.
+ */
+ private static class CustomToolInterpretedExpressionTargetSwitch extends ToolInterpretedExpressionTargetSwitch {
+ public CustomToolInterpretedExpressionTargetSwitch(EStructuralFeature feature, IInterpretedExpressionTargetSwitch defaultSwitch) {
+ super(feature, defaultSwitch);
+ }
+
+ @Override
+ protected EObject getFirstContextChangingContainer(EObject element) {
+ EObject defaultResult = super.getFirstContextChangingContainer(element);
+ if (defaultResult instanceof Extension) {
+ /*
+ * The generic algorithm in the super-class does not know
+ * anything about the properties metamodel but will stop at
+ * the top-level ViewExtensionDescription as it is an
+ * Extension.
+ */
+ return VSMNavigation.findClosestGroupDescription(element);
+ } else {
+ return defaultResult;
+ }
+ }
+ }
+
+ public PropertiesExpressionsGlobalTargetSwitch(EStructuralFeature feature) {
+ this.propertiesSwitch = new DomainClassSwitch(feature);
+ this.delegateSwitch = new CustomToolInterpretedExpressionTargetSwitch(feature, this);
+ }
+
+ @Override
+ public Option<Collection<String>> doSwitch(EObject target, boolean considerFeature) {
+ Collection<String> targetTypes = Sets.newLinkedHashSet();
+ Option<Collection<String>> expressionTarget = Options.newSome(targetTypes);
+ if (target != null) {
+ if (expressionTarget.some() && expressionTarget.get().isEmpty()) {
+ propertiesSwitch.setConsiderFeature(considerFeature);
+ expressionTarget = propertiesSwitch.doSwitch(target);
+ }
+ if (expressionTarget.some() && expressionTarget.get().isEmpty()) {
+ delegateSwitch.setConsiderFeature(considerFeature);
+ expressionTarget = delegateSwitch.doSwitch(target);
+ }
+ }
+ return expressionTarget;
+ }
+
+ @Override
+ public EObject getFirstRelevantContainer(EObject obj) {
+ if (obj != null) {
+ EObject container = obj.eContainer();
+ while (container != null && !isRelevant(container)) {
+ container = container.eContainer();
+ }
+ return container;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * In this context, relevant containers are top-level pages and groups
+ * only. The root ViewExtensionDescriptions do not define anything
+ * relevant for domain class computation.
+ */
+ private boolean isRelevant(EObject container) {
+ return container instanceof PageDescription || container instanceof GroupDescription;
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.ui.properties/src/org/eclipse/sirius/ui/properties/internal/expressions/VSMNavigation.java b/plugins/org.eclipse.sirius.ui.properties/src/org/eclipse/sirius/ui/properties/internal/expressions/VSMNavigation.java
new file mode 100644
index 0000000000..2513a251d2
--- /dev/null
+++ b/plugins/org.eclipse.sirius.ui.properties/src/org/eclipse/sirius/ui/properties/internal/expressions/VSMNavigation.java
@@ -0,0 +1,208 @@
+/*******************************************************************************
+ * Copyright (c) 2016 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.ui.properties.internal.expressions;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
+
+import org.eclipse.eef.common.api.utils.Util;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.sirius.business.api.query.EObjectQuery;
+import org.eclipse.sirius.common.tools.api.interpreter.TypeName;
+import org.eclipse.sirius.common.tools.api.util.StringUtil;
+import org.eclipse.sirius.ext.base.Option;
+import org.eclipse.sirius.ext.base.Options;
+import org.eclipse.sirius.properties.GroupDescription;
+import org.eclipse.sirius.properties.PageDescription;
+import org.eclipse.sirius.properties.PropertiesPackage;
+import org.eclipse.sirius.properties.ViewExtensionDescription;
+import org.eclipse.sirius.viewpoint.description.DescriptionPackage;
+import org.eclipse.sirius.viewpoint.description.Group;
+import org.eclipse.sirius.viewpoint.description.JavaExtension;
+import org.eclipse.sirius.viewpoint.description.RepresentationDescription;
+import org.eclipse.sirius.viewpoint.description.Viewpoint;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+
+/**
+ * Utility methods to navigate inside a VSM, especially wrt properties
+ * descriptions.
+ *
+ * @author pcdavid
+ */
+public final class VSMNavigation {
+ private VSMNavigation() {
+ // Preven instanciation.
+ }
+
+ /**
+ * Tests whether a model element is part of a Sirius properties view
+ * description.
+ *
+ * @param vsmElement
+ * the element to test.
+ * @return <code>true</code> if the element is part of a Sirius properties
+ * view description.
+ */
+ public static boolean isInsideViewExtensionDescription(EObject vsmElement) {
+ return new EObjectQuery(vsmElement).getFirstAncestorOfType(PropertiesPackage.Literals.VIEW_EXTENSION_DESCRIPTION).some();
+ }
+
+ /**
+ * Returns the domain class of a given {@link PageDescription}, defaulting
+ * to a generic catch-all type if no value was set explicitly.
+ *
+ * @param page
+ * a {@link PageDescription}.
+ * @return the names of potential domain classes for that page.
+ */
+ public static Collection<String> getPageDomainClass(PageDescription page) {
+ if (page != null && !Util.isBlank(page.getDomainClass())) {
+ return Collections.singleton(page.getDomainClass());
+ } else {
+ return Collections.singleton(TypeName.EOBJECT_TYPENAME.getCompleteName());
+ }
+ }
+
+ /**
+ * Returns the domain class of a given {@link GroupDescription}, defaulting
+ * to the union of all the possible domain classes from pages which
+ * reference that group if no value was set explicitly.
+ *
+ * @param group
+ * a {@link GroupDescription}.
+ * @return the names of potential domain classes for that group.
+ */
+ public static Collection<String> getGroupDomainClass(GroupDescription group) {
+ if (group != null && !Util.isBlank(group.getDomainClass())) {
+ return Collections.singleton(group.getDomainClass());
+ } else {
+ Collection<String> result = Sets.newLinkedHashSet();
+ for (PageDescription page : VSMNavigation.findReferencingPages(group)) {
+ result.addAll(getPageDomainClass(page));
+ }
+ return result;
+ }
+ }
+
+ /**
+ * Returns the domain class of a VSM element from inside a
+ * {@link GroupDescription} (for example a widget).
+ *
+ * @param vsmElement
+ * the VSM element.
+ * @return the domain class of the VSM element, as determined by the
+ * enclosing {@link GroupDescription}.
+ */
+ public static Option<Collection<String>> getDomainClassFromContainingGroup(EObject vsmElement) {
+ Option<Collection<String>> result = Options.newNone();
+ GroupDescription group = VSMNavigation.findClosestGroupDescription(vsmElement);
+ if (group != null) {
+ result = Options.newSome(getGroupDomainClass(group));
+ }
+ return result;
+ }
+
+ /**
+ * Get all the representation description defined in the same VSM as a given
+ * element.
+ *
+ * @param vsmElement
+ * a VSM element.
+ * @return all the representation description defined in the same VSM.
+ */
+ public static Collection<RepresentationDescription> getRepresentationDescriptionsInVSM(EObject vsmElement) {
+ Collection<RepresentationDescription> result = Lists.newArrayList();
+ Option<EObject> answer = getVSMRoot(vsmElement);
+ if (answer.some()) {
+ Group group = (Group) answer.get();
+ for (Viewpoint viewpoint : group.getOwnedViewpoints()) {
+ result.addAll(viewpoint.getOwnedRepresentations());
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Finds all the Java extensions registered in the VSM of the specified
+ * element.
+ *
+ * @param vsmElement
+ * an element from a VSM model.
+ * @return the qualified names of all the Java extensions registered in the
+ * same VSM.
+ */
+ public static Collection<String> getJavaExtensionsInVSM(EObject vsmElement) {
+ Collection<String> result = Lists.newArrayList();
+ Option<EObject> answer = getVSMRoot(vsmElement);
+ if (answer.some()) {
+ Group group = (Group) answer.get();
+ for (Viewpoint vp : group.getOwnedViewpoints()) {
+ for (JavaExtension dep : vp.getOwnedJavaExtensions()) {
+ if (!StringUtil.isEmpty(dep.getQualifiedClassName())) {
+ result.add(dep.getQualifiedClassName());
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ private static Option<EObject> getVSMRoot(EObject vsmElement) {
+ return new EObjectQuery(vsmElement).getFirstAncestorOfType(DescriptionPackage.Literals.GROUP);
+ }
+
+ /**
+ * Find which pages reference a given group in a VSM. Groups are not
+ * contained insides pages, but referenced from pages defined inside the
+ * same {@link ViewExtensionDescription}.
+ *
+ * @param group
+ * a group.
+ * @return all the pages inside the same ViewExtensionDescription as the
+ * group that reference it.
+ */
+ public static Set<PageDescription> findReferencingPages(GroupDescription group) {
+ EObject container = group.eContainer();
+ if (container instanceof ViewExtensionDescription) {
+ ViewExtensionDescription ved = (ViewExtensionDescription) container;
+ Set<PageDescription> result = Sets.newLinkedHashSet();
+ for (PageDescription page : ved.getPages()) {
+ if (page.getGroups().contains(group)) {
+ result.add(page);
+ }
+ }
+ return result;
+ } else {
+ return Collections.emptySet();
+ }
+ }
+
+ /**
+ * Returns the {@link GroupDescription} enclosing a given VSM element, if
+ * any.
+ *
+ * @param vsmElement
+ * a VSM element.
+ * @return the {@link GroupDescription} enclosing the element, or
+ * <code>null</code> if none could be found.
+ */
+ public static GroupDescription findClosestGroupDescription(EObject vsmElement) {
+ if (vsmElement instanceof GroupDescription) {
+ return (GroupDescription) vsmElement;
+ } else {
+ Option<EObject> answer = new EObjectQuery(vsmElement).getFirstAncestorOfType(PropertiesPackage.Literals.GROUP_DESCRIPTION);
+ return answer.some() ? (GroupDescription) answer.get() : null;
+ }
+ }
+}

Back to the top