blob: 25334f91fcf0f5cb772106785b54cf95bc18790f [file] [log] [blame]
/******************************************************************************
* Copyright (c) 2002, 2009 IBM Corporation 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:
* IBM Corporation - initial API and implementation
****************************************************************************/
package org.eclipse.gmf.runtime.diagram.ui.editpolicies;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.draw2d.Connection;
import org.eclipse.draw2d.ConnectionAnchor;
import org.eclipse.draw2d.ConnectionLayer;
import org.eclipse.draw2d.ConnectionRouter;
import org.eclipse.draw2d.Graphics;
import org.eclipse.draw2d.PolylineConnection;
import org.eclipse.draw2d.geometry.PointList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.LayerConstants;
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.gef.requests.ReconnectRequest;
import org.eclipse.gmf.runtime.common.core.command.CommandResult;
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.util.StringStatics;
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.commands.SetPropertyCommand;
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.CommandProxy;
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.editparts.ITreeBranchEditPart;
import org.eclipse.gmf.runtime.diagram.ui.internal.commands.SetConnectionBendpointsCommand;
import org.eclipse.gmf.runtime.diagram.ui.internal.properties.Properties;
import org.eclipse.gmf.runtime.diagram.ui.l10n.DiagramUIMessages;
import org.eclipse.gmf.runtime.diagram.ui.preferences.IPreferenceConstants;
import org.eclipse.gmf.runtime.diagram.ui.requests.ChangePropertyValueRequest;
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.CreateViewRequestFactory;
import org.eclipse.gmf.runtime.diagram.ui.requests.EditCommandRequestWrapper;
import org.eclipse.gmf.runtime.diagram.ui.requests.RequestConstants;
import org.eclipse.gmf.runtime.draw2d.ui.internal.figures.ConnectionLayerEx;
import org.eclipse.gmf.runtime.emf.core.util.EObjectAdapter;
import org.eclipse.gmf.runtime.emf.core.util.PackageUtil;
import org.eclipse.gmf.runtime.emf.type.core.IElementType;
import org.eclipse.gmf.runtime.emf.type.core.requests.CreateRelationshipRequest;
import org.eclipse.gmf.runtime.emf.ui.services.modelingassistant.ModelingAssistantService;
import org.eclipse.gmf.runtime.notation.Diagram;
import org.eclipse.gmf.runtime.notation.NotationPackage;
import org.eclipse.gmf.runtime.notation.Routing;
import org.eclipse.gmf.runtime.notation.RoutingStyle;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.swt.widgets.Display;
/**
* the graphical node edit policy
* @see org.eclipse.gef.editpolicies.GraphicalNodeEditPolicy
*
* @author mmostafa, cmahoney
*/
public class GraphicalNodeEditPolicy
extends
org.eclipse.gef.editpolicies.GraphicalNodeEditPolicy {
/** describes the view to be created. */
private IAdaptable _viewAdapter;
/**
* The label used for the command to create a new connection.
*/
private static final String CREATE_CONNECTION_COMMAND_LABEL = DiagramUIMessages.GraphicalNodeEditPolicy_createRelationshipCommand_label;
/**
* Gets a command that pops up a menu which allows the user to select which
* type of connection to be created and then creates the connection. This
* command uses
* {@link #getCommandForMenuSelection(Object, CreateConnectionRequest)} on
* the connection chosen to get the creation command.
*
* @author cmahoney
*/
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.
*/
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();
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();
}
protected CommandResult doUndoWithResult(IProgressMonitor progressMonitor, IAdaptable info) throws ExecutionException {
if (createCommand != null) {
createCommand.undo();
}
return super.doUndoWithResult(progressMonitor, info);
}
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;
}
}
protected Connection createDummyConnection(Request req) {
PolylineConnection c = (PolylineConnection) super.createDummyConnection(req);
c.setLineStyle(Graphics.LINE_DASHDOT);
c.setForegroundColor(((GraphicalEditPart) getHost()).getFigure()
.getForegroundColor());
return c;
}
/*
* (non-Javadoc)
* @see org.eclipse.gef.editpolicies.GraphicalNodeEditPolicy#getDummyConnectionRouter(org.eclipse.gef.requests.CreateConnectionRequest)
*/
protected ConnectionRouter getDummyConnectionRouter(CreateConnectionRequest arg0) {
EditPart ep = getHost();
if (ep instanceof IGraphicalEditPart) {
IGraphicalEditPart gep = ((IGraphicalEditPart)ep);
Routing routingVal = Routing.MANUAL_LITERAL;
if (gep.getNotationView() != null) {
Diagram dgrm = gep.getNotationView().getDiagram();
EditPart epfromReg = (EditPart)gep.getViewer().getEditPartRegistry().get(dgrm);
if (epfromReg != null)
routingVal = (Routing)epfromReg.getAdapter(Routing.class);
}
else {
IPreferenceStore store = (IPreferenceStore) ((IGraphicalEditPart)ep).getDiagramPreferencesHint().getPreferenceStore();
routingVal = Routing.get(store.getInt(IPreferenceConstants.PREF_LINE_STYLE));
}
ConnectionLayer cLayer = (ConnectionLayer) getLayer(LayerConstants.CONNECTION_LAYER);
if (cLayer instanceof ConnectionLayerEx) {
ConnectionLayerEx cLayerEx = (ConnectionLayerEx)cLayer;
if (routingVal == Routing.MANUAL_LITERAL) {
return cLayerEx.getObliqueRouter();
}
else if (routingVal == Routing.RECTILINEAR_LITERAL) {
return cLayerEx.getRectilinearRouter();
}
else if (routingVal == Routing.TREE_LITERAL) {
return cLayerEx.getTreeRouter();
}
}
}
return super.getDummyConnectionRouter(arg0);
}
protected ConnectionAnchor getSourceConnectionAnchor(
CreateConnectionRequest request) {
EditPart source = request.getSourceEditPart();
return source instanceof INodeEditPart ? ((INodeEditPart) source)
.getSourceConnectionAnchor(request) : null;
}
protected ConnectionAnchor getTargetConnectionAnchor(
CreateConnectionRequest request) {
EditPart target = request.getTargetEditPart();
return target instanceof INodeEditPart ? ((INodeEditPart) target)
.getTargetConnectionAnchor(request) : null;
}
/**
* get a connectable edit part
* @return INodeEditPart
*/
protected INodeEditPart getConnectableEditPart() {
return (INodeEditPart) getHost();
}
/**
* getConnectionCompleteEditPart
*
* This method is used when the connection is verified and made complete to
* retrieve the final connecting editpart to be used in the connection
* creation. This is by default the "host" edit part which is what is
* connected to by the user feedback. Subclassing edit-policies may wish to
* redirect the connection to a different edit-part depending on the
* gesture. i.e. the tree-view for generalizations will redirect the
* connection to the target of the host.
*
* @param request
* Request giving some information about the user gesture.
* @return INodeEditPart which will be the target connection.
*/
protected INodeEditPart getConnectionCompleteEditPart(Request request) {
if (getHost() instanceof INodeEditPart) {
return (INodeEditPart) getHost();
}
return null;
}
/**
* getConnectionTargetAnchor Method used during reconnection to retrieve
* the appropriate target anchor based on a request.
*
* @param request
* Request giving some information about the user gesture.
* @return ConnectionAnchor the connections target end will connect to.
*/
protected ConnectionAnchor getConnectionTargetAnchor(Request request) {
INodeEditPart node = getConnectableEditPart();
if (node != null)
return node.getTargetConnectionAnchor(request);
return null;
}
/**
* get this edit policy's edit part <code>View</code>
* @return View
*/
protected View getView() {
return (View)getHost().getModel();
}
/**
* getSemanticHint Retrieves the semanticHint from the request regarding
* the type of elemen being manipulated.
*
* @param request
* Request that is sent from the user gesture
* @return String that is the semantic type.
*/
protected String getSemanticHint(Request request) {
String hint = null;
if (request instanceof CreateConnectionViewAndElementRequest) {
CreateConnectionViewAndElementRequest ccvr = (CreateConnectionViewAndElementRequest) request;
// get the element descriptor
CreateElementRequestAdapter requestAdapter = ccvr
.getConnectionViewAndElementDescriptor()
.getCreateElementRequestAdapter();
// get the semantic request
CreateRelationshipRequest createElementRequest = (CreateRelationshipRequest) requestAdapter
.getAdapter(CreateRelationshipRequest.class);
hint = PackageUtil.getID(createElementRequest.getElementType().getEClass());
} else if (request instanceof ReconnectRequest) {
ReconnectRequest rr = (ReconnectRequest) request;
hint = ViewUtil.getSemanticElementClassId((View)rr.getConnectionEditPart().getModel());
} else if (request instanceof CreateConnectionViewRequest) {
CreateConnectionViewRequest ccvr = (CreateConnectionViewRequest) request;
hint = ccvr.getConnectionViewDescriptor().getSemanticHint();
}
return hint;
}
/**
* getRoutingAdjustment method to adjust routing if the reorient has moved
* the connection into a different routing environment. Specifically, if
* the connection has been reoriented out of a tree structure it will
* change routing to the default set in preference. Likewise, if the
* connection has connected to a tree structure then the routing will
* create a tree.
*
* @param connection
* IAdaptable that is placeholder for not yet created connection.
* Also adapts directly to a ConnectionEditPart in the case of a
* reorient.
* @param connectionHint
* String that is the semantic hint of the connection being
* manipulated
* @param currentRouterType
* Integer current representation of the routing style
* @param target
* EditPart that is being targeted by the request.
* @return Command to make any routing adjustments if necessary.
*/
protected Command getRoutingAdjustment(IAdaptable connection,
String connectionHint, Routing currentRouterType, EditPart target) {
Command cmd = null;
if (connectionHint == null ||
target == null || target.getModel() == null
|| ((View)target.getModel()).getElement() == null)
return null;
// check if router needs to change type due to reorient.
String targetHint = ViewUtil.getSemanticElementClassId((View) target.getModel());
Routing newRouterType = null;
if (target instanceof ITreeBranchEditPart
&& connectionHint.equals(targetHint)) {
newRouterType = Routing.TREE_LITERAL;
ChangePropertyValueRequest cpvr = new ChangePropertyValueRequest(
StringStatics.BLANK, Properties.ID_ROUTING, newRouterType);
Command cmdRouter = target.getCommand(cpvr);
if (cmdRouter != null)
cmd = cmd == null ? cmdRouter : cmd.chain(cmdRouter);
} else {
if (currentRouterType.equals(Routing.TREE_LITERAL)) {
IPreferenceStore store = (IPreferenceStore)
((IGraphicalEditPart) getHost())
.getDiagramPreferencesHint().getPreferenceStore();
newRouterType = Routing.get(store.getInt(IPreferenceConstants.PREF_LINE_STYLE));
}
}
if (newRouterType != null) {
// add commands for line routing. Convert the new connection and
// also the targeted connection.
ICommand spc = new SetPropertyCommand(
getEditingDomain(), connection,
Properties.ID_ROUTING, StringStatics.BLANK, newRouterType);
Command cmdRouter = new ICommandProxy(spc);
if (cmdRouter != null) {
cmd = cmd == null ? cmdRouter : cmd.chain(cmdRouter);
}
}
return cmd;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.gef.editpolicies.GraphicalNodeEditPolicy#getReconnectTargetCommand(org.eclipse.gef.requests.ReconnectRequest)
*/
protected Command getReconnectTargetCommand(ReconnectRequest request) {
INodeEditPart node = getConnectableEditPart();
if (node == null)
return null;
TransactionalEditingDomain editingDomain = getEditingDomain();
ConnectionAnchor targetAnchor = getConnectionTargetAnchor(request);
INodeEditPart targetEP = getConnectionCompleteEditPart(request);
if (targetEP == null) {
return null;
}
SetConnectionEndsCommand sceCommand = new SetConnectionEndsCommand(editingDomain, StringStatics.BLANK);
sceCommand.setEdgeAdaptor(new EObjectAdapter((EObject)request
.getConnectionEditPart().getModel()));
sceCommand.setNewTargetAdaptor(targetEP);
SetConnectionAnchorsCommand scaCommand = new SetConnectionAnchorsCommand(editingDomain, StringStatics.BLANK);
scaCommand.setEdgeAdaptor(new EObjectAdapter((EObject) request
.getConnectionEditPart().getModel()));
scaCommand.setNewTargetTerminal(targetEP
.mapConnectionAnchorToTerminal(targetAnchor));
CompositeCommand cc = new CompositeCommand(
DiagramUIMessages.Commands_SetConnectionEndsCommand_Target);
cc.compose(sceCommand);
cc.compose(scaCommand);
Command cmd = new ICommandProxy(cc);
EditPart cep = request.getConnectionEditPart();
RoutingStyle style = (RoutingStyle) ((View)cep.getModel()).getStyle(NotationPackage.eINSTANCE.getRoutingStyle());
Routing currentRouter = Routing.MANUAL_LITERAL;
if (style != null) {
currentRouter = style.getRouting();
}
Command cmdRouter = getRoutingAdjustment(request
.getConnectionEditPart(), getSemanticHint(request),
currentRouter, request.getTarget());
if (cmdRouter != null) {
cmd = cmd == null ? cmdRouter : cmd.chain(cmdRouter);
// reset the bendpoints
ConnectionAnchor sourceAnchor = node
.getSourceConnectionAnchor(request);
PointList pointList = new PointList();
pointList.addPoint(sourceAnchor.getLocation(targetAnchor
.getReferencePoint()));
pointList.addPoint(targetAnchor.getLocation(sourceAnchor
.getReferencePoint()));
SetConnectionBendpointsCommand sbbCommand = new SetConnectionBendpointsCommand(editingDomain);
sbbCommand.setEdgeAdapter(request.getConnectionEditPart());
sbbCommand.setNewPointList(pointList, sourceAnchor
.getReferencePoint(), targetAnchor.getReferencePoint());
Command cmdBP = new ICommandProxy(sbbCommand);
if (cmdBP != null) {
cmd = cmd == null ? cmdBP : cmd.chain(cmdBP);
}
}
return cmd;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.gef.editpolicies.GraphicalNodeEditPolicy#getReconnectSourceCommand(org.eclipse.gef.requests.ReconnectRequest)
*/
protected Command getReconnectSourceCommand(ReconnectRequest request) {
INodeEditPart node = getConnectableEditPart();
if (node == null)
return null;
TransactionalEditingDomain editingDomain = getEditingDomain();
ConnectionAnchor sourceAnchor = node.getSourceConnectionAnchor(request);
SetConnectionEndsCommand sceCommand = new SetConnectionEndsCommand(editingDomain, StringStatics.BLANK);
sceCommand.setEdgeAdaptor(new EObjectAdapter((View) request
.getConnectionEditPart().getModel()));
sceCommand.setNewSourceAdaptor(new EObjectAdapter((View)node
.getModel()));
SetConnectionAnchorsCommand scaCommand = new SetConnectionAnchorsCommand(editingDomain, StringStatics.BLANK);
scaCommand.setEdgeAdaptor(new EObjectAdapter((View) request
.getConnectionEditPart().getModel()));
scaCommand.setNewSourceTerminal(node.mapConnectionAnchorToTerminal(sourceAnchor));
CompositeCommand cc = new CompositeCommand(
DiagramUIMessages.Commands_SetConnectionEndsCommand_Source);
cc.compose(sceCommand);
cc.compose(scaCommand);
return new ICommandProxy(cc);
}
/**
* Returns a command that will create the connection.
*
* If you must override this method, you should call super.
*
* @see org.eclipse.gef.editpolicies.GraphicalNodeEditPolicy#getConnectionCompleteCommand(org.eclipse.gef.requests.CreateConnectionRequest)
*
*/
protected Command getConnectionCompleteCommand(
CreateConnectionRequest request) {
ICommandProxy proxy = (ICommandProxy) request
.getStartCommand();
if (proxy == null) {
return null;
}
// reset the target edit-part for the request
INodeEditPart targetEP = getConnectionCompleteEditPart(request);
if (targetEP == null) {
return null;
}
CompositeCommand cc = (CompositeCommand) proxy.getICommand();
ConnectionAnchor targetAnchor = targetEP
.getTargetConnectionAnchor(request);
Iterator commandItr = cc.iterator();
commandItr.next(); //0
SetConnectionEndsCommand sceCommand = (SetConnectionEndsCommand) commandItr.next(); //1
sceCommand.setNewTargetAdaptor(new EObjectAdapter(((IGraphicalEditPart) targetEP).getNotationView()));
SetConnectionAnchorsCommand scaCommand = (SetConnectionAnchorsCommand) commandItr.next(); //2
scaCommand.setNewTargetTerminal(targetEP
.mapConnectionAnchorToTerminal(targetAnchor));
setViewAdapter(sceCommand.getEdgeAdaptor());
INodeEditPart sourceEditPart = (INodeEditPart) request
.getSourceEditPart();
ConnectionAnchor sourceAnchor = sourceEditPart
.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()));
}
SetConnectionBendpointsCommand sbbCommand = (SetConnectionBendpointsCommand) commandItr.next(); //3
sbbCommand.setNewPointList(pointList, sourceAnchor.getReferencePoint(),
targetAnchor.getReferencePoint());
return request.getStartCommand();
}
/**
* Cache the view descriptor describing the connection to be create.
*
* @param viewAdapter
*/
protected final void setViewAdapter(IAdaptable viewAdapter) {
_viewAdapter = viewAdapter;
}
/**
* Return the view adapter describing the element to be created.
* @see #setViewAdapter(IAdaptable)
* @return adpater that can adapt <code>View.class</code>
*/
protected final IAdaptable getViewAdapter() {
return _viewAdapter;
}
protected Command getConnectionCreateCommand(CreateConnectionRequest request) {
if (!(request instanceof CreateConnectionViewRequest))
return null;
CreateConnectionViewRequest req = (CreateConnectionViewRequest) request;
CompositeCommand cc = new CompositeCommand(
DiagramUIMessages.Commands_CreateCommand_Connection_Label);
Diagram diagramView = ((View)getHost().getModel())
.getDiagram();
TransactionalEditingDomain editingDomain = getEditingDomain();
CreateCommand createCommand = new CreateCommand(editingDomain, req
.getConnectionViewDescriptor(), diagramView.getDiagram());
setViewAdapter((IAdaptable) createCommand.getCommandResult()
.getReturnValue());
SetConnectionEndsCommand sceCommand = new SetConnectionEndsCommand(editingDomain, StringStatics.BLANK);
sceCommand.setEdgeAdaptor(getViewAdapter());
sceCommand.setNewSourceAdaptor(new EObjectAdapter(getView()));
ConnectionAnchor sourceAnchor = getConnectableEditPart()
.getSourceConnectionAnchor(request);
SetConnectionAnchorsCommand scaCommand = new SetConnectionAnchorsCommand(editingDomain, StringStatics.BLANK);
scaCommand.setEdgeAdaptor(getViewAdapter());
scaCommand.setNewSourceTerminal(getConnectableEditPart()
.mapConnectionAnchorToTerminal(sourceAnchor));
SetConnectionBendpointsCommand sbbCommand = new SetConnectionBendpointsCommand(editingDomain);
sbbCommand.setEdgeAdapter(getViewAdapter());
cc.compose(createCommand);
cc.compose(sceCommand);
cc.compose(scaCommand);
cc.compose(sbbCommand);
Command c = new ICommandProxy(cc);
request.setStartCommand(c);
return c;
}
public Command getCommand(Request request) {
if (RequestConstants.REQ_CONNECTION_START.equals(request.getType())) {
if (request instanceof CreateConnectionViewAndElementRequest) {
return getConnectionAndRelationshipCreateCommand((CreateConnectionViewAndElementRequest) request);
} else if (request instanceof CreateUnspecifiedTypeConnectionRequest) {
return getUnspecifiedConnectionCreateCommand((CreateUnspecifiedTypeConnectionRequest) request);
}
} else if (RequestConstants.REQ_CONNECTION_END
.equals(request.getType())) {
if (request instanceof CreateConnectionViewAndElementRequest) {
return getConnectionAndRelationshipCompleteCommand((CreateConnectionViewAndElementRequest) request);
} else if (request instanceof CreateUnspecifiedTypeConnectionRequest) {
return getUnspecifiedConnectionCompleteCommand((CreateUnspecifiedTypeConnectionRequest) request);
}
}
return super.getCommand(request);
}
/**
* Gets the command to start the creation of a new connection and
* relationship. This will update the request appropriately.
*
* @param request
* @return Command
*/
protected Command getConnectionAndRelationshipCreateCommand(
CreateConnectionViewAndElementRequest request) {
// get the element descriptor
CreateElementRequestAdapter requestAdapter = request
.getConnectionViewAndElementDescriptor().getCreateElementRequestAdapter();
// get the semantic request
CreateRelationshipRequest createElementRequest = (CreateRelationshipRequest) requestAdapter
.getAdapter(CreateRelationshipRequest.class);
// complete the semantic request by filling in the source
View sourceView = (View)getHost().getModel();
createElementRequest.setSource(ViewUtil.resolveSemanticElement(sourceView));
// get the create element request based on the elementdescriptor's
// request
Command createElementCommand = getHost().getCommand(
new EditCommandRequestWrapper(
(CreateRelationshipRequest) requestAdapter
.getAdapter(CreateRelationshipRequest.class), request.getExtendedData()));
// if element cannot be created, ignore
if (createElementCommand == null || !createElementCommand.canExecute()){
// Even if the command is not executable, status information may be set.
return createElementCommand;
}
return getConnectionCreateCommand(request);
}
/**
* Gets the command to start the creation of a new connection and
* relationship (if applicable) for a unspecified type request. This will
* update all the individual requests appropriately.
*
* @param request
* the unspecified type request
* @return the command
*/
private Command getUnspecifiedConnectionCreateCommand(
final CreateUnspecifiedTypeConnectionRequest request) {
if (request.isDirectionReversed()) {
return new Command() {
/**
* All we know is the target and the possible relationship
* types. At this point, there is no way to validate the
* commands for this scenario.
*/
public boolean canExecute() {
return true;
}
};
} else {
// Get the start command for each individual request, this will
// update each request as required.
final List commands = new ArrayList();
for (Iterator iter = request.getAllRequests().iterator(); iter
.hasNext();) {
Request individualRequest = (Request) iter.next();
Command cmd = null;
if (individualRequest instanceof CreateConnectionViewAndElementRequest) {
cmd = getConnectionAndRelationshipCreateCommand((CreateConnectionViewAndElementRequest) individualRequest);
} else if (individualRequest instanceof CreateConnectionViewRequest) {
cmd = getConnectionCreateCommand((CreateConnectionViewRequest) individualRequest);
}
if (cmd != null && cmd.canExecute()) {
commands.add(cmd);
}
}
if (commands.isEmpty()) {
// GEF's AbstractConnectionCreationTool expects a null command
// when the gesture should be disabled.
return null;
}
// return an executable command that does nothing
return new Command() {/* do nothing*/};
}
}
/**
* Gets the command to complete the creation of a new connection and
* relationship.
*
* @param request
* @return Command
*/
protected Command getConnectionAndRelationshipCompleteCommand(
CreateConnectionViewAndElementRequest 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);
// get the create element request based on the elementdescriptor's
// request
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
Command viewCommand = getConnectionCompleteCommand(request);
if (null == viewCommand)
return null;
// form the compound command and return
CompositeCommand cc = new CompositeCommand(semanticCommand.getLabel());
cc.compose( semanticCommand );
cc.compose( new CommandProxy(viewCommand) );
return new ICommandProxy(cc);
}
/**
* Gets the command to complete the creation of a new connection and
* relationship (if applicable) for an unspecified type request. This command
* includes a command to popup a menu to prompt the user for the type of
* connection to be created.
*
* @param request
* the unspecified type request
* @return the command
*/
protected Command getUnspecifiedConnectionCompleteCommand(
CreateUnspecifiedTypeConnectionRequest request) {
if (request.isDirectionReversed()) {
return getReversedUnspecifiedConnectionCompleteCommand(request);
}
List menuContent = getConnectionMenuContent(request);
if (menuContent.isEmpty()) {
return null;
} else if (menuContent.size() == 1) {
return getConnectionCompleteCommand(menuContent.get(0), request);
} else {
return new ICommandProxy(getPromptAndCreateConnectionCommand(
menuContent, request));
}
}
/**
* Gets a command that pops up a menu which allows the user to select which
* type of connection to be created and then creates the connection.
*
* @param content
* The list of items making up the content of the popup menu.
* @param request
* The relevant create connection request.
* @return the command to popup up the menu and create the connection
*/
protected ICommand getPromptAndCreateConnectionCommand(List content,
CreateConnectionRequest request) {
return new PromptAndCreateConnectionCommand(content, request);
}
/**
* Gets the command to create a connection based on the request and the
* connection identifier. This method is called after the user has selected
* the connection to be created when presented with a popup.
* @see #getPromptAndCreateConnectionCommand(List, CreateConnectionRequest)
*
* @param connectionType
* the connection type as specified in
* {@link #getConnectionMenuContent(CreateConnectionRequest)}
* @param request
* the request, identifying the source and target
* @return the command to create the connection
*/
protected Command getConnectionCompleteCommand(Object connectionType,
CreateConnectionRequest request) {
if (connectionType instanceof IElementType) {
if (request instanceof CreateUnspecifiedTypeConnectionRequest) {
CreateRequest createRequest = ((CreateUnspecifiedTypeConnectionRequest) request)
.getRequestForType((IElementType) connectionType);
if (createRequest != null) {
return getHost().getCommand(createRequest);
}
}
}
return null;
}
/**
* Gets a list of all the connector items that will represent the connector
* choices and will appear in the popup menu. This method will get the
* connector content if the given request is a
* <code>CreateUnspecifiedTypeConnectionRequest</code> using the types it
* holds or the types retrieved from the Modeling Assistant Service.
*
* <p>
* If a subclass wishes to provide additional element types they should
* consider providing these in a Modeling Assistant Provider. If a subclass
* wishes to provide connector choices that are not elements types they may
* provide them here, in this case, the label provider for
* {@link PromptAndCreateConnectionCommand} may need to customized.
* </p>
*
* @return the list of connector items to appear in the popup menu
*/
protected List getConnectionMenuContent(CreateConnectionRequest request) {
List validRelTypes = new ArrayList();
if (request instanceof CreateUnspecifiedTypeConnectionRequest) {
CreateUnspecifiedTypeConnectionRequest unspecifiedRequest = (CreateUnspecifiedTypeConnectionRequest) request;
List allRequests = unspecifiedRequest.getAllRequests();
if (allRequests.isEmpty()) {
return null;
}
IGraphicalEditPart sourceEP = (IGraphicalEditPart) ((CreateConnectionRequest) allRequests
.get(0)).getSourceEditPart();
IGraphicalEditPart targetEP = (IGraphicalEditPart) ((CreateConnectionRequest) allRequests
.get(0)).getTargetEditPart();
List allRelTypes = unspecifiedRequest.useModelingAssistantService() ? ModelingAssistantService
.getInstance().getRelTypesOnSourceAndTarget(sourceEP, targetEP)
: unspecifiedRequest.getElementTypes();
for (Iterator iter = allRelTypes.iterator(); iter.hasNext();) {
IElementType type = (IElementType) iter.next();
Command individualCmd = null;
Request createConnectionRequest = unspecifiedRequest
.getRequestForType(type);
if (createConnectionRequest != null) {
individualCmd = getHost().getCommand(
createConnectionRequest);
if (individualCmd != null && individualCmd.canExecute()) {
validRelTypes.add(type);
}
} else {
// This type may not have been given when the connection
// creation occurred. In this case, use the deferred
// connection creation mechanism.
// First, setup the request to initialize the connection
// start command.
CreateConnectionViewRequest connectionRequest = CreateViewRequestFactory
.getCreateConnectionRequest(type,
((IGraphicalEditPart) getHost())
.getDiagramPreferencesHint());
connectionRequest.setSourceEditPart(null);
connectionRequest.setTargetEditPart(sourceEP);
connectionRequest
.setType(RequestConstants.REQ_CONNECTION_START);
sourceEP.getCommand(connectionRequest);
// Now, setup the request in preparation to get the
// connection end
// command.
connectionRequest.setSourceEditPart(sourceEP);
connectionRequest.setTargetEditPart(targetEP);
connectionRequest
.setType(RequestConstants.REQ_CONNECTION_END);
individualCmd = targetEP.getCommand(connectionRequest);
if (individualCmd != null && individualCmd.canExecute()) {
validRelTypes.add(type);
unspecifiedRequest.addRequest(type, connectionRequest);
}
}
}
}
return validRelTypes;
}
/**
* Gets the command to complete the creation of a new connection and
* relationship (if applicable) for an unspecified type request. This command
* includes a command to popup a menu to prompt the user for the type of
* relationship to be created.
*
* @param request
* the reversed unspecified type request
* @return the command
*/
protected Command getReversedUnspecifiedConnectionCompleteCommand(
CreateUnspecifiedTypeConnectionRequest request) {
EditPart realSourceEP = request.getTargetEditPart();
EditPart realTargetEP = request.getSourceEditPart();
for (Iterator iter = request.getAllRequests().iterator(); iter
.hasNext();) {
CreateConnectionRequest connectionRequest = (CreateConnectionRequest) iter
.next();
// First, setup the request to initialize the connection start
// command.
connectionRequest.setSourceEditPart(null);
connectionRequest.setTargetEditPart(realSourceEP);
connectionRequest.setType(RequestConstants.REQ_CONNECTION_START);
realSourceEP.getCommand(connectionRequest);
// Now, setup the request in preparation to get the connection end
// command.
connectionRequest.setSourceEditPart(realSourceEP);
connectionRequest.setTargetEditPart(realTargetEP);
connectionRequest.setType(RequestConstants.REQ_CONNECTION_END);
}
// The requests are now ready to be sent to get the connection end
// command from real source to real target.
request.setDirectionReversed(false);
Command command = realTargetEP.getCommand(request);
return command;
}
private TransactionalEditingDomain getEditingDomain() {
return ((IGraphicalEditPart) getHost()).getEditingDomain();
}
}