/*****************************************************************************
* Copyright (c) 2009 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
* Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr
*****************************************************************************/
package org.eclipse.papyrus.uml.diagram.composite.custom.helper;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.PrecisionRectangle;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.EditPartViewer;
import org.eclipse.gmf.runtime.common.core.command.CompositeCommand;
import org.eclipse.gmf.runtime.diagram.core.preferences.PreferencesHint;
import org.eclipse.gmf.runtime.diagram.core.util.ViewUtil;
import org.eclipse.gmf.runtime.diagram.ui.commands.CreateCommand;
import org.eclipse.gmf.runtime.diagram.ui.commands.SetBoundsCommand;
import org.eclipse.gmf.runtime.diagram.ui.editparts.CompartmentEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.GraphicalEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.ShapeNodeEditPart;
import org.eclipse.gmf.runtime.diagram.ui.requests.CreateConnectionViewRequest;
import org.eclipse.gmf.runtime.diagram.ui.requests.CreateViewRequest.ViewDescriptor;
import org.eclipse.gmf.runtime.emf.core.util.EObjectAdapter;
import org.eclipse.gmf.runtime.emf.type.core.IHintedType;
import org.eclipse.gmf.runtime.notation.Node;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.papyrus.uml.diagram.common.commands.CommonDeferredCreateConnectionViewCommand;
import org.eclipse.papyrus.uml.diagram.common.commands.SemanticAdapter;
import org.eclipse.papyrus.uml.diagram.common.helper.ElementHelper;
import org.eclipse.papyrus.uml.diagram.common.layout.LayoutUtils;
import org.eclipse.papyrus.uml.diagram.common.util.DiagramEditPartsUtil;
import org.eclipse.papyrus.uml.diagram.composite.providers.UMLElementTypes;
import org.eclipse.uml2.uml.ConnectableElement;
import org.eclipse.uml2.uml.Connector;
import org.eclipse.uml2.uml.Property;
/**
* Helper class containing the specific behavior for drag and drop of Connector
*/
public class ConnectorHelper extends ElementHelper {
/**
* Constructor
*
* @param editDomain
* the editing domain
*/
public ConnectorHelper(TransactionalEditingDomain editDomain) {
super();
this.editDomain = editDomain;
}
/**
* This method returns the drop command to use for Connector links. Mainly based on
*
* @param connector
* the connector to drop
* @param linkVisualID
* the visual identifier of the EditPart of the dropped Connector
* @param viewer
* @param host
* the EditPart of the element where the Connector is drop
* @param diagramPreferencesHint
* @param location
* the location where the Connector is dropped
* @param containerView
* @return the drop command for Connector
*/
public CompositeCommand dropConnector(Connector connector, int linkVisualID, EditPartViewer viewer, EditPart host, PreferencesHint diagramPreferencesHint, Point location, View containerView) {
CompositeCommand cc = new CompositeCommand("drop Connector");
ConnectableElement sourceRole = connector.getEnds().get(0).getRole();
ConnectableElement targetRole = connector.getEnds().get(1).getRole();
Property sourcePartWithPort = connector.getEnds().get(0).getPartWithPort();
Property targetPartWithPort = connector.getEnds().get(1).getPartWithPort();
if(sourceRole == null || targetRole == null) {//if an end is deleted, and the connector is still in the model (see bug 293168)
return cc;
}
// look for editpart
GraphicalEditPart sourceEditPart = resolveRoleEditPart(sourceRole, sourcePartWithPort, viewer);
GraphicalEditPart targetEditPart = resolveRoleEditPart(targetRole, targetPartWithPort, viewer);
// descriptor of the link
CreateConnectionViewRequest.ConnectionViewDescriptor linkdescriptor = new CreateConnectionViewRequest.ConnectionViewDescriptor(UMLElementTypes.getElementType(linkVisualID), ((IHintedType)UMLElementTypes.getElementType(linkVisualID)).getSemanticHint(), diagramPreferencesHint);
IAdaptable sourceAdapter = null;
IAdaptable targetAdapter = null;
//the parents of the ports, we use them when the PortEditPart are not on the diagram
EditPart sourceParent = null;
EditPart targetParent = null;
/*
* when the ports are not represented on the diagram,
* we look for their parents.
*/
DiagramEditPart diagram = DiagramEditPartsUtil.getDiagramEditPart(host);
if(sourceEditPart == null || targetEditPart == null) {
List<IGraphicalEditPart> AllEP = DiagramEditPartsUtil.getAllEditParts(diagram);
EObject srcParent = sourceRole.eContainer();
EObject tgtParent = targetRole.eContainer();
for(IGraphicalEditPart iGraphicalEditPart : AllEP) {
EObject object = ViewUtil.resolveSemanticElement((View)(iGraphicalEditPart).getModel());//method getHostObject
if(object == srcParent && !(iGraphicalEditPart instanceof CompartmentEditPart)) {
sourceParent = iGraphicalEditPart;
}
if(object == tgtParent && !(iGraphicalEditPart instanceof CompartmentEditPart)) {
targetParent = iGraphicalEditPart;
}
if(targetParent != null && sourceParent != null) {
break;
}
}
/*
* the parent of the port are not represented on the diagram
* we do nothing
*/
if(targetParent == null || sourceParent == null) {
return cc;
}
}
//set the location to absolute
Point absolutePosition = location.getCopy();
PrecisionRectangle hostBounds = LayoutUtils.getAbsolutePosition(host);
if(!hostBounds.equals(LayoutUtils.getAbsolutePosition(diagram))) {
absolutePosition = absolutePosition.translate(hostBounds.getLocation());//OK, the location is now in absolute!
}
if(sourceEditPart == null) {
//translate the point to relative (with the source editpart)
Point portLocation = absolutePosition.getCopy();
PrecisionRectangle parentBounds = LayoutUtils.getAbsolutePosition(sourceParent);
if(!sourceParent.equals(LayoutUtils.getAbsolutePosition(diagram))) {
portLocation = portLocation.translate(parentBounds.getLocation().getNegated());
}
// creation of the node
ViewDescriptor descriptor = new ViewDescriptor(new EObjectAdapter(sourceRole), Node.class, null, ViewUtil.APPEND, false, ((IGraphicalEditPart)host).getDiagramPreferencesHint());
// get the command and execute it.
CreateCommand nodeCreationCommand = new CreateCommand(((IGraphicalEditPart)host).getEditingDomain(), descriptor, ((View)sourceParent.getModel()));
cc.compose(nodeCreationCommand);
SetBoundsCommand setBoundsCommand = new SetBoundsCommand(getEditingDomain(), "move", (IAdaptable)nodeCreationCommand.getCommandResult().getReturnValue(), portLocation);
cc.compose(setBoundsCommand);
sourceAdapter = (IAdaptable)nodeCreationCommand.getCommandResult().getReturnValue();
} else {
sourceAdapter = new SemanticAdapter(null, sourceEditPart.getModel());
}
if(targetEditPart == null) {
//translate the location in relative (with the target editpart)
Point portLocation = absolutePosition.getCopy();
PrecisionRectangle parentBounds = LayoutUtils.getAbsolutePosition(targetParent);
if(!targetParent.equals(LayoutUtils.getAbsolutePosition(diagram))) {
portLocation = portLocation.translate(parentBounds.getLocation().getNegated());
}
// creation of the node
ViewDescriptor descriptor = new ViewDescriptor(new EObjectAdapter(targetRole), Node.class, null, ViewUtil.APPEND, false, ((IGraphicalEditPart)host).getDiagramPreferencesHint());
// get the command and execute it.
CreateCommand nodeCreationCommand = new CreateCommand(((IGraphicalEditPart)host).getEditingDomain(), descriptor, ((View)targetParent.getModel()));
cc.compose(nodeCreationCommand);
SetBoundsCommand setBoundsCommand = new SetBoundsCommand(getEditingDomain(), "move", (IAdaptable)nodeCreationCommand.getCommandResult().getReturnValue(), portLocation);
cc.compose(setBoundsCommand);
targetAdapter = (IAdaptable)nodeCreationCommand.getCommandResult().getReturnValue();
} else {
targetAdapter = new SemanticAdapter(null, targetEditPart.getModel());
}
CommonDeferredCreateConnectionViewCommand aLinkCommand = new CommonDeferredCreateConnectionViewCommand(getEditingDomain(), ((IHintedType)UMLElementTypes.getElementType(linkVisualID)).getSemanticHint(), sourceAdapter, targetAdapter, viewer, diagramPreferencesHint, linkdescriptor, null);
aLinkCommand.setElement(connector);
cc.compose(aLinkCommand);
return cc;
}
/**
* This method resolve the EditPart of the GraphicalElement attached to a ConnectorEnd.
*
* @param role
* the role of the considered ConnectorEnd
* @param partWithPort
* the partWithPort feature of the considered ConnectorEnd
* @param viewer
* @return the searched EditPart or null
*/
private ShapeNodeEditPart resolveRoleEditPart(ConnectableElement role, Property partWithPort, EditPartViewer viewer) {
Collection<?> editPartSet = viewer.getEditPartRegistry().values();
Iterator<?> editPartIterator = editPartSet.iterator();
EditPart foundEditPart = null;
while(editPartIterator.hasNext() && foundEditPart == null) {
EditPart currentEditPart = (EditPart)editPartIterator.next();
if((currentEditPart instanceof ShapeNodeEditPart) && (role.equals(((ShapeNodeEditPart)currentEditPart).resolveSemanticElement()))) {
if(partWithPort == null) {
foundEditPart = currentEditPart;
} else { // (partWithPort != null
ShapeNodeEditPart graphicalParent = (ShapeNodeEditPart)currentEditPart.getParent();
if(partWithPort.equals(graphicalParent.resolveSemanticElement())) {
foundEditPart = currentEditPart;
}
}
}
}
return (ShapeNodeEditPart)foundEditPart;
}
}