blob: 88399111ece59abf86159af797b9fc643347014e [file] [log] [blame]
/*****************************************************************************
* Copyright (c) 2019 CEA LIST, and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Nicolas FAUVERGUE (CEA LIST) nicolas.fauvergue@cea.fr - Initial API and implementation
*
*****************************************************************************/
package org.eclipse.papyrus.sysml16.diagram.common.css.dom;
import java.util.LinkedList;
import java.util.List;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.gmf.runtime.emf.type.core.ElementTypeRegistry;
import org.eclipse.gmf.runtime.emf.type.core.IElementMatcher;
import org.eclipse.gmf.runtime.emf.type.core.ISpecializationType;
import org.eclipse.gmf.runtime.notation.BasicCompartment;
import org.eclipse.gmf.runtime.notation.DecorationNode;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.papyrus.infra.gmfdiag.css.dom.GMFElementAdapter;
import org.eclipse.papyrus.infra.gmfdiag.css.engine.ExtendedCSSEngine;
import org.eclipse.papyrus.infra.tools.util.ListHelper;
import org.eclipse.papyrus.sysml16.diagram.common.css.helper.CSSDOMSYSMLSemanticElementHelper;
import org.eclipse.papyrus.sysml16.service.types.util.SysMLServiceTypeUtil;
import org.eclipse.papyrus.sysml16.util.DeprecatedElementUtil;
import org.eclipse.papyrus.uml.diagram.common.stereotype.display.helper.StereotypeDisplayConstant;
import org.eclipse.papyrus.uml.diagram.common.stereotype.display.helper.StereotypeDisplayUtil;
import org.eclipse.uml2.uml.AcceptEventAction;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Event;
import org.eclipse.uml2.uml.NamedElement;
import org.eclipse.uml2.uml.Property;
import org.eclipse.uml2.uml.Stereotype;
import org.eclipse.uml2.uml.TimeEvent;
import org.eclipse.uml2.uml.Trigger;
import org.eclipse.uml2.uml.Type;
import org.eclipse.uml2.uml.TypedElement;
/**
* DOM Element Adapter for SYSML Elements
*
* Supports applied stereotypes and stereotype properties
*/
public class GMFSYSMLElementAdapter extends GMFElementAdapter {
/**
* Name of the CSS Simple Selector to match on the Stereotype Compartment Shape
*/
private static final String STEREOTYPE_COMMENT = "StereotypeComment"; //$NON-NLS-1$
/** The stereotype helper. */
public final StereotypeDisplayUtil stereotypeHelper = StereotypeDisplayUtil.getInstance();
/** The Constant IS_CONSTRAINT. */
private static final String IS_CONSTRAINT = "isConstraint"; //$NON-NLS-1$
/** The Constant IS_PART. */
private static final String IS_PART = "isPart"; //$NON-NLS-1$
/** The Constant IS_REFERENCE. */
private static final String IS_REFERENCE = "isReference"; //$NON-NLS-1$
/** The Constant APPLIED_STEREOTYPES_PROPERTY. */
public static final String APPLIED_STEREOTYPES_PROPERTY = "appliedStereotypes"; //$NON-NLS-1$
/** The Constant TYPE_APPLIED_STEREOTYPES_PROPERTY */
private static final String TYPE_APPLIED_STEREOTYPES_PROPERTY = "typeAppliedStereotypes"; //$NON-NLS-1$
/** The Constant DEPRECATED. */
public static final String DEPRECATED = "deprecated"; //$NON-NLS-1$
/** The Constant IS_ABSTRACT. */
private static final String IS_ABSTRACT = "isAbstract"; //$NON-NLS-1$
/** The Constant IS_TIME_EVENT_ACTION. */
private static final String IS_TIME_EVENT_ACTION_PROPERTY = "isTimeEventAction"; //$NON-NLS-1$
/** The Constant IS_FRAMEZABLE. */
public static final String IS_FRAME = "isFrame"; //$NON-NLS-1$
/**
* The CSS Separator for qualifiers, when we must use CSS ID
* When we can use CSS String, we use the standard UML "::" qualifier separator
*
* NOTE: Separator "__" does not work
*/
public static final String QUALIFIER_SEPARATOR = "--"; //$NON-NLS-1$
public GMFSYSMLElementAdapter(View view, ExtendedCSSEngine engine) {
super(view, engine);
helper = CSSDOMSYSMLSemanticElementHelper.getInstance();
}
/**
* {@inheritDoc}
*
* Applied Stereotypes are manipulated as DOM Attributes
*/
@Override
protected String doGetAttribute(String attr) {
String parentValue = super.doGetAttribute(attr);
if (parentValue != null) {
return parentValue;
}
// This is present only for performance issues
// isAbstract isn't a SysML feature but will be called many time for UML
// and is very slow to answer (Check : L172)
if (IS_ABSTRACT.equals(attr)) {
return null;
}
// get stereotype Label attribute
if (stereotypeHelper.isStereotypeLabel(semanticElement)) {
String value = getStereotypeLabelAttribute(attr);
if (value != null && !value.isEmpty()) {
return value;
}
}
// get stereotype Compartment attribute
if (stereotypeHelper.isStereotypeCompartment(semanticElement) || stereotypeHelper.isStereotypeBrace(semanticElement)) {
String value = getStereotypeCompartmentAttribute(attr);
if (value != null && !value.isEmpty()) {
return value;
}
}
// get stereotype Property attribute
if (stereotypeHelper.isStereotypeProperty(semanticElement) || stereotypeHelper.isStereotypeBraceProperty(semanticElement)) {
String value = getStereotypePropertyAttribute(attr);
if (value != null && !value.isEmpty()) {
return value;
}
}
if (semanticElement instanceof Element) {
// Applied stereotypes
Element currentElement = (Element) semanticElement;
// IMPORTANT set the faster test first
if (DEPRECATED.equals(attr)) {
return String.valueOf(DeprecatedElementUtil.isDeprecatedElement(semanticElement));
}
boolean isProperty = semanticElement instanceof Property;
// manage of isConstraint=true attribute for Property
if (IS_CONSTRAINT.equals(attr) && isProperty) {
IElementMatcher constraint = ((ISpecializationType) ElementTypeRegistry.getInstance().getType(SysMLServiceTypeUtil.ORG_ECLIPSE_PAPYRUS_SYSML16_CONSTRAINTPROPERTY)).getMatcher();
return String.valueOf(constraint.matches((Property) semanticElement));
}
// manage of isPart=true attribute for Property
if (IS_PART.equals(attr) && isProperty) {
IElementMatcher part = ((ISpecializationType) ElementTypeRegistry.getInstance().getType(SysMLServiceTypeUtil.ORG_ECLIPSE_PAPYRUS_SYSML16_PART)).getMatcher();
return String.valueOf(part.matches((Property) semanticElement));
}
// manage of isReference=true attribute for Property
if (IS_REFERENCE.equals(attr) && isProperty) {
IElementMatcher reference = ((ISpecializationType) ElementTypeRegistry.getInstance().getType(SysMLServiceTypeUtil.ORG_ECLIPSE_PAPYRUS_SYSML16_REFERENCE)).getMatcher();
return String.valueOf(reference.matches((Property) semanticElement));
}
// Get applied STereotypes Attributes
if (APPLIED_STEREOTYPES_PROPERTY.equals(attr)) {
List<String> appliedStereotypes = new LinkedList<String>();
for (Stereotype stereotype : currentElement.getAppliedStereotypes()) {
appliedStereotypes.add(stereotype.getName());
appliedStereotypes.add(stereotype.getQualifiedName());
}
if (!appliedStereotypes.isEmpty()) {
return ListHelper.deepToString(appliedStereotypes, CSS_VALUES_SEPARATOR);
}
return null;
}
if (TYPE_APPLIED_STEREOTYPES_PROPERTY.equals(attr) && semanticElement instanceof TypedElement) {
Type type = ((TypedElement) semanticElement).getType();
if (type != null) {
List<String> appliedStereotypes = new LinkedList<>();
for (Stereotype stereotype : type.getAppliedStereotypes()) {
appliedStereotypes.add(stereotype.getName());
appliedStereotypes.add(stereotype.getQualifiedName());
}
if (!appliedStereotypes.isEmpty()) {
return ListHelper.deepToString(appliedStereotypes, CSS_VALUES_SEPARATOR);
}
}
}
for (EObject stereotypeApplication : currentElement.getStereotypeApplications()) {
EStructuralFeature feature = stereotypeApplication.eClass().getEStructuralFeature(attr);
if (feature != null) {
if (feature.isMany()) {
List<?> values = (List<?>) stereotypeApplication.eGet(feature);
List<String> cssValues = new LinkedList<String>();
for (Object value : values) {
cssValues.add(getCSSValue(feature, value));
}
return ListHelper.deepToString(cssValues, CSS_VALUES_SEPARATOR);
} else {
Object value = stereotypeApplication.eGet(feature);
return getCSSValue(feature, value);
}
}
return null;
}
if (attr.contains(QUALIFIER_SEPARATOR)) {
List<String> qualifiers = ListHelper.asList(attr.split(QUALIFIER_SEPARATOR)); // Writable list
String propertyName = qualifiers.remove(qualifiers.size() - 1); // Last element is the property name
// Remaining strings can be used to build the Stereotype's qualified name
String stereotypeName = ListHelper.deepToString(qualifiers, "::"); //$NON-NLS-1$
Stereotype appliedStereotype = currentElement.getAppliedStereotype(stereotypeName);
if (appliedStereotype != null) {
EObject stereotypeApplication = currentElement.getStereotypeApplication(appliedStereotype);
EStructuralFeature feature = stereotypeApplication.eClass().getEStructuralFeature(propertyName);
if (feature != null) {
Object value = stereotypeApplication.eGet(feature);
return getCSSValue(feature, value);
}
}
}
// manage of isTimeEventAction=true attribute for AcceptEventAction
if (IS_TIME_EVENT_ACTION_PROPERTY.equals(attr)) {
if (semanticElement instanceof AcceptEventAction) {
return String.valueOf(isAcceptTimeEventAction((AcceptEventAction) semanticElement));
}
}
// manage of isFraezable=true attribute for displaying header/frame
if (IS_FRAME.equals(attr)) {
if (notationElement.eContainer() == notationElement.getDiagram()) {
return String.valueOf(true);
} else {
return String.valueOf(false);
}
}
}
return null;
}
/**
* Retrieve the Matching String Value for the StereotypeCompartment Element
*
* @param attr
* Attribute of the String to match with
* @return The matching value for this Attribute
*/
protected String getStereotypeCompartmentAttribute(String attr) {
if (StereotypeDisplayConstant.STEREOTYPE_COMPARTMENT_NAME.equals(attr)) {
BasicCompartment propertyCompartment = (BasicCompartment) semanticElement;
return stereotypeHelper.getName(propertyCompartment);
}
return "";//$NON-NLS-1$
}
/**
* Retrieve the Matching String Value for the StereotypeCompartment Element
*
* @param attr
* Attribute of the String to match with
* @return The matching value for this Attribute
*/
protected String getStereotypePropertyAttribute(String attr) {
// CSS can match property level
if (StereotypeDisplayConstant.STEREOTYPE_PROPERTY_NAME.equals(attr)) {
DecorationNode propertyLabel = (DecorationNode) semanticElement;
if (propertyLabel.getElement() instanceof Property) {
Property prop = (Property) propertyLabel.getElement();
return prop.getName();
}
// CSS can match Container Name
} else if (StereotypeDisplayConstant.STEREOTYPE_COMPARTMENT_NAME.equals(attr)) {
EObject propertyCompartment = ((DecorationNode) semanticElement).eContainer();
if (stereotypeHelper.isStereotypeCompartment(propertyCompartment)) {
return stereotypeHelper.getName((DecorationNode) propertyCompartment);
}
}
return "";//$NON-NLS-1$
}
/**
* Get the matching Value of the Attribute
*
* @param attr
* Attribute of the String to match with
* @return The matching value for this Attribute
*/
protected String getStereotypeLabelAttribute(String attr) {
if (StereotypeDisplayConstant.STEREOTYPE_LABEL_NAME.equals(attr)) {
DecorationNode label = (DecorationNode) semanticElement;
return stereotypeHelper.getName(label);
}
if (KIND.equals(attr) && stereotypeHelper.isStereotypeLabel(semanticElement)) {
return StereotypeDisplayConstant.STEREOTYPE_LABEL_TYPE;
}
return null;
}
@Override
protected String getCSSValue(EStructuralFeature feature, Object value) {
if (feature instanceof EReference && value instanceof NamedElement) {
String name = ((NamedElement) value).getName();
return name == null || name.isEmpty() ? EMPTY_VALUE : name; // Bug 467716: Never return null or empty string if the value is not null
}
return super.getCSSValue(feature, value);
}
/**
* @see org.eclipse.papyrus.infra.gmfdiag.css.dom.GMFElementAdapter#getLocalName()
*
* @return The Local name for the CSS matching.
*/
@Override
public String getLocalName() {
// In case of StereotypeComment type, the selector should match on the Stereotype Comment.
if (localName == null && stereotypeHelper.isStereotypeComment(getNotationElement())) {
return STEREOTYPE_COMMENT;
}
return super.getLocalName();
}
/**
* Checks if is accept time event action.
*
* @param action
* the action
* @return true, if is accept time event action
*/
public boolean isAcceptTimeEventAction(AcceptEventAction action) {
boolean hasTimeEvent = false;
boolean hasOthersTriggers = false;
// Get triggers
if (action.getTriggers() != null) {
for (Trigger trigger : action.getTriggers()) {
if (trigger != null) {
Event event = trigger.getEvent();
if (event instanceof TimeEvent) {
hasTimeEvent = true;
} else {
hasOthersTriggers = true;
}
}
}
}
// only time events have been encountered.
return hasTimeEvent && !hasOthersTriggers;
}
}