/***************************************************************************** * Copyright (c) 2009-2011 CEA LIST. * * * 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: * Yann Tanguy (CEA LIST) yann.tanguy@cea.fr - Initial API and implementation * *****************************************************************************/ package org.eclipse.papyrus.uml.diagram.composite.custom.edit.command; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.emf.ecore.EObject; import org.eclipse.gef.EditPart; import org.eclipse.gmf.runtime.common.core.command.CommandResult; import org.eclipse.gmf.runtime.common.core.command.ICommand; import org.eclipse.gmf.runtime.diagram.ui.editparts.GraphicalEditPart; import org.eclipse.gmf.runtime.emf.type.core.IElementType; import org.eclipse.gmf.runtime.emf.type.core.requests.ConfigureRequest; import org.eclipse.gmf.runtime.emf.type.core.requests.CreateElementRequest; import org.eclipse.gmf.runtime.emf.type.core.requests.CreateRelationshipRequest; import org.eclipse.papyrus.uml.diagram.composite.custom.edit.policies.GraphicalNodeEditPolicy; import org.eclipse.papyrus.uml.diagram.composite.custom.messages.Messages; import org.eclipse.papyrus.uml.diagram.composite.providers.ElementInitializers; import org.eclipse.uml2.uml.ConnectableElement; import org.eclipse.uml2.uml.Connector; import org.eclipse.uml2.uml.ConnectorEnd; import org.eclipse.uml2.uml.Port; import org.eclipse.uml2.uml.Property; import org.eclipse.uml2.uml.StructuredClassifier; import org.eclipse.uml2.uml.UMLFactory; /** * <pre> * This class is a custom creation command for Connector. * * Difficulties for Connector creation: * - differences between semantic (ConnectableEnd) graphical (ConnectableElement) ends of Connector * - requires to know not only the graphical end (Port, Property) but also the graphical parent in case of Port. * * The Connector source and target are declared as ConnectorEnd in the GMFGEN model to ensure correct validation, * but the real source and target are ConnectableElement. * * </pre> */ public class ConnectorCreateCommand extends org.eclipse.papyrus.uml.diagram.composite.edit.commands.ConnectorCreateCommand { /** Graphical parent of Source **/ protected Property sourcePartWithPort = null; /** Graphical parent of Target **/ protected Property targetPartWithPort = null; /** Graphical EditPart of Source **/ protected GraphicalEditPart sourceGraphicalEditPart = null; /** Graphical EditPart of Target **/ protected GraphicalEditPart targetGraphicalEditPart = null; /** * Constructor of Connector custom creation command * * @param req * the creation request * @param source * the connector source element * @param target * the connector target element */ public ConnectorCreateCommand(CreateRelationshipRequest req, EObject source, EObject target) { super(req, source, target); // Resolve graphical parents of source and target store in request as Parameters // These parameters are added in request by (custom) GraphicalNodeEditPolicy if(req.getParameter(GraphicalNodeEditPolicy.CONNECTOR_CREATE_REQUEST_SOURCE_PARENT) instanceof Property) { sourcePartWithPort = (Property)req.getParameter(GraphicalNodeEditPolicy.CONNECTOR_CREATE_REQUEST_SOURCE_PARENT); } if(req.getParameter(GraphicalNodeEditPolicy.CONNECTOR_CREATE_REQUEST_TARGET_PARENT) instanceof Property) { targetPartWithPort = (Property)req.getParameter(GraphicalNodeEditPolicy.CONNECTOR_CREATE_REQUEST_TARGET_PARENT); } if(req.getParameter(GraphicalNodeEditPolicy.CONNECTOR_CREATE_REQUEST_SOURCE_GRAPHICAL) instanceof GraphicalEditPart) { sourceGraphicalEditPart = (GraphicalEditPart)req.getParameter(GraphicalNodeEditPolicy.CONNECTOR_CREATE_REQUEST_SOURCE_GRAPHICAL); } if(req.getParameter(GraphicalNodeEditPolicy.CONNECTOR_CREATE_REQUEST_TARGET_GRAPHICAL) instanceof GraphicalEditPart) { targetGraphicalEditPart = (GraphicalEditPart)req.getParameter(GraphicalNodeEditPolicy.CONNECTOR_CREATE_REQUEST_TARGET_GRAPHICAL); } container = deduceContainer(_getSource(), _getTarget()); } /** * Replaces the original getter which is cast as ConnectorEnd (expected end of Connector) * * @return the element that is graphically connected to Connector as source */ protected ConnectableElement _getSource() { return (ConnectableElement)source; } /** * Replaces the original getter which is cast as ConnectorEnd (expected end of Connector) * * @return the element that is graphically connected to Connector as target */ protected ConnectableElement _getTarget() { return (ConnectableElement)target; } /** * <pre> * Checks if the Connector can be created or not. * * {@inheritDoc} * </pre> */ @Override public boolean canExecute() { if((source == null) && (target == null)) { return false; } if((source != null) && !(source instanceof ConnectableElement)) { return false; } if((target != null) && !(target instanceof ConnectableElement)) { return false; } if(source == null) { return true; // link creation is in progress; source is not defined yet } if((target != null) && (getContainer() == null)) { return false; } // return // UMLBaseItemSemanticEditPolicy.LinkConstraints.canCreateConnector_4013(getContainer(), // _getSource(), // _getTarget()); // this returns true anyway... return true; } /** * <pre> * Creates the new Connector. * * {@inheritDoc} * </pre> */ @Override protected CommandResult doExecuteWithResult(IProgressMonitor monitor, IAdaptable info) throws ExecutionException { if(!canExecute()) { throw new ExecutionException(Messages.ConnectorCreateCommand_INVALID_ARGS_MSG); } Connector newElement = UMLFactory.eINSTANCE.createConnector(); getContainer().getOwnedConnectors().add(newElement); ConnectorEnd end0 = UMLFactory.eINSTANCE.createConnectorEnd(); end0.setLower(1); end0.setUpper(1); if(_getSource() instanceof Port) { end0.setRole((Port)_getSource()); end0.setPartWithPort(sourcePartWithPort); } else if(_getSource() instanceof ConnectableElement) { end0.setRole((ConnectableElement)_getSource()); } else { throw new ExecutionException(Messages.ConnectorCreateCommand_INVALID_SOURCE_MSG); } ConnectorEnd end1 = UMLFactory.eINSTANCE.createConnectorEnd(); end1.setLower(1); end1.setUpper(1); if(_getTarget() instanceof Port) { end1.setRole((Port)_getTarget()); end1.setPartWithPort(targetPartWithPort); } else if(_getTarget() instanceof ConnectableElement) { end1.setRole((ConnectableElement)_getTarget()); } else { throw new ExecutionException(Messages.ConnectorCreateCommand_INVALID_TARGET_MSG); } newElement.getEnds().add(end0); newElement.getEnds().add(end1); ElementInitializers.getInstance().init_Connector_4013(newElement); doConfigure(newElement, monitor, info); ((CreateElementRequest)getRequest()).setNewElement(newElement); return CommandResult.newOKCommandResult(newElement); } /** * <pre> * This method is the exact copy of the inherited method, except that it uses the local getters * (_getSource(), _getTarget()). * * {@inheritDoc} * </pre> */ @Override protected void doConfigure(Connector newElement, IProgressMonitor monitor, IAdaptable info) throws ExecutionException { IElementType elementType = ((CreateElementRequest)getRequest()).getElementType(); ConfigureRequest configureRequest = new ConfigureRequest(getEditingDomain(), newElement, elementType); configureRequest.setClientContext(((CreateElementRequest)getRequest()).getClientContext()); configureRequest.addParameters(getRequest().getParameters()); configureRequest.setParameter(CreateRelationshipRequest.SOURCE, _getSource()); configureRequest.setParameter(CreateRelationshipRequest.TARGET, _getTarget()); ICommand configureCommand = elementType.getEditCommand(configureRequest); if(configureCommand != null && configureCommand.canExecute()) { configureCommand.execute(monitor, info); } } /** * * Tries to find a common StructuredClassifier container to add the new Connector. * * @see org.eclipse.papyrus.uml.diagram.composite.edit.commands.ConnectorCreateCommand#deduceContainer(org.eclipse.emf.ecore.EObject, * org.eclipse.emf.ecore.EObject) * * @param source * the source object * @param target * the target object * @return a common StructuredClassifier container (graphical search) */ @Override protected StructuredClassifier deduceContainer(EObject source, EObject target) { StructuredClassifier containerProposedBySource = proposedContainer(sourceGraphicalEditPart); StructuredClassifier containerProposedByTarget = proposedContainer(targetGraphicalEditPart); StructuredClassifier deducedContainer = null; if((containerProposedBySource != null) && (containerProposedByTarget != null)) { if(containerProposedBySource == containerProposedByTarget) { deducedContainer = containerProposedBySource; } } return deducedContainer; } /** * Parse graphical parent of the graphicalEditPart until a StructureClassifier is found. * * @param graphicalEditPart * the graphical edit part * @return null or a StructuredClassifier that graphically contains the graphicalEditPart */ private StructuredClassifier proposedContainer(GraphicalEditPart graphicalEditPart) { for(EditPart ep = graphicalEditPart; ep != null; ep = ep.getParent()) { if(ep instanceof GraphicalEditPart) { GraphicalEditPart parent = (GraphicalEditPart)ep; EObject semanticParent = parent.resolveSemanticElement(); if(semanticParent instanceof StructuredClassifier) { return (StructuredClassifier)semanticParent; } } } return null; } }