/******************************************************************************* * Copyright (c) 2004, 2005 Elias Volanakis 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: �*����Elias Volanakis - initial API and implementation �*******************************************************************************/ package org.eclipse.gef.examples.shapes.model.commands; import java.util.Iterator; import org.eclipse.gef.commands.Command; import org.eclipse.gef.examples.shapes.model.Connection; import org.eclipse.gef.examples.shapes.model.Shape; /** * A command to reconnect a connection to a different start point or end point. * The command can be undone or redone. * <p> * This command is designed to be used together with a GraphicalNodeEditPolicy. * To use this command propertly, following steps are necessary: * </p> * <ol> * <li>Create a subclass of GraphicalNodeEditPolicy.</li> * <li>Override the <tt>getReconnectSourceCommand(...)</tt> method. * Here you need to obtain the Connection model element from the ReconnectRequest, * create a new ConnectionReconnectCommand, set the new connection <i>source</i> by calling * the <tt>setNewSource(Shape)</tt> method and return the command instance. * <li>Override the <tt>getReconnectTargetCommand(...)</tt> method.</li> * Here again you need to obtain the Connection model element from the ReconnectRequest, * create a new ConnectionReconnectCommand, set the new connection <i>target</i> by calling * the <tt>setNewTarget(Shape)</tt> method and return the command instance.</li> * </ol> * @see org.eclipse.gef.examples.shapes.parts.ShapeEditPart#createEditPolicies() for an * example of the above procedure. * @see org.eclipse.gef.editpolicies.GraphicalNodeEditPolicy * @see #setNewSource(Shape) * @see #setNewTarget(Shape) * @author Elias Volanakis */ public class ConnectionReconnectCommand extends Command { /** The connection instance to reconnect. */ private Connection connection; /** The new source endpoint. */ private Shape newSource; /** The new target endpoint. */ private Shape newTarget; /** The original source endpoint. */ private final Shape oldSource; /** The original target endpoint. */ private final Shape oldTarget; /** * Instantiate a command that can reconnect a Connection instance to a different source * or target endpoint. * @param conn the connection instance to reconnect (non-null) * @throws IllegalArgumentException if conn is null */ public ConnectionReconnectCommand(Connection conn) { if (conn == null) { throw new IllegalArgumentException(); } this.connection = conn; this.oldSource = conn.getSource(); this.oldTarget = conn.getTarget(); } /* (non-Javadoc) * @see org.eclipse.gef.commands.Command#canExecute() */ public boolean canExecute() { if (newSource != null) { return checkSourceReconnection(); } else if (newTarget != null) { return checkTargetReconnection(); } return false; } /** * Return true, if reconnecting the connection-instance to newSource is allowed. */ private boolean checkSourceReconnection() { // connection endpoints must be different Shapes if (newSource.equals(oldTarget)) { return false; } // return false, if the connection exists already for (Iterator iter = newSource.getSourceConnections().iterator(); iter.hasNext();) { Connection conn = (Connection) iter.next(); // return false if a newSource -> oldTarget connection exists already // and it is a different instance than the connection-field if (conn.getTarget().equals(oldTarget) && !conn.equals(connection)) { return false; } } return true; } /** * Return true, if reconnecting the connection-instance to newTarget is allowed. */ private boolean checkTargetReconnection() { // connection endpoints must be different Shapes if (newTarget.equals(oldSource)) { return false; } // return false, if the connection exists already for (Iterator iter = newTarget.getTargetConnections().iterator(); iter.hasNext();) { Connection conn = (Connection) iter.next(); // return false if a oldSource -> newTarget connection exists already // and it is a differenct instance that the connection-field if (conn.getSource().equals(oldSource) && !conn.equals(connection)) { return false; } } return true; } /** * Reconnect the connection to newSource (if setNewSource(...) was invoked before) * or newTarget (if setNewTarget(...) was invoked before). */ public void execute() { if (newSource != null) { connection.reconnect(newSource, oldTarget); } else if (newTarget != null) { connection.reconnect(oldSource, newTarget); } else { throw new IllegalStateException("Should not happen"); } } /** * Set a new source endpoint for this connection. * When execute() is invoked, the source endpoint of the connection will be attached * to the supplied Shape instance. * <p> * Note: Calling this method, deactivates reconnection of the <i>target</i> endpoint. * A single instance of this command can only reconnect either the source or the target * endpoint. * </p> * @param connectionSource a non-null Shape instance, to be used as a new source endpoint * @throws IllegalArgumentException if connectionSource is null */ public void setNewSource(Shape connectionSource) { if (connectionSource == null) { throw new IllegalArgumentException(); } setLabel("move connection startpoint"); newSource = connectionSource; newTarget = null; } /** * Set a new target endpoint for this connection * When execute() is invoked, the target endpoint of the connection will be attached * to the supplied Shape instance. * <p> * Note: Calling this method, deactivates reconnection of the <i>source</i> endpoint. * A single instance of this command can only reconnect either the source or the target * endpoint. * </p> * @param connectionTarget a non-null Shape instance, to be used as a new target endpoint * @throws IllegalArgumentException if connectionTarget is null */ public void setNewTarget(Shape connectionTarget) { if (connectionTarget == null) { throw new IllegalArgumentException(); } setLabel("move connection endpoint"); newSource = null; newTarget = connectionTarget; } /** * Reconnect the connection to its original source and target endpoints. */ public void undo() { connection.reconnect(oldSource, oldTarget); } }