| /******************************************************************************* |
| * 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.beans.IntrospectionException; |
| import java.beans.Introspector; |
| import java.beans.PropertyDescriptor; |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| import java.util.ArrayList; |
| import java.util.Date; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| |
| import org.eclipse.swt.dnd.DragSourceEvent; |
| import org.eclipse.swt.events.FocusEvent; |
| import org.eclipse.swt.events.KeyEvent; |
| import org.eclipse.swt.events.MouseEvent; |
| import org.eclipse.swt.events.TraverseEvent; |
| import org.eclipse.swt.graphics.Cursor; |
| import org.eclipse.swt.graphics.Rectangle; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.swt.widgets.Event; |
| import org.eclipse.swt.widgets.Scrollable; |
| |
| import org.eclipse.core.runtime.Platform; |
| |
| import org.eclipse.draw2d.IFigure; |
| import org.eclipse.draw2d.geometry.Dimension; |
| import org.eclipse.draw2d.geometry.Point; |
| import org.eclipse.draw2d.rap.swt.SWT; |
| |
| import org.eclipse.gef.DragTracker; |
| import org.eclipse.gef.EditDomain; |
| import org.eclipse.gef.EditPartViewer; |
| import org.eclipse.gef.LayerConstants; |
| import org.eclipse.gef.MouseWheelHandler; |
| import org.eclipse.gef.RequestConstants; |
| import org.eclipse.gef.Tool; |
| import org.eclipse.gef.commands.Command; |
| import org.eclipse.gef.commands.CommandStackEvent; |
| import org.eclipse.gef.commands.CommandStackEventListener; |
| import org.eclipse.gef.editparts.LayerManager; |
| |
| /** |
| * The base implementation for {@link Tool}s. The base implementation provides a |
| * framework for a <EM>state machine</EM> which processes mouse and keyboard |
| * input. The state machine consists of a series of states identified by |
| * <code>int</code>s. Each mouse or keyboard event results in a transition, |
| * sometimes to the same state in which the input was received. The interesting |
| * transitions have corresponding actions assigned to them, such as |
| * {@link #handleDragStarted()}. |
| * <P> |
| * The base implementation performs <EM>no</em> state transitions by default, |
| * but does route events to different method handlers based on state. It is up |
| * to subclasses to set the appropriate states. |
| * <P> |
| * There are two broad "categories" of methods on AbstractTool. There are the |
| * methods defined on the {@link Tool} interface which handle the job of |
| * receiving raw user input. For example, |
| * {@link #mouseDrag(MouseEvent, EditPartViewer)}. Then, there are the methods |
| * which correspond to higher-level interpretation of these events, such as |
| * {@link #handleDragInProgress()}, which is called from |
| * <code>mouseMove(...)</code>, but <em>only</em> when the drag threshold has |
| * been passed. These methods are generally more subclass-friendly. Subclasses |
| * should <em>not</em> override the methods which receive raw input. |
| */ |
| public abstract class AbstractTool extends org.eclipse.gef.util.FlagSupport |
| implements Tool, RequestConstants { |
| |
| /** |
| * The property to be used in {@link #setProperties(Map)} for |
| * {@link #setUnloadWhenFinished(boolean)} |
| */ |
| public static final Object PROPERTY_UNLOAD_WHEN_FINISHED = "unloadWhenFinished"; //$NON-NLS-1$ |
| |
| private static final int DRAG_THRESHOLD = 5; |
| private static final int FLAG_ACTIVE = 8; |
| private static final int FLAG_HOVER = 2; |
| private static final int FLAG_PAST_THRESHOLD = 1; |
| private static final int FLAG_UNLOAD = 4; |
| { |
| setFlag(FLAG_UNLOAD, true); |
| } |
| |
| /** |
| * The highest-bit flag being used. |
| */ |
| protected static final int MAX_FLAG = 8; |
| |
| /** |
| * The maximum state flag defined by this class |
| */ |
| protected static final int MAX_STATE = 32; |
| |
| /** |
| * constant used for mouse button 1. |
| * |
| * @deprecated Use {@link SWT#BUTTON1} instead. |
| */ |
| protected static final int MOUSE_BUTTON1 = SWT.BUTTON1; |
| /** |
| * constant used for mouse button 2. |
| * |
| * @deprecated Use {@link SWT#BUTTON2} instead. |
| */ |
| protected static final int MOUSE_BUTTON2 = SWT.BUTTON2; |
| /** |
| * constant used for mouse button 3. |
| * |
| * @deprecated Use {@link SWT#BUTTON3} instead. |
| */ |
| protected static final int MOUSE_BUTTON3 = SWT.BUTTON3; |
| /** |
| * constant used to indicate any of the mouse buttons. |
| * |
| * @deprecated Use {@link SWT#BUTTON_MASK} instead. |
| */ |
| protected static final int MOUSE_BUTTON_ANY = SWT.BUTTON_MASK; |
| |
| /** |
| * The state indicating that the keyboard is being used to perform a drag |
| * that is normally done using the mouse. |
| */ |
| protected static final int STATE_ACCESSIBLE_DRAG = 16; |
| |
| /** |
| * The state indicating that a keyboard drag is in progress. The threshold |
| * for keyboard drags is non-existent, so this state would be entered very |
| * quickly. |
| */ |
| protected static final int STATE_ACCESSIBLE_DRAG_IN_PROGRESS = 32; |
| |
| /** |
| * The state indicating that one or more buttons are pressed, but the user |
| * has not moved past the drag threshold. Many tools will do nothing during |
| * this state but wait until {@link #STATE_DRAG_IN_PROGRESS} is entered. |
| */ |
| protected static final int STATE_DRAG = 2; |
| |
| /** |
| * The state indicating that the drag detection theshold has been passed, |
| * and a drag is in progress. |
| */ |
| protected static final int STATE_DRAG_IN_PROGRESS = 4; |
| |
| /** |
| * The first state that a tool is in. The tool will generally be in this |
| * state immediately following {@link #activate()}. |
| */ |
| protected static final int STATE_INITIAL = 1; |
| |
| /** |
| * The state indicating that an input event has invalidated the interaction. |
| * For example, during a mouse drag, pressing additional mouse button might |
| * invalidate the drag. |
| */ |
| protected static final int STATE_INVALID = 8; |
| |
| /** |
| * The final state for a tool to be in. Once a tool reaches this state, it |
| * will not change states until it is activated() again. |
| */ |
| protected static final int STATE_TERMINAL = 1 << 30; |
| |
| /** |
| * Key modifier for ignoring snap while dragging. It's CTRL on Mac, and ALT |
| * on all other platforms. |
| */ |
| static final int MODIFIER_NO_SNAPPING; |
| |
| static { |
| if (Platform.OS_MACOSX.equals(Platform.getOS())) { |
| MODIFIER_NO_SNAPPING = SWT.CTRL; |
| } else { |
| MODIFIER_NO_SNAPPING = SWT.ALT; |
| } |
| } |
| |
| private long accessibleBegin; |
| |
| private int accessibleStep; |
| private Command command; |
| |
| private CommandStackEventListener commandStackListener = new CommandStackEventListener() { |
| public void stackChanged(CommandStackEvent event) { |
| if (event.isPreChangeEvent()) |
| handleCommandStackChanged(); |
| } |
| }; |
| private Input current; |
| private EditPartViewer currentViewer; |
| private Cursor defaultCursor, disabledCursor; |
| private EditDomain domain; |
| private List operationSet; |
| private int startX, startY, state; |
| |
| boolean acceptAbort(KeyEvent e) { |
| return e.character == SWT.ESC; |
| } |
| |
| /** |
| * Returns true if the event corresponds to an arrow key with the |
| * appropriate modifiers and if the system is in a state where the arrow key |
| * should be accepted. |
| * |
| * @param e |
| * the key event |
| * @return true if the arrow key should be accepted by this tool |
| * @since 3.4 |
| */ |
| protected boolean acceptArrowKey(KeyEvent e) { |
| int key = e.keyCode; |
| if (!(isInState(STATE_INITIAL | STATE_ACCESSIBLE_DRAG |
| | STATE_ACCESSIBLE_DRAG_IN_PROGRESS))) |
| return false; |
| return (key == SWT.ARROW_UP) || (key == SWT.ARROW_RIGHT) |
| || (key == SWT.ARROW_DOWN) || (key == SWT.ARROW_LEFT); |
| } |
| |
| boolean acceptDragCommit(KeyEvent e) { |
| return isInState(STATE_ACCESSIBLE_DRAG_IN_PROGRESS) |
| && e.character == 13; |
| } |
| |
| int accGetStep() { |
| return accessibleStep; |
| } |
| |
| void accStepIncrement() { |
| if (accessibleBegin == -1) { |
| accessibleBegin = new Date().getTime(); |
| accessibleStep = 1; |
| } else { |
| accessibleStep = 4; |
| long elapsed = new Date().getTime() - accessibleBegin; |
| if (elapsed > 1000) |
| accessibleStep = Math.min(16, (int) (elapsed / 150)); |
| } |
| } |
| |
| void accStepReset() { |
| accessibleBegin = -1; |
| } |
| |
| /** |
| * Activates the tool. Any initialization should be performed here. This |
| * method is called when a tool is selected. |
| * |
| * @see #deactivate() |
| */ |
| public void activate() { |
| resetFlags(); |
| accessibleBegin = -1; |
| getCurrentInput().verifyMouseButtons = true; |
| setState(STATE_INITIAL); |
| setFlag(FLAG_ACTIVE, true); |
| getDomain().getCommandStack().addCommandStackEventListener( |
| commandStackListener); |
| } |
| |
| /** |
| * Convenience method to add the given figure to the feedback layer. |
| * |
| * @param figure |
| * the feedback being added |
| */ |
| protected void addFeedback(IFigure figure) { |
| LayerManager lm = (LayerManager) getCurrentViewer() |
| .getEditPartRegistry().get(LayerManager.ID); |
| if (lm == null) |
| return; |
| lm.getLayer(LayerConstants.FEEDBACK_LAYER).add(figure); |
| } |
| |
| /** |
| * This method is invoked from {@link #setProperties(Map)}. Sub-classes can |
| * override to add support for more properties. This method should fail |
| * silently in case of any error. |
| * <p> |
| * AbstractTool uses introspection to match any keys with properties. For |
| * instance, the key "defaultCursor" would lead to the invocation of |
| * {@link #setDefaultCursor(Cursor)} with the provided value. |
| * |
| * @param key |
| * the key; may be <code>null</code> |
| * @param value |
| * the new value |
| * @since 3.1 |
| * @see #setProperties(Map) |
| */ |
| protected void applyProperty(Object key, Object value) { |
| if (PROPERTY_UNLOAD_WHEN_FINISHED.equals(key)) { |
| if (value instanceof Boolean) |
| setUnloadWhenFinished(((Boolean) value).booleanValue()); |
| return; |
| } |
| |
| if (!(key instanceof String)) |
| return; |
| |
| try { |
| PropertyDescriptor[] descriptors = Introspector.getBeanInfo( |
| getClass(), Introspector.IGNORE_ALL_BEANINFO) |
| .getPropertyDescriptors(); |
| PropertyDescriptor property = null; |
| for (int i = 0; i < descriptors.length; i++) { |
| if (descriptors[i].getName().equals(key)) { |
| property = descriptors[i]; |
| break; |
| } |
| } |
| if (property != null) { |
| Method setter = property.getWriteMethod(); |
| // setter.setAccessible(true); |
| setter.invoke(this, new Object[] { value }); |
| } |
| } catch (IntrospectionException ie) { |
| } catch (IllegalAccessException iae) { |
| } catch (InvocationTargetException ite) { |
| } catch (SecurityException se) { |
| } |
| } |
| |
| /** |
| * Returns the appropriate cursor for the tools current state. If the tool |
| * is in its terminal state, <code>null</code> is returned. Otherwise, |
| * either the default or disabled cursor is returned, based on the existence |
| * of a current command, and whether that current command is executable. |
| * <P> |
| * Subclasses may override or extend this method to calculate the |
| * appropriate cursor based on other conditions. |
| * |
| * @see #getDefaultCursor() |
| * @see #getDisabledCursor() |
| * @see #getCurrentCommand() |
| * @return <code>null</code> or a cursor to be displayed. |
| */ |
| protected Cursor calculateCursor() { |
| if (isInState(STATE_TERMINAL)) |
| return null; |
| Command command = getCurrentCommand(); |
| if (command == null || !command.canExecute()) |
| return getDisabledCursor(); |
| return getDefaultCursor(); |
| } |
| |
| /** |
| * Added for compatibility. {@link DragTracker#commitDrag()} was added for |
| * accessibility reasons. Since all tool implementations must inherit from |
| * this base class, then implementing this method here avoids breaking |
| * subclasses that implemented the {@link DragTracker} interface. |
| */ |
| public void commitDrag() { |
| } |
| |
| /** |
| * Returns a new List of editparts that this tool is operating on. This |
| * method is called once during {@link #getOperationSet()}, and its result |
| * is cached. |
| * <P> |
| * By default, the operations set is the current viewer's entire selection. |
| * Subclasses may override this method to filter or alter the operation set |
| * as necessary. |
| * |
| * @return a list of editparts being operated on |
| */ |
| protected List createOperationSet() { |
| return new ArrayList(getCurrentViewer().getSelectedEditParts()); |
| } |
| |
| /** |
| * Deactivates the tool. This method is called whenever the user switches to |
| * another tool. Use this method to do some clean-up when the tool is |
| * switched. The abstract tool allows cursors for viewers to be changed. |
| * When the tool is deactivated it must revert to normal the cursor of the |
| * last tool it changed. |
| * |
| * @see #activate() |
| */ |
| public void deactivate() { |
| setFlag(FLAG_ACTIVE, false); |
| setViewer(null); |
| setCurrentCommand(null); |
| setState(STATE_TERMINAL); |
| operationSet = null; |
| current = null; |
| getDomain().getCommandStack().removeCommandStackEventListener( |
| commandStackListener); |
| } |
| |
| /** |
| * Prints a string in the GEF Debug console if the Tools debug option is |
| * selected. |
| * |
| * @param message |
| * a message for the debug trace tool |
| * @deprecated |
| */ |
| protected void debug(String message) { |
| } |
| |
| /** |
| * Executes the given command on the command stack. |
| * |
| * @since 3.1 |
| * @param command |
| * the command to execute |
| */ |
| protected void executeCommand(Command command) { |
| getDomain().getCommandStack().removeCommandStackEventListener( |
| commandStackListener); |
| try { |
| getDomain().getCommandStack().execute(command); |
| } finally { |
| getDomain().getCommandStack().addCommandStackEventListener( |
| commandStackListener); |
| } |
| } |
| |
| /** |
| * Execute the currently active command. |
| */ |
| protected void executeCurrentCommand() { |
| Command curCommand = getCurrentCommand(); |
| if (curCommand != null && curCommand.canExecute()) |
| executeCommand(curCommand); |
| setCurrentCommand(null); |
| } |
| |
| /** |
| * Called when a viewer that the editor controls gains focus. |
| * |
| * @param event |
| * The SWT focus event |
| * @param viewer |
| * The viewer that the focus event is over. |
| */ |
| public void focusGained(FocusEvent event, EditPartViewer viewer) { |
| setViewer(viewer); |
| handleFocusGained(); |
| } |
| |
| /** |
| * Called when a viewer that the editor controls loses focus. |
| * |
| * @param event |
| * The SWT focus event |
| * @param viewer |
| * The viewer that the focus event is over. |
| */ |
| public void focusLost(FocusEvent event, EditPartViewer viewer) { |
| setViewer(viewer); |
| handleFocusLost(); |
| } |
| |
| /** |
| * Returns a new, updated command based on the tool's current properties. |
| * The default implementation returns an unexecutable command. Some tools do |
| * not work commands and the model, but simply change the viewer's state in |
| * some way. |
| * |
| * @return a newly obtained command |
| */ |
| protected Command getCommand() { |
| return org.eclipse.gef.commands.UnexecutableCommand.INSTANCE; |
| } |
| |
| /** |
| * Returns the identifier of the command that is being sought. This name is |
| * also the named that will be logged in the debug view. |
| * |
| * @return the identifier for the command |
| */ |
| protected abstract String getCommandName(); |
| |
| /** |
| * Returns the currently cached command. |
| * |
| * @return the current command |
| * @see #setCurrentCommand(Command) |
| */ |
| protected Command getCurrentCommand() { |
| return command; |
| } |
| |
| /** |
| * Returns the input object encapsulating the current mouse and keyboard |
| * state. |
| * |
| * @return the current input |
| */ |
| protected Input getCurrentInput() { |
| if (current == null) |
| current = new Input(); |
| return current; |
| } |
| |
| /** |
| * Return the viewer that the tool is currently receiving input from, or |
| * <code>null</code>. The last viewer to dispatch an event is defined as the |
| * current viewer. Current viewer is automatically updated as events are |
| * received, and is set to <code>null</code> on <code>deactivate()</code>. |
| * |
| * @return the current viewer |
| */ |
| protected EditPartViewer getCurrentViewer() { |
| return currentViewer; |
| } |
| |
| /** |
| * Returns the debug name for this tool. |
| * |
| * @return the debug name |
| */ |
| protected String getDebugName() { |
| return getClass().getName(); |
| } |
| |
| /** |
| * Returns a String representation of the given state for debug purposes. |
| * |
| * @param state |
| * the state |
| * @return the string for the given state |
| */ |
| protected String getDebugNameForState(int state) { |
| switch (state) { |
| case STATE_INITIAL: |
| return "Initial State";//$NON-NLS-1$ |
| case STATE_DRAG: |
| return "Drag State";//$NON-NLS-1$ |
| case STATE_DRAG_IN_PROGRESS: |
| return "Drag In Progress State";//$NON-NLS-1$ |
| case STATE_INVALID: |
| return "Invalid State"; //$NON-NLS-1$ |
| case STATE_TERMINAL: |
| return "Terminal State"; //$NON-NLS-1$ |
| case STATE_ACCESSIBLE_DRAG: |
| return "Accessible Drag"; //$NON-NLS-1$ |
| case STATE_ACCESSIBLE_DRAG_IN_PROGRESS: |
| return "Accessible Drag In Progress"; //$NON-NLS-1$ |
| } |
| return "Unknown state:";//$NON-NLS-1$ |
| } |
| |
| /** |
| * Returns the cursor used under normal conditions. |
| * |
| * @see #setDefaultCursor(Cursor) |
| * @return the default cursor |
| */ |
| protected Cursor getDefaultCursor() { |
| return defaultCursor; |
| } |
| |
| /** |
| * Returns the cursor used under abnormal conditions. |
| * |
| * @see #calculateCursor() |
| * @see #setDisabledCursor(Cursor) |
| * @return the disabled cursor |
| */ |
| protected Cursor getDisabledCursor() { |
| if (disabledCursor != null) |
| return disabledCursor; |
| return getDefaultCursor(); |
| } |
| |
| /** |
| * Returns the EditDomain. A tool is told its EditDomain when it becomes |
| * active. A tool may need to know its edit domain prior to receiving any |
| * events from any of that domain's viewers. |
| * |
| * @return the editdomain |
| */ |
| protected EditDomain getDomain() { |
| return domain; |
| } |
| |
| /** |
| * Return the number of pixels that the mouse has been moved since that drag |
| * was started. The drag start is determined by where the mouse button was |
| * first pressed. |
| * |
| * @see #getStartLocation() |
| * @return the drag delta |
| */ |
| protected Dimension getDragMoveDelta() { |
| return getLocation().getDifference(getStartLocation()); |
| } |
| |
| /** |
| * Returns the current x, y position of the mouse cursor. |
| * |
| * @return the mouse location |
| */ |
| protected Point getLocation() { |
| return new Point(getCurrentInput().getMouseLocation()); |
| } |
| |
| /** |
| * Lazily creates and returns the list of editparts on which the tool |
| * operates. The list is initially <code>null</code>, in which case |
| * {@link #createOperationSet()} is called, and its results cached until the |
| * tool is deactivated. |
| * |
| * @return the operation set. |
| */ |
| protected List getOperationSet() { |
| if (operationSet == null) |
| operationSet = createOperationSet(); |
| return operationSet; |
| } |
| |
| /** |
| * Returns the starting mouse location for the current tool operation. This |
| * is typically the mouse location where the user first pressed a mouse |
| * button. This is important for tools that interpret mouse drags. |
| * |
| * @return the start location |
| */ |
| protected Point getStartLocation() { |
| return new Point(startX, startY); |
| } |
| |
| /** |
| * Returns the tool's current state. |
| * |
| * @return the current state |
| */ |
| protected int getState() { |
| return state; |
| } |
| |
| /** |
| * Called when the mouse button has been pressed. By default, nothing |
| * happens and <code>false</code> is returned. Subclasses may override this |
| * method to interpret the meaning of a mouse down. Returning |
| * <code>true</code> indicates that the button down was handled in some way. |
| * |
| * @param button |
| * which button went down |
| * @return <code>true</code> if the buttonDown was handled |
| */ |
| protected boolean handleButtonDown(int button) { |
| return false; |
| } |
| |
| /** |
| * Called when the mouse button has been released. By default, nothing |
| * happens and <code>false</code> is returned. Subclasses may override this |
| * method to interpret the mouse up. Returning <code>true</code> indicates |
| * that the mouse up was handled in some way. |
| * |
| * @see #mouseUp(MouseEvent, EditPartViewer) |
| * @param button |
| * the button being released |
| * @return <code>true</code> if the button up was handled |
| */ |
| protected boolean handleButtonUp(int button) { |
| return false; |
| } |
| |
| /** |
| * Called when the command stack has changed, for instance, when a delete or |
| * undo command has been executed. By default, state is set to |
| * <code>STATE_INVALID</code> and handleInvalidInput is called. Subclasses |
| * may override this method to change what happens when the command stack |
| * changes. Returning <code>true</code> indicates that the change was |
| * handled in some way. |
| * |
| * @return <code>true</code> if the change was handled in some way |
| */ |
| protected boolean handleCommandStackChanged() { |
| if (!isInState(STATE_INITIAL | STATE_INVALID)) { |
| setState(STATE_INVALID); |
| handleInvalidInput(); |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Called when a mouse double-click occurs. By default, nothing happens and |
| * <code>false</code> is returned. Subclasses may override this method to |
| * interpret double-clicks. Returning <code>true</code> indicates that the |
| * event was handled in some way. |
| * |
| * @param button |
| * which button was double-clicked |
| * @return <code>true</code> if the event was handled |
| * @see #mouseDoubleClick(MouseEvent, EditPartViewer) |
| */ |
| protected boolean handleDoubleClick(int button) { |
| return false; |
| } |
| |
| /** |
| * Called whenever the mouse is being dragged. This method continues to be |
| * called even once {@link #handleDragInProgress()} starts getting called. |
| * By default, nothing happens, and <code>false</code> is returned. |
| * Subclasses may override this method to interpret a drag. Returning |
| * <code>true</code> indicates that the drag was handled in some way. |
| * |
| * @return <code>true</code> if the drag is handled |
| * @see #mouseDrag(MouseEvent, EditPartViewer) |
| */ |
| protected boolean handleDrag() { |
| return false; |
| } |
| |
| /** |
| * Called whenever a mouse is being dragged and the drag threshold has been |
| * exceeded. Prior to the drag threshold being exceeded, only |
| * {@link #handleDrag()} is called. This method gets called repeatedly for |
| * every mouse move during the drag. By default, nothing happens and |
| * <code>false</code> is returned. Subclasses may override this method to |
| * interpret the drag. Returning <code>true</code> indicates that the drag |
| * was handled. |
| * |
| * @see #movedPastThreshold() |
| * @see #mouseDrag(MouseEvent, EditPartViewer) |
| * @return <code>true</code> if the drag was handled |
| */ |
| protected boolean handleDragInProgress() { |
| return false; |
| } |
| |
| /** |
| * Called only one time during a drag when the drag threshold has been |
| * exceeded. By default, nothing happens and <code>false</code> is returned. |
| * Subclasses may override to interpret the drag starting. Returning |
| * <code>true</code> indicates that the event was handled. |
| * |
| * @see #movedPastThreshold() |
| * @see #mouseDrag(MouseEvent, EditPartViewer) |
| * @return true if the drag starting was handled |
| */ |
| protected boolean handleDragStarted() { |
| return false; |
| } |
| |
| /** |
| * Called when the current tool operation is to be completed. In other |
| * words, the "state machine" and has accepted the sequence of input (i.e. |
| * the mouse gesture). By default, the tool will either reactivate itself, |
| * or ask the edit domain to load the default tool. |
| * <P> |
| * Subclasses should extend this method to first do whatever it is that the |
| * tool does, and then call <code>super</code>. |
| * |
| * @see #unloadWhenFinished() |
| */ |
| protected void handleFinished() { |
| if (unloadWhenFinished()) |
| getDomain().loadDefaultTool(); |
| else |
| reactivate(); |
| } |
| |
| /** |
| * Handles high-level processing of a focus gained event. By default, |
| * nothing happens and <code>false</code> is returned. Subclasses may |
| * override this method to interpret the focus gained event. Return |
| * <code>true</code> to indicate that the event was processed. |
| * |
| * @see #focusGained(FocusEvent, EditPartViewer) |
| * @return <code>true</code> if the event was handled |
| */ |
| protected boolean handleFocusGained() { |
| return false; |
| } |
| |
| /** |
| * Handles high-level processing of a focus lost event. By default, nothing |
| * happens and <code>false</code> is returned. Subclasses may override this |
| * method to interpret the focus lost event. Return <code>true</code> to |
| * indicate that the event was processed. |
| * |
| * @see #focusLost(FocusEvent, EditPartViewer) |
| * @return <code>true</code> if the event was handled |
| */ |
| protected boolean handleFocusLost() { |
| return false; |
| } |
| |
| /** |
| * Handles high-level processing of a mouse hover event. By default, nothing |
| * happens and <code>false</code> is returned. Subclasses may override this |
| * method to interpret the hover. Return <code>true</code> to indicate that |
| * the hover was handled. |
| * |
| * @see #mouseHover(MouseEvent, EditPartViewer) |
| * @return <code>true</code> if the hover was handled |
| */ |
| protected boolean handleHover() { |
| return false; |
| } |
| |
| /** |
| * Called when invalid input is encountered. The state does not change, so |
| * the caller must set the state to {@link AbstractTool#STATE_INVALID}. |
| * |
| * @return <code>true</code> |
| */ |
| protected boolean handleInvalidInput() { |
| return false; |
| } |
| |
| /** |
| * Handles high-level processing of a key down event. By default, the |
| * KeyEvent is checked to see if it is the ESCAPE key. If so, the domain's |
| * default tool is reloaded, and <code>true</code> is returned. Subclasses |
| * may extend this method to interpret additional key down events. Returns |
| * <code>true</code> if the given key down was handled. |
| * |
| * @see #keyDown(KeyEvent, EditPartViewer) |
| * @param e |
| * the key event |
| * @return <code>true</code> if the key down was handled. |
| */ |
| protected boolean handleKeyDown(KeyEvent e) { |
| if (acceptAbort(e)) { |
| getDomain().loadDefaultTool(); |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Override to process a traverse event. If the event's |
| * {@link KeyEvent#doit doit} field is set to <code>false</code>, the |
| * traversal will be prevented from occurring. Otherwise, a traverse will |
| * occur. |
| * |
| * @param event |
| * the SWT traverse event |
| * @since 3.1 |
| */ |
| protected void handleKeyTraversed(TraverseEvent event) { |
| } |
| |
| /** |
| * Handles high-level processing of a key up event. By default, does nothing |
| * and returns <code>false</code>. Subclasses may extend this method to |
| * process key up events. Returns <code>true</code> if the key up was |
| * processed in some way. |
| * |
| * @see #keyUp(KeyEvent, EditPartViewer) |
| * @param e |
| * the key event |
| * @return <code>true</code> if the event was handled |
| */ |
| protected boolean handleKeyUp(KeyEvent e) { |
| return false; |
| } |
| |
| /** |
| * Handles high-level processing of a mouse move. By default, does nothing |
| * and returns <code>false</code>. Subclasses may extend this method to |
| * process mouse moves. Returns <code>true</code> if the mouse move was |
| * processed. |
| * |
| * @see #mouseMove(MouseEvent, EditPartViewer) |
| * @return <code>true</code> if the mouse move was handled |
| */ |
| protected boolean handleMove() { |
| return false; |
| } |
| |
| /** |
| * Handles when a native drag has ended. By default, does nothing and |
| * returns <code>false</code>. Subclasses may extend this method to process |
| * native drags ending. |
| * |
| * @param event |
| * the drag event |
| * @return <code>true</code> if the native drag finished was handled |
| */ |
| protected boolean handleNativeDragFinished(DragSourceEvent event) { |
| return false; |
| } |
| |
| /** |
| * Handles when a native drag has started. By default, does nothing and |
| * returns <code>false</code>. Subclasses may extend this method to process |
| * native drag starts. |
| * <P> |
| * When a native drag starts, all subsequent mouse events will not be |
| * received, including the mouseUp event. The only event that will be |
| * received is the drag finished event. |
| * |
| * @param event |
| * the drag event |
| * @return <code>true</code> if the native drag start was handled |
| */ |
| protected boolean handleNativeDragStarted(DragSourceEvent event) { |
| return false; |
| } |
| |
| /** |
| * Called when the mouse enters an EditPartViewer. By default, does nothing |
| * and returns <code>false</code>. Subclasses may extend this method to |
| * process the viewer enter. Returns <code>true</code> to indicate if the |
| * viewer entered was process in some way. |
| * |
| * @return <code>true</code> if the viewer entered was handled |
| */ |
| protected boolean handleViewerEntered() { |
| return false; |
| } |
| |
| /** |
| * Called when the mouse exits an EditPartViewer. By default, does nothing |
| * and returns <code>false</code>. Subclasses may extend this method to |
| * process viewer exits. Returns <code>true</code> to indicate if the viewer |
| * exited was process in some way. |
| * |
| * @return <code>true</code> if the viewer exited was handled |
| */ |
| protected boolean handleViewerExited() { |
| return false; |
| } |
| |
| /** |
| * Returns <code>true</code> if the tool is active. |
| * |
| * @return <code>true</code> if active |
| */ |
| protected boolean isActive() { |
| return getFlag(FLAG_ACTIVE); |
| } |
| |
| boolean isCurrentViewerMirrored() { |
| return (getCurrentViewer().getControl().getStyle() & SWT.MIRRORED) != 0; |
| } |
| |
| /** |
| * Returns <code>true</code> if the tool is hovering. |
| * |
| * @return <code>true</code> if hovering |
| */ |
| protected boolean isHoverActive() { |
| return getFlag(FLAG_HOVER); |
| } |
| |
| boolean isInDragInProgress() { |
| return isInState(STATE_DRAG_IN_PROGRESS |
| | STATE_ACCESSIBLE_DRAG_IN_PROGRESS); |
| } |
| |
| /* |
| * Returns <code>true</code> if the current {@link Input} is synchronized |
| * with the current MouseEvent. |
| */ |
| private boolean isInputSynched(MouseEvent event) { |
| Input input = getCurrentInput(); |
| return input.isMouseButtonDown(1) == ((event.stateMask & SWT.BUTTON1) != 0) |
| && input.isMouseButtonDown(2) == ((event.stateMask & SWT.BUTTON2) != 0) |
| && input.isMouseButtonDown(3) == ((event.stateMask & SWT.BUTTON3) != 0) |
| && input.isMouseButtonDown(4) == ((event.stateMask & SWT.BUTTON4) != 0) |
| && input.isMouseButtonDown(5) == ((event.stateMask & SWT.BUTTON5) != 0); |
| } |
| |
| /** |
| * Returns <code>true</code> if the tool is in the given state. |
| * |
| * @param state |
| * the state being queried |
| * @return <code>true</code> if the tool is in the given state |
| */ |
| protected boolean isInState(int state) { |
| return ((getState() & state) != 0); |
| } |
| |
| /** |
| * Default implementation always returns <code>true</code>. Sub-classes may |
| * override. |
| * |
| * @param viewer |
| * the viewer where the event occured |
| * @return <code>true</code> if this tool is interested in events occuring |
| * in the given viewer; <code>false</code> otherwise |
| * @since 3.1 |
| */ |
| protected boolean isViewerImportant(EditPartViewer viewer) { |
| return true; |
| } |
| |
| /** |
| * Receives a KeyDown event for the given viewer. Subclasses wanting to |
| * handle this event should override {@link #handleKeyDown(KeyEvent)}. |
| * |
| * @param evt |
| * the key event |
| * @param viewer |
| * the originating viewer |
| */ |
| public void keyDown(KeyEvent evt, EditPartViewer viewer) { |
| if (!isViewerImportant(viewer)) |
| return; |
| setViewer(viewer); |
| getCurrentInput().setInput(evt); |
| handleKeyDown(evt); |
| } |
| |
| /** |
| * Receives a traversal event for the given viewer. Subclasses wanting to |
| * handle this event should override |
| * {@link #handleKeyTraversed(TraverseEvent)}. |
| * |
| * @param event |
| * the traverse event |
| * @param viewer |
| * the originating viewer |
| */ |
| public void keyTraversed(TraverseEvent event, EditPartViewer viewer) { |
| if (!isViewerImportant(viewer)) |
| return; |
| setViewer(viewer); |
| getCurrentInput().setInput(event); |
| handleKeyTraversed(event); |
| } |
| |
| /** |
| * Receives a KeyUp event for the given viewer. Subclasses wanting to handle |
| * this event should override {@link #handleKeyUp(KeyEvent)}. |
| * |
| * @param evt |
| * the key event |
| * @param viewer |
| * the originating viewer |
| */ |
| public void keyUp(KeyEvent evt, EditPartViewer viewer) { |
| if (!isViewerImportant(viewer)) |
| return; |
| setViewer(viewer); |
| getCurrentInput().setInput(evt); |
| handleKeyUp(evt); |
| } |
| |
| /** |
| * Handles mouse double click events within a viewer. Subclasses wanting to |
| * handle this event should override {@link #handleDoubleClick(int)}. |
| * |
| * @param me |
| * the mouse event |
| * @param viewer |
| * the originating viewer |
| */ |
| public void mouseDoubleClick(MouseEvent me, EditPartViewer viewer) { |
| if (me.button > 5 || !isViewerImportant(viewer)) |
| return; |
| setViewer(viewer); |
| getCurrentInput().setInput(me); |
| |
| handleDoubleClick(me.button); |
| } |
| |
| /** |
| * Handles mouse down events within a viewer. Subclasses wanting to handle |
| * this event should override {@link #handleButtonDown(int)}. |
| * |
| * @param me |
| * the mouse event |
| * @param viewer |
| * the originating viewer |
| */ |
| public void mouseDown(MouseEvent me, EditPartViewer viewer) { |
| if (!isViewerImportant(viewer)) |
| return; |
| setViewer(viewer); |
| |
| getCurrentInput().setInput(me); |
| getCurrentInput().setMouseButton(me.button, true); |
| |
| setStartLocation(new Point(me.x, me.y)); |
| |
| handleButtonDown(me.button); |
| } |
| |
| /** |
| * Handles mouse drag events within a viewer. Subclasses wanting to handle |
| * this event should override {@link #handleDrag()} and/or |
| * {@link #handleDragInProgress()}. |
| * |
| * @param me |
| * the mouse event |
| * @param viewer |
| * the originating viewer |
| */ |
| public void mouseDrag(MouseEvent me, EditPartViewer viewer) { |
| if (!isViewerImportant(viewer)) |
| return; |
| setViewer(viewer); |
| boolean wasDragging = movedPastThreshold(); |
| getCurrentInput().setInput(me); |
| handleDrag(); |
| if (movedPastThreshold()) { |
| if (!wasDragging) |
| handleDragStarted(); |
| handleDragInProgress(); |
| } |
| } |
| |
| /** |
| * Handles mouse hover event. within a viewer. Subclasses wanting to handle |
| * this event should override {@link #handleHover()}. |
| * |
| * @param me |
| * the mouse event |
| * @param viewer |
| * the originating viewer |
| * |
| */ |
| public void mouseHover(MouseEvent me, EditPartViewer viewer) { |
| if (!isViewerImportant(viewer)) |
| return; |
| setViewer(viewer); |
| getCurrentInput().setInput(me); |
| handleHover(); |
| } |
| |
| /** |
| * Handles mouse moves (if the mouse button is up) within a viewer. |
| * Subclasses wanting to handle this event should override |
| * {@link #handleMove()}. |
| * |
| * @param me |
| * the mouse event |
| * @param viewer |
| * the originating viewer |
| */ |
| public void mouseMove(MouseEvent me, EditPartViewer viewer) { |
| if (!isViewerImportant(viewer)) |
| return; |
| setViewer(viewer); |
| if (!isInputSynched(me)) { |
| boolean b1 = getCurrentInput().isMouseButtonDown(1); |
| boolean b2 = getCurrentInput().isMouseButtonDown(2); |
| boolean b3 = getCurrentInput().isMouseButtonDown(3); |
| boolean b4 = getCurrentInput().isMouseButtonDown(4); |
| boolean b5 = getCurrentInput().isMouseButtonDown(5); |
| getCurrentInput().verifyMouseButtons = true; |
| getCurrentInput().setInput(me); |
| if (b1) |
| handleButtonUp(1); |
| if (b2) |
| handleButtonUp(2); |
| if (b3) |
| handleButtonUp(3); |
| if (b4) |
| handleButtonUp(4); |
| if (b5) |
| handleButtonUp(5); |
| if (getDomain().getActiveTool() != this) |
| return; |
| /* |
| * processing one of the buttonUps may have caused the tool to |
| * reactivate itself, which causes the viewer to get nulled-out. If |
| * we are going to call another handleXxx method below, we must set |
| * the viewer again to be paranoid. |
| */ |
| setViewer(viewer); |
| } else |
| getCurrentInput().setInput(me); |
| if (isInState(STATE_ACCESSIBLE_DRAG_IN_PROGRESS)) |
| handleDragInProgress(); |
| else |
| handleMove(); |
| } |
| |
| /** |
| * Handles mouse up within a viewer. Subclasses wanting to handle this event |
| * should override {@link #handleButtonUp(int)}. |
| * |
| * @param me |
| * the mouse event |
| * @param viewer |
| * the originating viewer |
| */ |
| public void mouseUp(MouseEvent me, EditPartViewer viewer) { |
| if (!isViewerImportant(viewer)) |
| return; |
| setViewer(viewer); |
| getCurrentInput().setInput(me); |
| getCurrentInput().setMouseButton(me.button, false); |
| handleButtonUp(me.button); |
| } |
| |
| /** |
| * Handles mouse-wheel scrolling for a viewer. Sub-classes may override as |
| * needed. The default implementation delegates to |
| * {@link #performViewerMouseWheel(Event, EditPartViewer)} IFF the tool is |
| * in the initial state. Mouse-wheel events generated at other times are |
| * ignored. |
| * |
| * @param event |
| * the SWT scroll event |
| * @param viewer |
| * the originating viewer |
| * @see #performViewerMouseWheel(Event, EditPartViewer) |
| */ |
| public void mouseWheelScrolled(Event event, EditPartViewer viewer) { |
| if (isInState(STATE_INITIAL)) |
| performViewerMouseWheel(event, viewer); |
| } |
| |
| /** |
| * Returns <code>true</code> if the threshold has been exceeded during a |
| * mouse drag. |
| * |
| * @return <code>true</code> if the threshold has been exceeded |
| */ |
| protected boolean movedPastThreshold() { |
| if (getFlag(FLAG_PAST_THRESHOLD)) |
| return true; |
| Point start = getStartLocation(), end = getLocation(); |
| if (Math.abs(start.x - end.x) > DRAG_THRESHOLD |
| || Math.abs(start.y - end.y) > DRAG_THRESHOLD) { |
| setFlag(FLAG_PAST_THRESHOLD, true); |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * @see org.eclipse.gef.Tool#nativeDragFinished(DragSourceEvent, |
| * EditPartViewer) |
| */ |
| public void nativeDragFinished(DragSourceEvent event, EditPartViewer viewer) { |
| if (!isViewerImportant(viewer)) |
| return; |
| setViewer(viewer); |
| handleNativeDragFinished(event); |
| } |
| |
| /** |
| * @see org.eclipse.gef.Tool#nativeDragStarted(DragSourceEvent, |
| * EditPartViewer) |
| */ |
| public void nativeDragStarted(DragSourceEvent event, EditPartViewer viewer) { |
| if (!isViewerImportant(viewer)) |
| return; |
| setViewer(viewer); |
| handleNativeDragStarted(event); |
| } |
| |
| /** |
| * Delegates mouse-wheel event handling to registered |
| * {@link MouseWheelHandler MouseWheelHandlers} based on the given Event's |
| * statemask. Does nothing if there are no matching handlers found. |
| * |
| * @param event |
| * the SWT scroll event |
| * @param viewer |
| * the originating viewer |
| * @since 3.1 |
| */ |
| protected void performViewerMouseWheel(Event event, EditPartViewer viewer) { |
| MouseWheelHandler handler = (MouseWheelHandler) viewer |
| .getProperty(MouseWheelHandler.KeyGenerator |
| .getKey(event.stateMask)); |
| if (handler != null) |
| handler.handleMouseWheel(event, viewer); |
| } |
| |
| /** |
| * Places the mouse in the viewer based on the point given. If the point |
| * given is outside the viewer, then the mouse is placed in the location |
| * nearest the given point but within the viewer. |
| * |
| * @param p |
| * the point |
| * @since 3.4 |
| */ |
| protected void placeMouseInViewer(Point p) { |
| if (getCurrentViewer() == null) |
| return; |
| Control c = getCurrentViewer().getControl(); |
| Rectangle rect; |
| if (c instanceof Scrollable) |
| rect = ((Scrollable) c).getClientArea(); |
| else |
| rect = c.getBounds(); |
| if (p.x > rect.x + rect.width - 1) |
| p.x = rect.x + rect.width - 1; |
| else if (p.x < rect.x) |
| p.x = rect.x; |
| if (p.y > rect.y + rect.height - 1) |
| p.y = rect.y + rect.height - 1; |
| else if (p.y < rect.y) |
| p.y = rect.y; |
| org.eclipse.swt.graphics.Point swt = new org.eclipse.swt.graphics.Point( |
| p.x, p.y); |
| swt = c.toDisplay(swt); |
| // UNSUPPORTED - api not supported in RAP |
| // c.getDisplay().setCursorLocation(swt); |
| } |
| |
| /** |
| * Calls <code>deactivate()</code> and then <code>activate()</code>. |
| */ |
| protected void reactivate() { |
| // Fix for Bug# 91448 |
| EditPartViewer viewer = getCurrentViewer(); |
| deactivate(); |
| activate(); |
| if (viewer != null) { |
| Control c = viewer.getControl(); |
| if (c != null && !c.isDisposed() && c.isFocusControl()) |
| setViewer(viewer); |
| } |
| } |
| |
| /** |
| * Sets the cursor being displayed to the appropriate cursor. If the tool is |
| * active, the current cursor being displayed is updated by calling |
| * {@link #calculateCursor()}. |
| */ |
| protected void refreshCursor() { |
| if (isActive()) |
| setCursor(calculateCursor()); |
| } |
| |
| /** |
| * Releases tool capture. |
| * |
| * @see #setToolCapture() |
| */ |
| protected void releaseToolCapture() { |
| getCurrentViewer().setRouteEventsToEditDomain(false); |
| } |
| |
| /** |
| * Convenience method to removes a figure from the feedback layer. |
| * |
| * @param figure |
| * the figure being removed |
| */ |
| protected void removeFeedback(IFigure figure) { |
| LayerManager lm = (LayerManager) getCurrentViewer() |
| .getEditPartRegistry().get(LayerManager.ID); |
| if (lm == null) |
| return; |
| lm.getLayer(LayerConstants.FEEDBACK_LAYER).remove(figure); |
| } |
| |
| /** |
| * Resets all stateful flags to their initial values. Subclasses should |
| * extend this method to reset their own custom flags. |
| */ |
| protected void resetFlags() { |
| setFlag(FLAG_PAST_THRESHOLD, false); |
| setFlag(FLAG_HOVER, false); |
| } |
| |
| /** |
| * Used to cache a command obtained from {@link #getCommand()}. |
| * |
| * @param c |
| * the command |
| * @see #getCurrentCommand() |
| */ |
| protected void setCurrentCommand(Command c) { |
| command = c; |
| refreshCursor(); |
| } |
| |
| /** |
| * Shows the given cursor on the current viewer. |
| * |
| * @param cursor |
| * the cursor to display |
| */ |
| protected void setCursor(Cursor cursor) { |
| if (getCurrentViewer() != null) |
| getCurrentViewer().setCursor(cursor); |
| } |
| |
| /** |
| * Sets the default cursor. |
| * |
| * @param cursor |
| * the cursor |
| * @see #getDefaultCursor() |
| */ |
| public void setDefaultCursor(Cursor cursor) { |
| if (defaultCursor == cursor) |
| return; |
| defaultCursor = cursor; |
| refreshCursor(); |
| } |
| |
| /** |
| * Sets the disabled cursor. |
| * |
| * @param cursor |
| * the cursor |
| * @see #getDisabledCursor() |
| */ |
| public void setDisabledCursor(Cursor cursor) { |
| if (disabledCursor == cursor) |
| return; |
| disabledCursor = cursor; |
| refreshCursor(); |
| } |
| |
| /** |
| * Sets the EditDomain. |
| * |
| * @param domain |
| * the edit domain |
| * @see #getDomain() |
| */ |
| public void setEditDomain(EditDomain domain) { |
| this.domain = domain; |
| } |
| |
| /** |
| * Sets whether the hover flag is true or false. Subclasses which do |
| * something on hover can use this flag to track whether they have received |
| * a hover or not. |
| * |
| * @param value |
| * whether hover is active |
| */ |
| protected void setHoverActive(boolean value) { |
| setFlag(FLAG_HOVER, value); |
| } |
| |
| void setMouseCapture(boolean value) { |
| // UNSUPPORTED - capture api not implemented in RAP |
| // if (getCurrentViewer() != null |
| // && getCurrentViewer().getControl() != null |
| // && !getCurrentViewer().getControl().isDisposed()) |
| // getCurrentViewer().getControl().setCapture(value); |
| } |
| |
| /** |
| * An example is {@link #PROPERTY_UNLOAD_WHEN_FINISHED} -> Boolean. |
| * AbstractTool uses introspection to set properties that are not explicitly |
| * specified. For instance, the key "defaultCursor" will cause |
| * {@link #setDefaultCursor(Cursor)} to be invoked with the given value. |
| * |
| * @see org.eclipse.gef.Tool#setProperties(java.util.Map) |
| */ |
| public void setProperties(Map properties) { |
| if (properties == null) |
| return; |
| Iterator entries = properties.entrySet().iterator(); |
| while (entries.hasNext()) { |
| Entry entry = (Entry) entries.next(); |
| applyProperty(entry.getKey(), entry.getValue()); |
| } |
| } |
| |
| /** |
| * Sets the start mouse location, typically for a drag operation. |
| * |
| * @param p |
| * the start location |
| */ |
| protected void setStartLocation(Point p) { |
| startX = p.x; |
| startY = p.y; |
| } |
| |
| /** |
| * Sets the tools state. |
| * |
| * @param state |
| * the new state |
| */ |
| protected void setState(int state) { |
| this.state = state; |
| } |
| |
| /** |
| * Sets tool capture. When a tool has capture, viewers will make every |
| * effort to send events through the editdomain to the tool. Therefore, the |
| * default handling of some events is bypassed. |
| */ |
| protected void setToolCapture() { |
| getCurrentViewer().setRouteEventsToEditDomain(true); |
| } |
| |
| /** |
| * Setting this to <code>true</code> will cause the tool to be unloaded |
| * after one operation has completed. The default value is <code>true</code> |
| * . The tool is unloaded, and the edit domains default tool will be |
| * activated. |
| * |
| * @param value |
| * whether the tool should be unloaded on completion |
| */ |
| public void setUnloadWhenFinished(boolean value) { |
| setFlag(FLAG_UNLOAD, value); |
| } |
| |
| /** |
| * Sets the active EditPartViewer. The active viewer is the viewer from |
| * which the last event was received. |
| * |
| * @param viewer |
| * the viewer |
| */ |
| public void setViewer(EditPartViewer viewer) { |
| if (viewer == currentViewer) |
| return; |
| |
| setCursor(null); |
| currentViewer = viewer; |
| if (currentViewer != null) { |
| org.eclipse.swt.graphics.Point p = currentViewer.getControl() |
| .toControl(Display.getCurrent().getCursorLocation()); |
| getCurrentInput().setMouseLocation(p.x, p.y); |
| } |
| refreshCursor(); |
| } |
| |
| /** |
| * Returns <code>true</code> if the give state transition succeeds. This is |
| * a "test and set" operation, where the tool is tested to be in the |
| * specified start state, and if so, is set to the given end state. The |
| * method returns the result of the first test. |
| * |
| * @param start |
| * the start state being tested |
| * @param end |
| * the end state |
| * @return <code>true</code> if the state transition is successful |
| */ |
| protected boolean stateTransition(int start, int end) { |
| if ((getState() & start) != 0) { |
| setState(end); |
| return true; |
| } else |
| return false; |
| } |
| |
| /** |
| * Returns <code>true</code> if the tool is set to unload when its current |
| * operation is complete. |
| * |
| * @return <code>true</code> if the tool should be unloaded when finished |
| */ |
| protected final boolean unloadWhenFinished() { |
| return getFlag(FLAG_UNLOAD); |
| } |
| |
| /** |
| * Receives the mouse entered event. Subclasses wanting to handle this event |
| * should override {@link #handleViewerEntered()}. |
| * <p> |
| * FEATURE in SWT: mouseExit comes after mouseEntered on the new control. |
| * Therefore, if the current viewer is not <code>null</code>, it means the |
| * exit has not been sent yet by SWT. To maintain proper ordering, GEF fakes |
| * the exit and calls {@link #handleViewerExited()}. The real exit will then |
| * be ignored. |
| * |
| * @param me |
| * the mouse event |
| * @param viewer |
| * the originating viewer |
| */ |
| public void viewerEntered(MouseEvent me, EditPartViewer viewer) { |
| if (!isViewerImportant(viewer)) |
| return; |
| getCurrentInput().setInput(me); |
| if (getCurrentViewer() != null && getCurrentViewer() != viewer) |
| handleViewerExited(); |
| setViewer(viewer); |
| handleViewerEntered(); |
| } |
| |
| /** |
| * Handles the mouse exited event. Subclasses wanting to handle this event |
| * should override {@link #handleViewerExited()}. |
| * |
| * @param me |
| * the mouse event |
| * @param viewer |
| * the originating viewer |
| */ |
| public void viewerExited(MouseEvent me, EditPartViewer viewer) { |
| /* |
| * FEATURE in SWT. mouseExited comes after mouseEntered. So only call |
| * handle exit if we didn't previously fake it on viewer entered. |
| */ |
| if (viewer == getCurrentViewer()) { |
| getCurrentInput().setInput(me); |
| handleViewerExited(); |
| setViewer(null); |
| } |
| } |
| |
| /** |
| * Allows the user to access mouse and keyboard input. |
| */ |
| public static class Input extends org.eclipse.gef.util.FlagSupport { |
| int modifiers; |
| Point mouse = new Point(); |
| boolean verifyMouseButtons; |
| |
| /** |
| * Returns the event modifiers. Modifiers are defined in |
| * {@link MouseEvent#stateMask}, and include things like the mouse |
| * buttons and keyboard modifier keys. |
| * |
| * @return the event modifiers |
| */ |
| protected int getModifiers() { |
| return modifiers; |
| } |
| |
| /** |
| * Returns the current location of the mouse. |
| * |
| * @return the mouse location |
| */ |
| public Point getMouseLocation() { |
| return mouse; |
| } |
| |
| /** |
| * Returns <code>true</code> if the ALT key is pressed. |
| * |
| * @return <code>true</code> if the ALT key is pressed |
| */ |
| public boolean isAltKeyDown() { |
| return (modifiers & SWT.ALT) != 0; |
| } |
| |
| /** |
| * Returns <code>true</code> if any of the mouse buttons are pressed. |
| * |
| * @return <code>true</code> if any of the mouse buttons are pressed |
| */ |
| public boolean isAnyButtonDown() { |
| return getFlag(2 | 4 | 8 | 16 | 32); |
| } |
| |
| /** |
| * Returns <code>true</code> if the CTRL key is pressed. |
| * |
| * @return <code>true</code> of CTRL pressed |
| */ |
| public boolean isControlKeyDown() { |
| return (modifiers & SWT.CONTROL) != 0; |
| } |
| |
| /** |
| * Returns <code>true</code> if any of the given mod keys are pressed. |
| * |
| * @param mod |
| * SWT.MOD1, SWT.MOD2, SWT.MOD3, SWT.MOD4 or any combination |
| * thereof |
| * @return <code>true</code> if the given mod key is pressed |
| * @since 3.1 |
| */ |
| public boolean isModKeyDown(int mod) { |
| return (modifiers & mod) != 0; |
| } |
| |
| /** |
| * Returns <code>true</code> if the specified button is down. |
| * |
| * @param which |
| * which button |
| * @return <code>true</code> if the button is down |
| */ |
| public boolean isMouseButtonDown(int which) { |
| return getFlag(1 << which); |
| } |
| |
| /** |
| * Returns <code>true</code> if the SHIFT key is pressed. |
| * |
| * @return <code>true</code> if SHIFT pressed |
| */ |
| public boolean isShiftKeyDown() { |
| return (modifiers & SWT.SHIFT) != 0; |
| } |
| |
| /** |
| * Sets the keyboard input based on the KeyEvent. |
| * |
| * @param ke |
| * the key event providing the input |
| */ |
| public void setInput(KeyEvent ke) { |
| modifiers = ke.stateMask; |
| } |
| |
| /** |
| * Sets the mouse and keyboard input based on the MouseEvent. |
| * |
| * @param me |
| * the mouse event providing the input |
| */ |
| public void setInput(MouseEvent me) { |
| setMouseLocation(me.x, me.y); |
| modifiers = me.stateMask; |
| if (verifyMouseButtons) { |
| setMouseButton(1, (modifiers & SWT.BUTTON1) != 0); |
| setMouseButton(2, (modifiers & SWT.BUTTON2) != 0); |
| setMouseButton(3, (modifiers & SWT.BUTTON3) != 0); |
| setMouseButton(4, (modifiers & SWT.BUTTON4) != 0); |
| setMouseButton(5, (modifiers & SWT.BUTTON5) != 0); |
| verifyMouseButtons = false; |
| } |
| } |
| |
| /** |
| * Sets mouse button # <code>which</code> to be pressed if |
| * <code>state</code> is true. |
| * |
| * @param which |
| * which button |
| * @param state |
| * <code>true</code> if button down |
| */ |
| public void setMouseButton(int which, boolean state) { |
| setFlag(1 << which, state); |
| } |
| |
| /** |
| * Sets the current location of the mouse |
| * |
| * @param x |
| * x location |
| * @param y |
| * y location |
| * @since 3.4 |
| */ |
| public void setMouseLocation(int x, int y) { |
| mouse.setLocation(x, y); |
| } |
| } |
| |
| } |