| /****************************************************************************** |
| * Copyright (c) 2002, 2007 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.editparts; |
| |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| |
| import org.eclipse.draw2d.Connection; |
| import org.eclipse.draw2d.ConnectionAnchor; |
| import org.eclipse.draw2d.geometry.Point; |
| import org.eclipse.emf.common.notify.Notification; |
| import org.eclipse.emf.transaction.RunnableWithResult; |
| import org.eclipse.gef.EditPart; |
| import org.eclipse.gef.EditPolicy; |
| import org.eclipse.gef.NodeEditPart; |
| import org.eclipse.gef.Request; |
| import org.eclipse.gef.requests.CreateRequest; |
| import org.eclipse.gef.requests.DropRequest; |
| import org.eclipse.gef.requests.ReconnectRequest; |
| import org.eclipse.gmf.runtime.common.core.util.Log; |
| import org.eclipse.gmf.runtime.common.core.util.Trace; |
| import org.eclipse.gmf.runtime.diagram.core.util.ViewUtil; |
| import org.eclipse.gmf.runtime.diagram.ui.editpolicies.GraphicalNodeEditPolicy; |
| import org.eclipse.gmf.runtime.diagram.ui.internal.DiagramUIDebugOptions; |
| import org.eclipse.gmf.runtime.diagram.ui.internal.DiagramUIPlugin; |
| import org.eclipse.gmf.runtime.diagram.ui.internal.DiagramUIStatusCodes; |
| import org.eclipse.gmf.runtime.diagram.ui.internal.editpolicies.NoteAttachmentReorientEditPolicy; |
| import org.eclipse.gmf.runtime.draw2d.ui.figures.IAnchorableFigure; |
| import org.eclipse.gmf.runtime.notation.Anchor; |
| import org.eclipse.gmf.runtime.notation.IdentityAnchor; |
| import org.eclipse.gmf.runtime.notation.NotationPackage; |
| import org.eclipse.gmf.runtime.notation.View; |
| |
| /** |
| * Connection Node EditPart, a specialized Connection EditPart that installs |
| * a <code>ditPolicy.GRAPHICAL_NODE_ROLE</code> on this edit part. it also implements |
| * INodeEditPart which defines the connectable edit parts |
| * @author mmostafa |
| */ |
| abstract public class ConnectionNodeEditPart |
| extends ConnectionEditPart |
| implements INodeEditPart { |
| |
| /** |
| * constructor |
| * @param view owned view by this edit part |
| */ |
| public ConnectionNodeEditPart(View view) { |
| super(view); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.gmf.runtime.diagram.ui.editparts.ConnectionEditPart#createDefaultEditPolicies() |
| */ |
| protected void createDefaultEditPolicies() { |
| // node edit policy needs to be installed before connection editpolicy from the super |
| // since connections of a node need to be deleted before the node |
| //installEditPolicy(EditPolicy.NODE_ROLE, new NodeEditPolicy()); |
| super.createDefaultEditPolicies(); |
| installEditPolicy(EditPolicy.GRAPHICAL_NODE_ROLE, new GraphicalNodeEditPolicy()); |
| |
| // Disable note attachment reorient between two shapes where neither is a note. |
| installEditPolicy("NoteAttachmentReorient", //$NON-NLS-1$ |
| new NoteAttachmentReorientEditPolicy()); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.gef.editparts.AbstractGraphicalEditPart#getModelSourceConnections() |
| */ |
| protected List getModelSourceConnections(){ |
| return ViewUtil.getSourceConnections(getEdge()); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.gef.editparts.AbstractGraphicalEditPart#getModelTargetConnections() |
| */ |
| protected List getModelTargetConnections(){ |
| return ViewUtil.getTargetConnections(getEdge()); |
| } |
| |
| protected ConnectionAnchor getSourceConnectionAnchor() { |
| if (getSource() != null && getSource() instanceof NodeEditPart) { |
| NodeEditPart editPart = (NodeEditPart) getSource(); |
| return editPart.getSourceConnectionAnchor(this); |
| } |
| return super.getSourceConnectionAnchor(); |
| } |
| |
| /* |
| * @see NodeEditPart#getSourceConnectionAnchor(ConnectionEditPart) |
| */ |
| public ConnectionAnchor getSourceConnectionAnchor(org.eclipse.gef.ConnectionEditPart connEditPart) { |
| final ConnectionNodeEditPart connection = (ConnectionNodeEditPart) connEditPart; |
| String t = ""; //$NON-NLS-1$ |
| try { |
| t = (String) getEditingDomain().runExclusive( |
| new RunnableWithResult.Impl() { |
| |
| public void run() { |
| Anchor a = connection.getEdge().getSourceAnchor(); |
| if (a instanceof IdentityAnchor) |
| setResult(((IdentityAnchor) a).getId()); |
| else |
| setResult(""); //$NON-NLS-1$ |
| } |
| }); |
| } catch (InterruptedException e) { |
| Trace.catching(DiagramUIPlugin.getInstance(), |
| DiagramUIDebugOptions.EXCEPTIONS_CATCHING, getClass(), |
| "getSourceConnectionAnchor", e); //$NON-NLS-1$ |
| Log.error(DiagramUIPlugin.getInstance(), |
| DiagramUIStatusCodes.IGNORED_EXCEPTION_WARNING, |
| "getSourceConnectionAnchor", e); //$NON-NLS-1$ |
| } |
| return ((IAnchorableFigure)getFigure()).getConnectionAnchor(t); |
| } |
| |
| /* |
| * @see NodeEditPart#getSourceConnectionAnchor(Request) |
| */ |
| public ConnectionAnchor getSourceConnectionAnchor(Request request) { |
| Point center = getFigure().getBounds().getCenter(); |
| getFigure().translateToAbsolute(center); |
| Point pt = ((DropRequest)request).getLocation()==null ? |
| center : new Point(((DropRequest)request).getLocation()); |
| if (request instanceof CreateRequest) { |
| getFigure().translateToRelative(pt); |
| } |
| return ((IAnchorableFigure)getFigure()).getSourceConnectionAnchorAt(pt); |
| } |
| |
| protected ConnectionAnchor getTargetConnectionAnchor() { |
| if (getTarget() instanceof NodeEditPart) { |
| NodeEditPart editPart = (NodeEditPart) getTarget(); |
| return editPart.getTargetConnectionAnchor(this); |
| } |
| return super.getTargetConnectionAnchor(); |
| } |
| |
| /* |
| * @see NodeEditPart#getTargetConnectionAnchor(ConnectionEditPart) |
| */ |
| public ConnectionAnchor getTargetConnectionAnchor(org.eclipse.gef.ConnectionEditPart connEditPart) { |
| final ConnectionNodeEditPart connection = (ConnectionNodeEditPart) connEditPart; |
| String t = ""; //$NON-NLS-1$ |
| try { |
| t = (String) getEditingDomain().runExclusive( |
| new RunnableWithResult.Impl() { |
| |
| public void run() { |
| Anchor a = connection.getEdge().getTargetAnchor(); |
| if (a instanceof IdentityAnchor) |
| setResult(((IdentityAnchor) a).getId()); |
| else |
| setResult(""); //$NON-NLS-1$ |
| } |
| }); |
| } catch (InterruptedException e) { |
| Trace.catching(DiagramUIPlugin.getInstance(), |
| DiagramUIDebugOptions.EXCEPTIONS_CATCHING, getClass(), |
| "getTargetConnectionAnchor", e); //$NON-NLS-1$ |
| Log.error(DiagramUIPlugin.getInstance(), |
| DiagramUIStatusCodes.IGNORED_EXCEPTION_WARNING, |
| "getTargetConnectionAnchor", e); //$NON-NLS-1$ |
| } |
| return ((IAnchorableFigure)getFigure()).getConnectionAnchor(t); |
| } |
| |
| /* |
| * @see NodeEditPart#getTargetConnectionAnchor(Request) |
| */ |
| public ConnectionAnchor getTargetConnectionAnchor(Request request) { |
| Point center = getFigure().getBounds().getCenter(); |
| getFigure().translateToAbsolute(center); |
| Point pt = ((DropRequest)request).getLocation()==null ? |
| center : new Point(((DropRequest)request).getLocation()); |
| if (request instanceof CreateRequest) { |
| getFigure().translateToRelative(pt); |
| } |
| return ((IAnchorableFigure)getFigure()).getTargetConnectionAnchorAt(pt); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.gmf.runtime.diagram.ui.editparts.INodeEditPart#mapConnectionAnchorToTerminal(org.eclipse.draw2d.ConnectionAnchor) |
| */ |
| final public String mapConnectionAnchorToTerminal(ConnectionAnchor c) { |
| return ((IAnchorableFigure) getFigure()).getConnectionAnchorTerminal(c); |
| } |
| |
| /** |
| * @see org.eclipse.gmf.runtime.diagram.ui.editparts.INodeEditPart#mapTerminalToConnectionAnchor(String) |
| */ |
| final public ConnectionAnchor mapTerminalToConnectionAnchor(String terminal) { |
| return ((IAnchorableFigure) getFigure()).getConnectionAnchor(terminal); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.gmf.runtime.diagram.ui.internal.editparts.INoteableEditPart#canAttachNote() |
| */ |
| public boolean canAttachNote() { |
| return true; |
| } |
| |
| /* |
| * @see org.eclipse.gmf.runtime.diagram.ui.editparts.ConnectionEditPart#handleNotificationEvent(org.eclipse.gmf.runtime.diagram.ui.internal.listener.NotificationEvent) |
| */ |
| protected void handleNotificationEvent(Notification notification) { |
| Object feature = notification.getFeature(); |
| if (NotationPackage.eINSTANCE.getView_SourceEdges().equals(feature)) |
| refreshSourceConnections(); |
| else |
| if (NotationPackage.eINSTANCE.getView_TargetEdges().equals(feature)) |
| refreshTargetConnections(); |
| else |
| super.handleNotificationEvent(notification); |
| |
| if ( NotationPackage.eINSTANCE.getIdentityAnchor_Id().equals(feature) || |
| notification.getNewValue() instanceof IdentityAnchor || |
| notification.getOldValue() instanceof IdentityAnchor) { |
| anchorChange(); |
| } |
| } |
| |
| /** |
| * updates identity connection anchors |
| */ |
| public void anchorChange() { |
| refreshSourceAnchor(); |
| refreshTargetAnchor(); |
| } |
| |
| /** |
| * Retrieve the list of all source and target connections for the connection. |
| * @param set HashSet to add the connections to. |
| * @param connectionEditPart the connection edit part. |
| */ |
| private void getSourceAndTargetConnections(HashSet set, |
| org.eclipse.gef.ConnectionEditPart connectionEditPart) { |
| |
| if (connectionEditPart == null || set == null) |
| return; |
| |
| for (Iterator i = connectionEditPart.getSourceConnections().iterator(); |
| i.hasNext();) { |
| |
| org.eclipse.gef.ConnectionEditPart next = |
| (org.eclipse.gef.ConnectionEditPart) i.next(); |
| Connection sourceConnection = (Connection) next.getFigure(); |
| set.add(sourceConnection); |
| getSourceAndTargetConnections(set, next); |
| } |
| |
| for (Iterator i = connectionEditPart.getTargetConnections().iterator(); |
| i.hasNext();) { |
| |
| org.eclipse.gef.ConnectionEditPart next = |
| (org.eclipse.gef.ConnectionEditPart) i.next(); |
| Connection targetConnection = (Connection) next.getFigure(); |
| set.add(targetConnection); |
| getSourceAndTargetConnections(set, next); |
| } |
| } |
| |
| /** |
| * Figure out if a cyclic dependency will arise if target connection edit part |
| * is connected to the source connection edit part. |
| * @param targetCEP the target connection edit part |
| * @param sourceCEP the source connection edit part |
| * @param checkSourceAndTargetEditParts check both the source and taret edit parts |
| * for cyclic dependencies |
| * @param doNotCheckSourceEditPart (if checkSourceAndTargetEditParts is false) check |
| * only the target edit part if true, otherwise check only the source edit part |
| * @return true if a cyclic dependency would be create when targetCEP and |
| * sourceCEP were to be connected, false otherwise. |
| */ |
| private boolean isCyclicConnectionRequest(org.eclipse.gef.ConnectionEditPart targetCEP, |
| org.eclipse.gef.ConnectionEditPart sourceCEP, |
| boolean checkSourceAndTargetEditParts, boolean doNotCheckSourceEditPart) { |
| |
| if (targetCEP == null || sourceCEP == null) |
| return false; |
| |
| if (sourceCEP == targetCEP) |
| return true; |
| |
| // first, do a cyclic check on source and target connections |
| // of the source connection itself. |
| // (as every connection is also a node). |
| |
| HashSet set = new HashSet(); |
| getSourceAndTargetConnections(set, sourceCEP); |
| if (set.contains(targetCEP.getFigure())) |
| return true; |
| |
| |
| // now do the cyclic check on the source and target of the source connection... |
| EditPart sourceEP = sourceCEP.getSource(), |
| targetEP = sourceCEP.getTarget(); |
| |
| if ((sourceEP == targetCEP) || (targetEP == targetCEP)) { |
| return true; |
| } |
| else { |
| |
| if (!checkSourceAndTargetEditParts && doNotCheckSourceEditPart) { |
| // . |
| } |
| else |
| if (sourceEP instanceof org.eclipse.gef.ConnectionEditPart && |
| isCyclicConnectionRequest(targetCEP, |
| (org.eclipse.gef.ConnectionEditPart)sourceEP, |
| true, doNotCheckSourceEditPart)) |
| return true; |
| |
| if (!checkSourceAndTargetEditParts && !doNotCheckSourceEditPart) { |
| // . |
| } |
| else |
| if (targetEP instanceof org.eclipse.gef.ConnectionEditPart && |
| isCyclicConnectionRequest(targetCEP, |
| (org.eclipse.gef.ConnectionEditPart)targetEP, |
| true, doNotCheckSourceEditPart)) |
| return true; |
| } |
| |
| return false; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.gef.editparts.AbstractEditPart#getTargetEditPart(org.eclipse.gef.Request) |
| */ |
| public EditPart getTargetEditPart(Request request) { |
| EditPart ep = super.getTargetEditPart(request); |
| |
| if (ep != null && ep instanceof org.eclipse.gef.ConnectionEditPart) { |
| if (request instanceof ReconnectRequest) { |
| ReconnectRequest rRequest = (ReconnectRequest)request; |
| |
| // If this is just moving an anchor point on the same target or |
| // source, then it is fine. See bugzilla# 208408. |
| if (rRequest.isMovingStartAnchor()) { |
| if (rRequest.getConnectionEditPart().getSource() == ep) { |
| return ep; |
| } |
| } else if (rRequest.getConnectionEditPart().getTarget() == ep) { |
| return ep; |
| } |
| |
| // If source anchor is moved, the connection's source edit part |
| // should not be taken into account for a cyclic dependency |
| // check so as to avoid false checks. Same goes for the target |
| // anchor. See bugzilla# 155243 -- we do not want to target a |
| // connection that is already connected to us so that we do not |
| // introduce a cyclic connection |
| if (isCyclicConnectionRequest((org.eclipse.gef.ConnectionEditPart)ep, |
| rRequest.getConnectionEditPart(), false, rRequest.isMovingStartAnchor())) |
| return null; |
| } |
| } |
| |
| return ep; |
| } |
| } |