/*******************************************************************************
* Copyright (c) 2012 University of Mannheim: Chair for Software Engineering
* and others 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:
* Michael Golubev - initial API and implementation and initial documentation
* Ralph Gerbig - extension
*******************************************************************************/
package de.uni_mannheim.informatik.swt.models.plm.diagram.custom.implicitconnection.policy;
import java.util.LinkedList;
import java.util.List;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.draw2d.ConnectionAnchor;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.XYLayout;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.PointList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.gef.Request;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.requests.CreateConnectionRequest;
import org.eclipse.gef.requests.CreateRequest;
import org.eclipse.gmf.runtime.common.core.command.CommandResult;
import org.eclipse.gmf.runtime.common.core.command.ICommand;
import org.eclipse.gmf.runtime.diagram.core.commands.SetConnectionAnchorsCommand;
import org.eclipse.gmf.runtime.diagram.core.commands.SetConnectionEndsCommand;
import org.eclipse.gmf.runtime.diagram.core.edithelpers.CreateElementRequestAdapter;
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.CreateOrSelectElementCommand;
import org.eclipse.gmf.runtime.diagram.ui.commands.ICommandProxy;
import org.eclipse.gmf.runtime.diagram.ui.commands.SemanticCreateCommand;
import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.INodeEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editpolicies.GraphicalNodeEditPolicy;
import org.eclipse.gmf.runtime.diagram.ui.l10n.DiagramUIMessages;
import org.eclipse.gmf.runtime.diagram.ui.requests.CreateConnectionViewAndElementRequest;
import org.eclipse.gmf.runtime.diagram.ui.requests.CreateConnectionViewRequest;
import org.eclipse.gmf.runtime.diagram.ui.requests.CreateUnspecifiedTypeConnectionRequest;
import org.eclipse.gmf.runtime.diagram.ui.requests.EditCommandRequestWrapper;
import org.eclipse.gmf.runtime.emf.core.util.EObjectAdapter;
import org.eclipse.gmf.runtime.emf.type.core.IElementType;
import org.eclipse.gmf.runtime.emf.type.core.MetamodelType;
import org.eclipse.gmf.runtime.emf.type.core.requests.CreateRelationshipRequest;
import org.eclipse.gmf.runtime.notation.Diagram;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.swt.widgets.Display;
import de.uni_mannheim.informatik.swt.mlm.workbench.ExtensionPointService;
import de.uni_mannheim.informatik.swt.models.plm.PLM.Clabject;
import de.uni_mannheim.informatik.swt.models.plm.PLM.Connection;
import de.uni_mannheim.informatik.swt.models.plm.PLM.Entity;
import de.uni_mannheim.informatik.swt.models.plm.PLM.Participation;
/**
* Inherited GraphicalNodeEditPolicy that does the following: <br />
*
* <ul>
* <li>Enable advanced link creation (two participations + connection with one line)</li>
* <li>Modifies the content of the displayed popup menu when drawing a connection</li>
*</ul>
*
*/
public class ImplicitConnectionGraphicalNodeEditPolicy extends GraphicalNodeEditPolicy {
public static final String DISPLAY_NAME = "DisplayName";
//The linguistic meta-model type e.g. Participation
public static final String ELEMENT_TYPE = "ElementType";
//The ontologic meta-model type
public static final String DSL_TYPE = "DSL_TYPE";
protected class PromptAndCreateConnectionCommand
extends CreateOrSelectElementCommand {
/**
* Cache the request because it needs to be passed to
* {@link #getCommandForMenuSelection(Object, CreateConnectionRequest)}.
*/
private CreateConnectionRequest request;
/**
* Creates a new instance.
*
* @param content
* The list of items making up the content of the popup menu.
* @param request
* The relevant create connection request.
*/
public PromptAndCreateConnectionCommand(List content,
CreateConnectionRequest request) {
super(CREATE_CONNECTION_COMMAND_LABEL, Display.getCurrent()
.getActiveShell(), content);
this.request = request;
}
/**
* The command to create the connection that may need to be
* undone/redone.
*/
private Command createCommand;
/**
* Pops up the dialog with the content provided, gets the command to be
* executed based on the user selection, and then executes the command.
*/
@Override
protected CommandResult doExecuteWithResult(
IProgressMonitor progressMonitor, IAdaptable info)
throws ExecutionException {
CommandResult cmdResult = super.doExecuteWithResult(progressMonitor, info);
if (!cmdResult.getStatus().isOK()) {
return cmdResult;
}
Object connectionType = (cmdResult.getReturnValue() instanceof IElementType) ? cmdResult.getReturnValue() : ((Request)cmdResult.getReturnValue()).getExtendedData().get(ELEMENT_TYPE);
if (cmdResult.getReturnValue() instanceof Request)
getRequest().getExtendedData().put(DSL_TYPE, ((Request)cmdResult.getReturnValue()).getExtendedData().get(DSL_TYPE));
Command cmd = getConnectionCompleteCommand(connectionType, getRequest());
Assert.isTrue(cmd != null && cmd.canExecute());
cmd.execute();
createCommand = cmd;
if (connectionType instanceof IElementType) {
CreateRequest createRequest = ((CreateUnspecifiedTypeConnectionRequest) request)
.getRequestForType((IElementType) connectionType);
Object newObject = createRequest.getNewObject();
return CommandResult.newOKCommandResult(newObject);
}
return CommandResult.newOKCommandResult();
}
@Override
protected CommandResult doUndoWithResult(IProgressMonitor progressMonitor, IAdaptable info) throws ExecutionException {
if (createCommand != null) {
createCommand.undo();
}
return super.doUndoWithResult(progressMonitor, info);
}
@Override
protected CommandResult doRedoWithResult(IProgressMonitor progressMonitor, IAdaptable info) throws ExecutionException {
if (createCommand != null) {
createCommand.redo();
}
return super.doRedoWithResult(progressMonitor, info);
}
/**
* Gets the request.
*
* @return Returns the request.
*/
private CreateConnectionRequest getRequest() {
return request;
}
}
/**
* The label used for the command to create a new connection.
*/
private static final String CREATE_CONNECTION_COMMAND_LABEL = DiagramUIMessages.GraphicalNodeEditPolicy_createRelationshipCommand_label;
// /**
// * Diagrams that install modified edit policy for
// * {@link org.eclipse.gef.EditPolicy#GRAPHICAL_NODE_ROLE} also require to
// * install it into all default nodes, normally created outside the diagram
// * plugin.
// *
// * @see #315953
// */
// public static class ITMNoteEditPart extends NoteEditPart {
//
// public ITMNoteEditPart(View view) {
// super(view);
// }
//
// protected void createDefaultEditPolicies() {
// super.createDefaultEditPolicies();
//
// removeEditPolicy(org.eclipse.gef.EditPolicy.GRAPHICAL_NODE_ROLE);
// installEditPolicy(org.eclipse.gef.EditPolicy.GRAPHICAL_NODE_ROLE,
// new ImplicitConnectionGraphicalNodeEditPolicy());
//
// }
// }
public ImplicitConnectionGraphicalNodeEditPolicy() {
super();
}
@Override
protected Command getConnectionCreateCommand(CreateConnectionRequest request) {
if (!(request instanceof CreateConnectionViewRequest)) {
return null;
}
CreateConnectionViewRequest req = (CreateConnectionViewRequest) request;
TransactionalEditingDomain editingDomain = getHostImpl().getEditingDomain();
ImplicitConnectionCreateLinkCommand result = new ImplicitConnectionCreateLinkCommand(editingDomain,
getHostImpl().getDiagramPreferencesHint());
result.setSourceParameters(computeParameters(request));
result.registerInRequest(request);
Diagram diagramView = getView().getDiagram();
CreateCommand createCommand = new CreateCommand(editingDomain, req
.getConnectionViewDescriptor(), diagramView);
result.setEdgeCreation(createCommand);
IAdaptable edgeAdaptor = (IAdaptable) createCommand.getCommandResult()
.getReturnValue();
result.setEdgeAdapter(edgeAdaptor);
SetConnectionEndsCommand sceCommand = result
.getSetConnectionEndsCommand();
sceCommand.setNewSourceAdaptor(new EObjectAdapter(getView()));
ConnectionAnchor sourceAnchor = getConnectableEditPart()
.getSourceConnectionAnchor(request);
SetConnectionAnchorsCommand scaCommand = result
.getSetConnectionAnchorsCommand();
scaCommand.setNewSourceTerminal(getConnectableEditPart()
.mapConnectionAnchorToTerminal(sourceAnchor));
Command c = new ICommandProxy(result);
request.setStartCommand(c);
return c;
}
@Override
protected INodeEditPart getConnectableEditPart() {
return getHost() instanceof INodeEditPart ? (INodeEditPart) getHost()
: null;
}
@Override
@SuppressWarnings("restriction")
protected Command getConnectionCompleteCommand(
CreateConnectionRequest request) {
if (request.getStartCommand() != null &&
!(((ICommandProxy)request.getStartCommand()).getICommand() instanceof ImplicitConnectionCreateLinkCommand))
return super.getConnectionCompleteCommand(request);
ImplicitConnectionCreateLinkCommand cc = unwrapStartCommand(request);
if (cc == null) {
return null;
}
// reset the target edit-part for the request
INodeEditPart targetEP = getConnectionCompleteEditPart(request);
if (targetEP == null) {
return null;
}
ConnectionAnchor targetAnchor = targetEP
.getTargetConnectionAnchor(request);
SetConnectionEndsCommand sceCommand = cc.getSetConnectionEndsCommand();
sceCommand.setNewTargetAdaptor(new EObjectAdapter(
((IGraphicalEditPart) targetEP).getNotationView()));
SetConnectionAnchorsCommand scaCommand = cc
.getSetConnectionAnchorsCommand();
scaCommand.setNewTargetTerminal(targetEP
.mapConnectionAnchorToTerminal(targetAnchor));
INodeEditPart sourceEditPart = (INodeEditPart) request
.getSourceEditPart();
//FIX: This works with the connection fixed anchors
ConnectionAnchor sourceAnchor = sourceEditPart.getSourceConnectionAnchor(request);
//.mapTerminalToConnectionAnchor(scaCommand
// .getNewSourceTerminal());
PointList pointList = new PointList();
if (request.getLocation() == null) {
pointList.addPoint(sourceAnchor.getLocation(targetAnchor
.getReferencePoint()));
pointList.addPoint(targetAnchor.getLocation(sourceAnchor
.getReferencePoint()));
} else {
pointList.addPoint(sourceAnchor.getLocation(request.getLocation()));
pointList.addPoint(targetAnchor.getLocation(request.getLocation()));
}
cc.getSetConnectionBendpointsCommand().setNewPointList(pointList,
sourceAnchor.getReferencePoint(),
targetAnchor.getReferencePoint());
return request.getStartCommand();
}
@Override
protected Command getConnectionAndRelationshipCompleteCommand(
CreateConnectionViewAndElementRequest request) {
if (request.getStartCommand() != null &&
!(((ICommandProxy)request.getStartCommand()).getICommand() instanceof ImplicitConnectionCreateLinkCommand))
return super.getConnectionAndRelationshipCompleteCommand(request);
// get the element descriptor
CreateElementRequestAdapter requestAdapter = request
.getConnectionViewAndElementDescriptor()
.getCreateElementRequestAdapter();
// get the semantic request
CreateRelationshipRequest createElementRequest = (CreateRelationshipRequest) requestAdapter
.getAdapter(CreateRelationshipRequest.class);
createElementRequest.setPrompt(!request.isUISupressed());
// complete the semantic request by filling in the source and
// destination
INodeEditPart targetEP = getConnectionCompleteEditPart(request);
View sourceView = (View) request.getSourceEditPart().getModel();
View targetView = (View) targetEP.getModel();
// resolve the source
EObject source = ViewUtil.resolveSemanticElement(sourceView);
if (source == null) {
source = sourceView;
}
createElementRequest.setSource(source);
// resolve the target
EObject target = ViewUtil.resolveSemanticElement(targetView);
if (target == null) {
target = targetView;
}
createElementRequest.setTarget(target);
ImplicitConnectionCreateParametersImpl computeParameters = computeParameters(request);
ImplicitConnectionCreateLinkCommand unwrapStartCommand = unwrapStartCommand(request);
if (null != unwrapStartCommand && computeParameters != null) {
unwrapStartCommand.setTargetParameters(computeParameters);
}
Command createElementCommand = targetEP.getCommand(//
new EditCommandRequestWrapper(//
(CreateRelationshipRequest) requestAdapter
.getAdapter(CreateRelationshipRequest.class), //
request.getExtendedData()));
// create the create semantic element wrapper command
if (null == createElementCommand) {
return null;
}
SemanticCreateCommand semanticCommand = new SemanticCreateCommand(
requestAdapter, createElementCommand);
// get the view command
ICommandProxy result = (ICommandProxy) getConnectionCompleteCommand(request);
if (null == result) {
return null;
}
ImplicitConnectionCreateLinkCommand viewCommandImpl = (ImplicitConnectionCreateLinkCommand) result
.getICommand();
// set semantic creation to be executed before edge creation and setup
viewCommandImpl.setSemanticCreation(semanticCommand);
return result;
}
@Override
protected Command getConnectionCompleteCommand(Object connectionType,
CreateConnectionRequest request) {
if (connectionType instanceof IElementType) {
if (request instanceof CreateUnspecifiedTypeConnectionRequest) {
CreateRequest createRequest = ((CreateUnspecifiedTypeConnectionRequest) request)
.getRequestForType((IElementType) connectionType);
//This modification is needed to put the DSL type into the request which is
//used for connection and participation creation
if (request.getExtendedData().get(DSL_TYPE) != null)
createRequest.getExtendedData().put(DSL_TYPE, request.getExtendedData().get(DSL_TYPE));
if (createRequest != null) {
return getHost().getCommand(createRequest);
}
}
}
return null;
}
private IGraphicalEditPart getHostImpl() {
return (IGraphicalEditPart) getHost();
}
protected ImplicitConnectionCreateLinkCommand unwrapStartCommand(
CreateConnectionRequest request) {
ICommandProxy proxy = (ICommandProxy) request.getStartCommand();
if (proxy == null) {
return null;
}
return (ImplicitConnectionCreateLinkCommand) proxy.getICommand();
}
protected ImplicitConnectionCreateParametersImpl computeParameters(
CreateConnectionRequest request) {
ImplicitConnectionCreateParametersImpl parameters = new ImplicitConnectionCreateParametersImpl();
parameters.setParentView(getHostImpl().getNotationView());
if (request.getLocation() != null) {
IFigure hostContentPane = getHostImpl().getContentPane();
Point origin;
if (hostContentPane.getLayoutManager() instanceof XYLayout) {
origin = ((XYLayout) hostContentPane.getLayoutManager())
.getOrigin(hostContentPane);
} else {
origin = hostContentPane.getClientArea().getLocation();
}
Point relativeLocation = new Point(request.getLocation());
hostContentPane.translateToRelative(relativeLocation);
relativeLocation.translate(origin.getNegated());
parameters.setRelativeLocation(relativeLocation);
}
return parameters;
}
/**
*
* <p>Takes care that all possible DSL connections are listed when creating
* a connection at instance level.</p>
*
* <p><b>Must be refactored to get rid of reflective API. May this must be abstract and
* implemented in plugin.</b></p>
*/
@Override
protected List getConnectionMenuContent(CreateConnectionRequest request) {
//This is specialized for Participations
if (request instanceof CreateUnspecifiedTypeConnectionRequest)
{
List result = super.getConnectionMenuContent(request);
try {
EObject source = ((IGraphicalEditPart)request.getSourceEditPart()).resolveSemanticElement();
EObject target = ((IGraphicalEditPart)request.getTargetEditPart()).resolveSemanticElement();
// Only applyed if a Clabject is connected to an Clabject as only these
// can have types for instantiation.
if (!(source instanceof Clabject) ||
! (target instanceof Clabject))
return super.getConnectionMenuContent(request);
List<Connection> connections = new LinkedList<Connection>();
List<Participation> participations = new LinkedList<Participation>();
if (source instanceof Entity && target instanceof Entity)
connections = ExtensionPointService.Instance().getActiveDSLService().getInstantiableConnectionsBetween((Entity)source, (Entity)target);
else if (source instanceof Connection && target instanceof Entity){
participations = ExtensionPointService.Instance().getActiveDSLService().getInstantiableParticipationsBetween((Connection)source, (Entity)target);
connections = ExtensionPointService.Instance().getActiveDSLService().getInstantiableConnectionsBetween((Connection)source, (Entity)target);
}
// else
// return super.getConnectionMenuContent(request);
//Go for the connections
if (connections.size() > 0){
IElementType elementType = null;
for (IElementType type: (List<IElementType>)((CreateUnspecifiedTypeConnectionRequest)request).getElementTypes())
if (type.toString().contains("Participation"))
elementType = type;
for (Connection connection : connections){
//Here we do only create the captions
Request clone = cloneRequest((CreateUnspecifiedTypeConnectionRequest)request);
clone.getExtendedData().put(DISPLAY_NAME, connection.getHumanReadableName());
clone.getExtendedData().put(DSL_TYPE, connection);
clone.getExtendedData().put(ELEMENT_TYPE, elementType);
result.add(clone);
}
}
//Go for the participations
if (participations.size() > 0){
IElementType elementType = null;
for (IElementType type: (List<IElementType>)((CreateUnspecifiedTypeConnectionRequest)request).getElementTypes())
if (type.toString().contains("Participation"))
elementType = type;
for (Participation r : participations){
//Here we do only create the captions
Request clone = cloneRequest((CreateUnspecifiedTypeConnectionRequest)request);
clone.getExtendedData().put(DISPLAY_NAME, r.getHumanReadableParticipationName());
clone.getExtendedData().put(DSL_TYPE, r);
clone.getExtendedData().put(ELEMENT_TYPE, elementType);
result.add(clone);
}
}
//We should also over to create a connection between two connections
if (source instanceof Connection && target instanceof Connection){
IElementType elementType = null;
for (IElementType type: (List<IElementType>)((CreateUnspecifiedTypeConnectionRequest)request).getElementTypes())
if (type.toString().contains("Participation"))
elementType = type;
Request clone = cloneRequest((CreateUnspecifiedTypeConnectionRequest)request);
clone.getExtendedData().put(DISPLAY_NAME, "Create Connection");
clone.getExtendedData().put(ELEMENT_TYPE, elementType);
result.add(clone);
}
return result;
}
catch (CoreException e) {
e.printStackTrace();
}
}
return super.getConnectionMenuContent(request);
}
private CreateUnspecifiedTypeConnectionRequest cloneRequest(CreateUnspecifiedTypeConnectionRequest request){
CreateUnspecifiedTypeConnectionRequest result = new CreateUnspecifiedTypeConnectionRequest(request.getElementTypes(), request.useModelingAssistantService(), getHostImpl().getDiagramPreferencesHint());
result.setTargetEditPart(request.getTargetEditPart());
result.setSourceEditPart(request.getSourceEditPart());
result.setDirectionReversed(request.isDirectionReversed());
return result;
}
/**
* This needs to be overridden to provide the right text for the content
*/
@Override
protected ICommand getPromptAndCreateConnectionCommand(final List content,
final CreateConnectionRequest request) {
return new PromptAndCreateConnectionCommand(content, request){
@Override
protected CommandResult doExecuteWithResult(
IProgressMonitor progressMonitor, IAdaptable info)
throws ExecutionException {
return super.doExecuteWithResult(progressMonitor, info);
}
@Override
protected ILabelProvider getLabelProvider() {
return new LabelProvider(){
@Override
public String getText(Object object) {
if (object instanceof Request && ((Request) object).getExtendedData().get(DISPLAY_NAME) != null)
return ((Request) object).getExtendedData().get(DISPLAY_NAME).toString();
else if (object instanceof MetamodelType && ((MetamodelType)object).getDisplayName().equals("Participation")
&& content.size() > 1
&& ((IGraphicalEditPart)request.getSourceEditPart()).resolveSemanticElement() instanceof Entity
&& ((IGraphicalEditPart)request.getTargetEditPart()).resolveSemanticElement() instanceof Entity
)
return "Create new Connection";
return super.getText(object);
}
};
}
};
}
}