/***************************************************************************** * Copyright (c) 2011-2012 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: * * CEA LIST - Initial API and implementation * *****************************************************************************/ package org.eclipse.papyrus.uml.service.types.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.emf.ecore.util.EcoreUtil; import org.eclipse.gmf.runtime.common.core.command.CommandResult; import org.eclipse.gmf.runtime.diagram.core.util.ViewUtil; import org.eclipse.gmf.runtime.emf.type.core.commands.EditElementCommand; import org.eclipse.gmf.runtime.emf.type.core.requests.ReorientRelationshipRequest; import org.eclipse.gmf.runtime.notation.Edge; import org.eclipse.gmf.runtime.notation.View; import org.eclipse.papyrus.uml.service.types.utils.ConnectorUtils; import org.eclipse.papyrus.uml.service.types.utils.NamedElementHelper; import org.eclipse.papyrus.uml.service.types.utils.RequestParameterUtils; import org.eclipse.uml2.uml.ConnectableElement; import org.eclipse.uml2.uml.Connector; import org.eclipse.uml2.uml.ConnectorEnd; import org.eclipse.uml2.uml.Element; import org.eclipse.uml2.uml.Port; import org.eclipse.uml2.uml.Property; import org.eclipse.uml2.uml.StructuredClassifier; /** * <pre> * Re-orient command for binary {@link Connector}. * </pre> */ public class ConnectorReorientCommand extends EditElementCommand { private final int reorientDirection; private final EObject oldEnd; private final EObject newEnd; private final View newEndView; private final View oppositeEndView; private final Edge reorientedEdgeView; private ConnectorUtils utils = new ConnectorUtils(); /** * Constructor. */ public ConnectorReorientCommand(ReorientRelationshipRequest request) { super(request.getLabel(), request.getRelationship(), request); reorientDirection = request.getDirection(); oldEnd = request.getOldRelationshipEnd(); newEnd = request.getNewRelationshipEnd(); reorientedEdgeView = RequestParameterUtils.getReconnectedEdge(request); newEndView = RequestParameterUtils.getReconnectedEndView(request); oppositeEndView = (reorientDirection == ReorientRelationshipRequest.REORIENT_SOURCE) ? reorientedEdgeView.getTarget() : reorientedEdgeView.getSource(); } /** * Test if the command can be executed. */ public boolean canExecute() { if(!(getElementToEdit() instanceof Connector)) { return false; } if(getLink().getEnds().size() != 2) { return false; } return canReorient(newEndView, oppositeEndView); } private boolean canReorient(View newEndView, View oppositeEndView) { // Verify possible type of new source if((newEndView.getElement() == null) || !(newEndView.getElement() instanceof ConnectableElement)) { return false; } if((newEndView != null) && (oppositeEndView != null)) { // Cannot create a self connector on a view if(newEndView == oppositeEndView) { return false; } // Cannot create a connector from a view representing a Part to its own Port (or the opposite) if((newEndView.getChildren().contains(oppositeEndView)) || (oppositeEndView.getChildren().contains(newEndView))) { return false; } // Cannot connect two Port owned by the same view if ((newEndView.getElement() instanceof Port) && (oppositeEndView.getElement() instanceof Port)) { if (ViewUtil.getContainerView(newEndView) == ViewUtil.getContainerView(oppositeEndView)) { return false; } } // Cannot connect a Part to one of its (possibly indirect) containment, must connect to one of its Port. if (utils.getStructureContainers(newEndView).contains(oppositeEndView) || utils.getStructureContainers(oppositeEndView).contains(newEndView)) { return false; } // Ensure container can be deduced if(deduceContainer(newEndView, oppositeEndView) == null) { return false; } } return true; } protected CommandResult doExecuteWithResult(IProgressMonitor monitor, IAdaptable info) throws ExecutionException { if(!canExecute()) { throw new ExecutionException("Invalid arguments in reorient link command"); //$NON-NLS-1$ } EObject oldOwner = getLink().eContainer(); if(reorientDirection == ReorientRelationshipRequest.REORIENT_SOURCE) { StructuredClassifier newOwner = deduceContainer(reorientedEdgeView.getTarget(), newEndView); if (oldOwner != newOwner) { replaceOwner(getLink(), newOwner); } return reorientSource(); } if(reorientDirection == ReorientRelationshipRequest.REORIENT_TARGET) { StructuredClassifier newOwner = deduceContainer(reorientedEdgeView.getSource(), newEndView); if (oldOwner != newOwner) { replaceOwner(getLink(), newOwner); } return reorientTarget(); } throw new IllegalStateException(); } protected CommandResult reorientSource() throws ExecutionException { // Nothing to do here on the connector itself, the connector end remains // the same but related to new Port or PartWithPort. ConnectorEnd reorientedEnd = getLink().getEnds().get(0); ConnectorEnd oppositeEnd = getLink().getEnds().get(1); return reorientEnd(reorientedEnd, oppositeEnd, (ConnectableElement)getNewSource(), getNewPartWithPort(), getNewOppositePartWithPort()); } protected CommandResult reorientTarget() throws ExecutionException { // Nothing to do here on the connector itself, the connector end remains // the same but related to new Port or PartWithPort. ConnectorEnd reorientedEnd = getLink().getEnds().get(1); ConnectorEnd oppositeEnd = getLink().getEnds().get(0); return reorientEnd(reorientedEnd, oppositeEnd, (ConnectableElement)getNewTarget(), getNewPartWithPort(), getNewOppositePartWithPort()); } private CommandResult reorientEnd(ConnectorEnd end, ConnectorEnd oppositeEnd, ConnectableElement role, Property partWithPort, Property oppositePartWithPort) throws ExecutionException { end.setRole(role); end.setPartWithPort(partWithPort); oppositeEnd.setPartWithPort(oppositePartWithPort); return CommandResult.newOKCommandResult(); } /** * Get the link to re-orient. * * @return the edited {@link Connector} */ protected Connector getLink() { return (Connector)getElementToEdit(); } /** * Get the old {@link Connector} source. * * @return the previous {@link Connector} source. */ protected Element getOldSource() { return (Element)oldEnd; } /** * Get the new {@link Connector} source. * * @return the new {@link Connector} source. */ protected Element getNewSource() { return (Element)newEnd; } /** * Get the old {@link Connector} target. * * @return the previous {@link Connector} target. */ protected Element getOldTarget() { return (Element)oldEnd; } /** * Get the new {@link Connector} target. * * @return the new {@link Connector} target. */ protected Element getNewTarget() { return (Element)newEnd; } /** * Get the new {@link Connector} end graphical parent. * * @return the new {@link Connector} end graphical parent. */ protected Element getEndParent(View endView) { EObject parent = ViewUtil.getContainerView(endView).getElement(); return (parent instanceof Element) ? (Element)parent : null; } private void replaceOwner(Connector connector, StructuredClassifier newOwner) { // Change owner and Connector name (possibly already exists in new container) if (newOwner.getOwnedConnector(connector.getName()) != null) { String replacementName = NamedElementHelper.getDefaultNameWithIncrementFromBase("connector", newOwner.eContents()); // //$NON-NLS-0$ connector.setName(replacementName); } // Replace connector owner newOwner.getOwnedConnectors().add(connector); } /** * Get the new {@link Connector} end part with port. * * @return the new {@link Connector} end part with port. */ private Property getNewPartWithPort() { Property partWithPort = null; Element newEndParent = getEndParent(newEndView); if(newEnd instanceof Port) { // Only look for PartWithPort if the role is a Port. if((newEndParent != null) && (newEndParent instanceof Property) && !(newEndParent instanceof Port)) { // Only add PartWithPort for assembly (not for delegation) if(!EcoreUtil.isAncestor(ViewUtil.getContainerView(newEndView), oppositeEndView)) { partWithPort = (Property)newEndParent; } } } return partWithPort; } /** * Get the new {@link Connector} opposite end part with port. * * @return the new {@link Connector} opposite end part with port. */ private Property getNewOppositePartWithPort() { Property partWithPort = null; Element oppositeEndParent = getEndParent(oppositeEndView); if(oppositeEndView.getElement() instanceof Port) { // Only look for PartWithPort if the role is a Port. if((oppositeEndParent != null) && (oppositeEndParent instanceof Property) && !(oppositeEndParent instanceof Port)) { // Only add PartWithPort for assembly (not for delegation) if(!EcoreUtil.isAncestor(ViewUtil.getContainerView(oppositeEndView), newEndView)) { partWithPort = (Property)oppositeEndParent; } } } return partWithPort; } private StructuredClassifier deduceContainer(View source, View target) { return new ConnectorUtils().deduceContainer(source, target); } }