/******************************************************************************* * Copyright (c) 2000, 2010 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.gef.editpolicies; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.List; import org.eclipse.draw2d.AncestorListener; import org.eclipse.draw2d.ColorConstants; import org.eclipse.draw2d.Connection; import org.eclipse.draw2d.ConnectionAnchor; import org.eclipse.draw2d.ConnectionLocator; import org.eclipse.draw2d.Graphics; import org.eclipse.draw2d.IFigure; import org.eclipse.draw2d.Polygon; import org.eclipse.draw2d.geometry.PointList; import org.eclipse.gef.ConnectionEditPart; import org.eclipse.gef.GraphicalEditPart; import org.eclipse.gef.NodeEditPart; import org.eclipse.gef.Request; import org.eclipse.gef.commands.Command; import org.eclipse.gef.handles.ConnectionEndpointHandle; import org.eclipse.gef.requests.ReconnectRequest; /** * A selection handle policy for placing handles at the two ends of a * ConnectionEditPart. All ConnectionEditParts should have one of these, even if * the ends of the connection aren't draggable, because this is the primary * SelectionEditPolicy for showing focus. * <P> * A connection can receive focus but not selection by pressing * <code>Control+/</code> on the keyboard. * * @since 2.0 */ public class ConnectionEndpointEditPolicy extends SelectionHandlesEditPolicy { private ConnectionAnchor originalAnchor; private FeedbackHelper feedbackHelper; private ConnectionFocus focus; class ConnectionFocus extends Polygon implements PropertyChangeListener { AncestorListener ancestorListener = new AncestorListener.Stub() { public void ancestorMoved(IFigure ancestor) { revalidate(); } }; ConnectionFocus() { setFill(false); setForegroundColor(ColorConstants.white()); setXOR(true); setOutline(true); } public void addNotify() { super.addNotify(); getConnection().addPropertyChangeListener( Connection.PROPERTY_POINTS, this); getConnection().addAncestorListener(ancestorListener); } protected void outlineShape(Graphics g) { g.setLineDash(new int[] { 1, 1 }); super.outlineShape(g); } public void propertyChange(PropertyChangeEvent evt) { revalidate(); } public void removeNotify() { getConnection().removePropertyChangeListener( Connection.PROPERTY_POINTS, this); getConnection().removeAncestorListener(ancestorListener); super.removeNotify(); } public void validate() { if (isValid()) return; PointList points = getConnection().getPoints().getCopy(); getConnection().translateToAbsolute(points); points = StrokePointList.strokeList(points, 5); translateToRelative(points); setPoints(points); } } /** * @see org.eclipse.gef.editpolicies.SelectionHandlesEditPolicy#createSelectionHandles() */ protected List createSelectionHandles() { List list = new ArrayList(); list.add(new ConnectionEndpointHandle((ConnectionEditPart) getHost(), ConnectionLocator.SOURCE)); list.add(new ConnectionEndpointHandle((ConnectionEditPart) getHost(), ConnectionLocator.TARGET)); return list; } /** * Erases connection move feedback. This method is called when a * ReconnectRequest is received. * * @param request * the reconnect request. */ protected void eraseConnectionMoveFeedback(ReconnectRequest request) { if (originalAnchor == null) return; if (request.isMovingStartAnchor()) getConnection().setSourceAnchor(originalAnchor); else getConnection().setTargetAnchor(originalAnchor); originalAnchor = null; feedbackHelper = null; } /** * @see org.eclipse.gef.EditPolicy#eraseSourceFeedback(org.eclipse.gef.Request) */ public void eraseSourceFeedback(Request request) { if (REQ_RECONNECT_TARGET.equals(request.getType()) || REQ_RECONNECT_SOURCE.equals(request.getType())) eraseConnectionMoveFeedback((ReconnectRequest) request); } /** * @see org.eclipse.gef.EditPolicy#getCommand(org.eclipse.gef.Request) */ public Command getCommand(Request request) { return null; } /** * Convenience method for obtaining the host's <code>Connection</code> * figure. * * @return the Connection figure */ protected Connection getConnection() { return (Connection) ((GraphicalEditPart) getHost()).getFigure(); } /** * Lazily creates and returns the feedback helper for the given request. The * helper will be configured as either moving the source or target end of * the connection. * * @param request * the reconnect request * @return the feedback helper */ protected FeedbackHelper getFeedbackHelper(ReconnectRequest request) { if (feedbackHelper == null) { feedbackHelper = new FeedbackHelper(); feedbackHelper.setConnection(getConnection()); feedbackHelper.setMovingStartAnchor(request.isMovingStartAnchor()); } return feedbackHelper; } /** * Hides the focus indicator. The focus indicator is a dotted outline around * the connection. * * @see #showFocus() * @see org.eclipse.gef.editpolicies.SelectionEditPolicy#hideFocus() */ protected void hideFocus() { if (focus != null) { removeFeedback(focus); focus = null; } } /** * Shows or updates connection move feedback. Called whenever a show * feedback request is received for reconnection. * * @param request * the reconnect request */ protected void showConnectionMoveFeedback(ReconnectRequest request) { NodeEditPart node = null; if (request.getTarget() instanceof NodeEditPart) node = (NodeEditPart) request.getTarget(); if (originalAnchor == null) { if (request.isMovingStartAnchor()) originalAnchor = getConnection().getSourceAnchor(); else originalAnchor = getConnection().getTargetAnchor(); } ConnectionAnchor anchor = null; if (node != null) { if (request.isMovingStartAnchor()) anchor = node.getSourceConnectionAnchor(request); else anchor = node.getTargetConnectionAnchor(request); } FeedbackHelper helper = getFeedbackHelper(request); helper.update(anchor, request.getLocation()); } /** * Shows focus around the connection. * * @see org.eclipse.gef.editpolicies.SelectionEditPolicy#showFocus() */ protected void showFocus() { if (focus == null) { focus = new ConnectionFocus(); addFeedback(focus); } } /** * @see org.eclipse.gef.EditPolicy#showSourceFeedback(org.eclipse.gef.Request) */ public void showSourceFeedback(Request request) { if (REQ_RECONNECT_SOURCE.equals(request.getType()) || REQ_RECONNECT_TARGET.equals(request.getType())) showConnectionMoveFeedback((ReconnectRequest) request); } }