| /******************************************************************************* |
| * 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.tools; |
| |
| import java.util.List; |
| |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.events.KeyEvent; |
| import org.eclipse.swt.widgets.Event; |
| |
| import org.eclipse.draw2d.PositionConstants; |
| import org.eclipse.draw2d.geometry.Point; |
| |
| import org.eclipse.gef.AccessibleAnchorProvider; |
| import org.eclipse.gef.EditPart; |
| import org.eclipse.gef.EditPartViewer; |
| import org.eclipse.gef.commands.Command; |
| import org.eclipse.gef.requests.CreateConnectionRequest; |
| import org.eclipse.gef.requests.CreationFactory; |
| |
| /** |
| * The default creation tool for connections. With this tool, the user must |
| * click and release the left mouse button on the source edit part and then |
| * click and release the left mouse button on the target edit part. By default, |
| * this tool will remain active after connections are created. The user must |
| * select a different tool to deactivate this tool. |
| */ |
| public class ConnectionCreationTool extends AbstractConnectionCreationTool { |
| |
| /** |
| * Default Constructor. |
| */ |
| public ConnectionCreationTool() { |
| setUnloadWhenFinished(false); |
| } |
| |
| /** |
| * Constructs a new ConnectionCreationTool with the given factory. |
| * |
| * @param factory |
| * the creation factory |
| */ |
| public ConnectionCreationTool(CreationFactory factory) { |
| setFactory(factory); |
| setUnloadWhenFinished(false); |
| } |
| |
| boolean acceptConnectionFinish(KeyEvent event) { |
| return isInState(STATE_ACCESSIBLE_DRAG_IN_PROGRESS) |
| && event.character == 13; |
| } |
| |
| boolean acceptConnectionStart(KeyEvent event) { |
| return isInState(STATE_INITIAL) && event.character == 13; |
| } |
| |
| /** |
| * If the connections is already started, the second button down will call |
| * {@link AbstractConnectionCreationTool#handleCreateConnection()}. |
| * Otherwise, it attempts to start the connection. |
| * |
| * @param button |
| * the button that was pressed |
| * @return <code>true</code> if the button down was processed |
| */ |
| protected boolean handleButtonDown(int button) { |
| if (button == 1 |
| && stateTransition(STATE_CONNECTION_STARTED, STATE_TERMINAL)) |
| return handleCreateConnection(); |
| |
| super.handleButtonDown(button); |
| if (isInState(STATE_CONNECTION_STARTED)) |
| // Fake a drag to cause feedback to be displayed immediately on |
| // mouse down. |
| handleDrag(); |
| return true; |
| } |
| |
| /** |
| * Cleans up feedback and resets the tool when focus is lost. |
| * |
| * @return <code>true</code> if this focus lost event was processed |
| */ |
| protected boolean handleFocusLost() { |
| if (isInState(STATE_CONNECTION_STARTED |
| | STATE_ACCESSIBLE_DRAG_IN_PROGRESS)) { |
| eraseSourceFeedback(); |
| eraseTargetFeedback(); |
| setState(STATE_INVALID); |
| handleFinished(); |
| } |
| return super.handleFocusLost(); |
| } |
| |
| /** |
| * Processes the arrow keys (to move the cursor to nearby anchor locations) |
| * and the enter key (to start or complete a connections). |
| * |
| * @param event |
| * the key event |
| * @return <code>true</code> if this key down event was processed |
| */ |
| protected boolean handleKeyDown(KeyEvent event) { |
| if (acceptArrowKey(event)) { |
| int direction = 0; |
| switch (event.keyCode) { |
| case SWT.ARROW_DOWN: |
| direction = PositionConstants.SOUTH; |
| break; |
| case SWT.ARROW_UP: |
| direction = PositionConstants.NORTH; |
| break; |
| case SWT.ARROW_RIGHT: |
| direction = isCurrentViewerMirrored() ? PositionConstants.WEST |
| : PositionConstants.EAST; |
| break; |
| case SWT.ARROW_LEFT: |
| direction = isCurrentViewerMirrored() ? PositionConstants.EAST |
| : PositionConstants.WEST; |
| break; |
| } |
| |
| boolean consumed = false; |
| if (direction != 0 && event.stateMask == 0) |
| consumed = navigateNextAnchor(direction); |
| if (!consumed) { |
| event.stateMask |= SWT.CONTROL; |
| event.stateMask &= ~SWT.SHIFT; |
| if (getCurrentViewer().getKeyHandler().keyPressed(event)) { |
| navigateNextAnchor(0); |
| updateTargetRequest(); |
| updateTargetUnderMouse(); |
| Command command = getCommand(); |
| if (command != null) |
| setCurrentCommand(command); |
| return true; |
| } |
| } |
| } |
| |
| if (event.character == '/' || event.character == '\\') { |
| event.stateMask |= SWT.CONTROL; |
| if (getCurrentViewer().getKeyHandler().keyPressed(event)) { |
| navigateNextAnchor(0); |
| return true; |
| } |
| } |
| |
| if (acceptConnectionStart(event)) { |
| Command command = getCommand(); |
| if (command != null && command.canExecute()) { |
| updateTargetUnderMouse(); |
| setConnectionSource(getTargetEditPart()); |
| ((CreateConnectionRequest) getTargetRequest()) |
| .setSourceEditPart(getTargetEditPart()); |
| setState(STATE_ACCESSIBLE_DRAG_IN_PROGRESS); |
| placeMouseInViewer(getLocation().getTranslated(6, 6)); |
| } |
| return true; |
| } |
| |
| if (acceptConnectionFinish(event)) { |
| Command command = getCommand(); |
| if (command != null && command.canExecute()) { |
| setState(STATE_INITIAL); |
| placeMouseInViewer(getLocation().getTranslated(6, 6)); |
| eraseSourceFeedback(); |
| eraseTargetFeedback(); |
| setCurrentCommand(command); |
| executeCurrentCommand(); |
| } |
| return true; |
| } |
| |
| return super.handleKeyDown(event); |
| } |
| |
| /** |
| * Scrolling can happen either in the {@link AbstractTool#STATE_INITIAL |
| * initial} state or once the source of the connection has been |
| * {@link AbstractConnectionCreationTool#STATE_CONNECTION_STARTED |
| * identified}. |
| * |
| * @see org.eclipse.gef.Tool#mouseWheelScrolled(org.eclipse.swt.widgets.Event, |
| * org.eclipse.gef.EditPartViewer) |
| */ |
| public void mouseWheelScrolled(Event event, EditPartViewer viewer) { |
| if (isInState(STATE_INITIAL | STATE_CONNECTION_STARTED)) |
| performViewerMouseWheel(event, viewer); |
| } |
| |
| boolean navigateNextAnchor(int direction) { |
| EditPart focus = getCurrentViewer().getFocusEditPart(); |
| AccessibleAnchorProvider provider; |
| provider = (AccessibleAnchorProvider) focus |
| .getAdapter(AccessibleAnchorProvider.class); |
| if (provider == null) |
| return false; |
| |
| List list; |
| if (isInState(STATE_ACCESSIBLE_DRAG_IN_PROGRESS)) |
| list = provider.getTargetAnchorLocations(); |
| else |
| list = provider.getSourceAnchorLocations(); |
| |
| Point start = getLocation(); |
| int distance = Integer.MAX_VALUE; |
| Point next = null; |
| for (int i = 0; i < list.size(); i++) { |
| Point p = (Point) list.get(i); |
| if (p.equals(start) |
| || (direction != 0 && (start.getPosition(p) != direction))) |
| continue; |
| int d = p.getDistanceOrthogonal(start); |
| if (d < distance) { |
| distance = d; |
| next = p; |
| } |
| } |
| |
| if (next != null) { |
| placeMouseInViewer(next); |
| return true; |
| } |
| return false; |
| } |
| |
| } |