blob: 2a97e35cadd2c2c4d81dd42628e30f4cdfd36bcc [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.service.types.advice;
import java.util.Arrays;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.gmf.runtime.common.core.command.CompositeCommand;
import org.eclipse.gmf.runtime.common.core.command.ICommand;
import org.eclipse.gmf.runtime.common.core.command.UnexecutableCommand;
import org.eclipse.gmf.runtime.emf.type.core.ElementTypeRegistry;
import org.eclipse.gmf.runtime.emf.type.core.ISpecializationType;
import org.eclipse.gmf.runtime.emf.type.core.edithelper.AbstractEditHelperAdvice;
import org.eclipse.gmf.runtime.emf.type.core.requests.CreateRelationshipRequest;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.papyrus.sysml16.service.types.command.UpdateNestedPathConnectorEnd;
import org.eclipse.papyrus.sysml16.service.types.util.ConnectorUtil;
import org.eclipse.papyrus.sysml16.service.types.util.SysMLServiceTypeUtil;
import org.eclipse.papyrus.sysml16.service.types.util.UMLConnectorUtils;
import org.eclipse.papyrus.uml.service.types.element.UMLElementTypes;
import org.eclipse.papyrus.uml.service.types.utils.RequestParameterUtils;
import org.eclipse.uml2.uml.ConnectableElement;
/**
* 8.3.2.3 Block
* the service edit must implement the following constraints
* isEncapsulated: Boolean [0..1]
* If true, then the block is treated as a black box; a part typed by this black box can only be connected via its ports or
* directly to its outer boundary. If false, or if a value is not present, then connections can be established to elements of
* its internal structure via deep-nested connector ends.
*/
public class ConnectorCreationEditHelperAdvice extends AbstractEditHelperAdvice {
private UMLConnectorUtils utils = new UMLConnectorUtils();
/**
* @see org.eclipse.gmf.runtime.emf.type.core.edithelper.AbstractEditHelperAdvice#getBeforeCreateRelationshipCommand(org.eclipse.gmf.runtime.emf.type.core.requests.CreateRelationshipRequest)
*
* @param request
* @return
*/
@Override
protected ICommand getBeforeCreateRelationshipCommand(CreateRelationshipRequest request) {
EObject source = request.getSource();
EObject target = request.getTarget();
EObject container = request.getContainer();
View sourceView = RequestParameterUtils.getSourceView(request);
View targetView = RequestParameterUtils.getTargetView(request);
// Restrict this advice action to the end of Connector creation gesture (before clicking on target)
// in order to add SysML specific constraint
if ((Arrays.asList(request.getElementType().getAllSuperTypes()).contains(UMLElementTypes.CONNECTOR))
&& (source != null) && (target != null) && (container != null)) {
// Restrict action to SysML Connector (meaning owned by Block)
if (((ISpecializationType) ElementTypeRegistry.getInstance().getType(SysMLServiceTypeUtil.ORG_ECLIPSE_PAPYRUS_SYSML16_BLOCK)).getMatcher().matches(container)
|| ((ISpecializationType) ElementTypeRegistry.getInstance().getType(SysMLServiceTypeUtil.ORG_ECLIPSE_PAPYRUS_SYSML16_CONSTRAINTBLOCK)).getMatcher().matches(container)) {
// If the source or target view is enclosed in a structure encapsulated view, forbid creation.
if (ConnectorUtil.isCrossingEncapsulation(sourceView, targetView)
|| ConnectorUtil.isCrossingEncapsulation(targetView, sourceView)) {
return UnexecutableCommand.INSTANCE;
}
if (canCreate(source, target, sourceView, targetView)) {
request.setParameter(org.eclipse.papyrus.uml.service.types.utils.RequestParameterConstants.UML_STRICT, false);
}
}
}
return super.getBeforeCreateRelationshipCommand(request);
}
/**
* @see org.eclipse.gmf.runtime.emf.type.core.edithelper.AbstractEditHelperAdvice#getAfterCreateRelationshipCommand(org.eclipse.gmf.runtime.emf.type.core.requests.CreateRelationshipRequest)
*
* @param request
* @return
*/
@Override
protected ICommand getAfterCreateRelationshipCommand(CreateRelationshipRequest request) {
ICommand defaultCommand = super.getAfterCreateRelationshipCommand(request);
EObject container = request.getContainer();
View sourceView = RequestParameterUtils.getSourceView(request);
View targetView = RequestParameterUtils.getTargetView(request);
// Restrict this advice action to the end of Connector creation gesture (before clicking on target)
// in order to add SysML specific constraint
if ((Arrays.asList(request.getElementType().getAllSuperTypes()).contains(UMLElementTypes.CONNECTOR))
&& (request.getSource() != null) && (request.getTarget() != null) && (container != null)) {
// Restrict action to SysML Connector (meaning owned by Block)
if (((ISpecializationType) ElementTypeRegistry.getInstance().getType(SysMLServiceTypeUtil.ORG_ECLIPSE_PAPYRUS_SYSML16_BLOCK)).getMatcher().matches(container)
|| ((ISpecializationType) ElementTypeRegistry.getInstance().getType(SysMLServiceTypeUtil.ORG_ECLIPSE_PAPYRUS_SYSML16_CONSTRAINTBLOCK)).getMatcher().matches(container)) {
UpdateNestedPathConnectorEnd updateNestedPathConnectorEndSource = new UpdateNestedPathConnectorEnd("UpdateNestedPathConnectorEnd Source", sourceView, request, true);
defaultCommand = CompositeCommand.compose(defaultCommand, updateNestedPathConnectorEndSource);
UpdateNestedPathConnectorEnd updateNestedPathConnectorEndTarget = new UpdateNestedPathConnectorEnd("UpdateNestedPathConnectorEnd Target", targetView, request, false);
defaultCommand = CompositeCommand.compose(defaultCommand, updateNestedPathConnectorEndTarget);
}
}
return defaultCommand;
}
/**
* Test if the relationship creation is allowed.
*
* @param source
* the relationship source can be null
* @param target
* the relationship target can be null
* @param sourceView
* the relationship graphical source can be null
* @param targetView
* the relationship graphical target can be null
* @return true if the creation is allowed
*/
//FIXME test creation should be done in approve request
private boolean canCreate(EObject source, EObject target, View sourceView, View targetView) {
if ((source != null) && !(source instanceof ConnectableElement)) {
return false;
}
if ((target != null) && !(target instanceof ConnectableElement)) {
return false;
}
if ((sourceView != null) && (targetView != null)) {
// Cannot create a connector from a view representing a Part to its own Port (or the opposite)
if ((sourceView.getChildren().contains(targetView)) || (targetView.getChildren().contains(sourceView))) {
return false;
}
// Cannot connect a Part to one of its (possibly indirect) containment, must connect to one of its Port.
if (utils.getStructureContainers(sourceView).contains(targetView) || utils.getStructureContainers(targetView).contains(sourceView)) {
return false;
}
}
return true;
}
}