/*******************************************************************************
 * 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.SWT;
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.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;

		// place the mouse cursor at the calculated position within the viewer
		org.eclipse.swt.graphics.Point cursorLocation = new org.eclipse.swt.graphics.Point(
				p.x, p.y);
		cursorLocation = c.toDisplay(cursorLocation);
		// calling Display#setCursorLocation(Point) will cause an SWT.MouseMove
		// event to be dispatched as a result, so that mouseMove(MouseEvent,
		// EditPartViewer) will be triggered as a result, which will react to
		// the movement by delegating to handleMove() or handleDragInProgress().
		c.getDisplay().setCursorLocation(cursorLocation);
	}

	/**
	 * 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) {
		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);
		}
	}

}
