| /******************************************************************************* |
| * Copyright (c) 2000, 2005 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.draw2d; |
| |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.accessibility.AccessibleControlEvent; |
| import org.eclipse.swt.accessibility.AccessibleControlListener; |
| import org.eclipse.swt.accessibility.AccessibleEvent; |
| import org.eclipse.swt.accessibility.AccessibleListener; |
| import org.eclipse.swt.events.DisposeEvent; |
| import org.eclipse.swt.events.TraverseEvent; |
| import org.eclipse.swt.graphics.Cursor; |
| import org.eclipse.swt.widgets.Control; |
| |
| /** |
| * The SWTEventDispatcher provides draw2d with the ability to dispatch SWT Events. The |
| * {@link org.eclipse.draw2d.LightweightSystem} adds SWT event listeners on its Canvas. |
| * When the Canvas receives an SWT event, it calls the appropriate dispatcher method in |
| * SWTEventDispatcher. |
| */ |
| public class SWTEventDispatcher |
| extends EventDispatcher |
| { |
| |
| /** |
| * Used to tell if any button is pressed without regard to the specific button. |
| * @deprecated Use {@link SWT#BUTTON_MASK} instead. |
| */ |
| protected static final int ANY_BUTTON = SWT.BUTTON_MASK; |
| |
| private boolean figureTraverse = true; |
| |
| private boolean captured; |
| private IFigure root; |
| private IFigure mouseTarget; |
| private IFigure cursorTarget; |
| private IFigure focusOwner; |
| private IFigure hoverSource; |
| |
| private MouseEvent currentEvent; |
| private Cursor cursor; |
| /** The control this dispatcher is listening to. */ |
| protected org.eclipse.swt.widgets.Control control; |
| |
| private ToolTipHelper toolTipHelper; |
| private FocusTraverseManager focusManager = new FocusTraverseManager(); |
| |
| /** |
| * Implements {@link EventDispatcher.AccessibilityDispatcher} but |
| * does nothing in the implementation. |
| */ |
| protected class FigureAccessibilityDispatcher |
| extends AccessibilityDispatcher |
| { |
| /** @see AccessibleControlListener#getChildAtPoint(AccessibleControlEvent) */ |
| public void getChildAtPoint(AccessibleControlEvent e) { } |
| /** @see AccessibleControlListener#getChildCount(AccessibleControlEvent) */ |
| public void getChildCount(AccessibleControlEvent e) { } |
| /** @see AccessibleControlListener#getChildren(AccessibleControlEvent) */ |
| public void getChildren(AccessibleControlEvent e) { } |
| /** @see AccessibleControlListener#getDefaultAction(AccessibleControlEvent) */ |
| public void getDefaultAction(AccessibleControlEvent e) { } |
| /** @see AccessibleListener#getDescription(AccessibleEvent) */ |
| public void getDescription(AccessibleEvent e) { } |
| /** @see AccessibleControlListener#getFocus(AccessibleControlEvent) */ |
| public void getFocus(AccessibleControlEvent e) { } |
| /** @see AccessibleListener#getHelp(AccessibleEvent) */ |
| public void getHelp(AccessibleEvent e) { } |
| /** @see AccessibleListener#getKeyboardShortcut(AccessibleEvent) */ |
| public void getKeyboardShortcut(AccessibleEvent e) { } |
| /** @see AccessibleControlListener#getLocation(AccessibleControlEvent) */ |
| public void getLocation(AccessibleControlEvent e) { } |
| /** @see AccessibleListener#getName(AccessibleEvent) */ |
| public void getName(AccessibleEvent e) { } |
| /** @see AccessibleControlListener#getRole(AccessibleControlEvent) */ |
| public void getRole(AccessibleControlEvent e) { } |
| /** @see AccessibleControlListener#getSelection(AccessibleControlEvent) */ |
| public void getSelection(AccessibleControlEvent e) { } |
| /** @see AccessibleControlListener#getState(AccessibleControlEvent) */ |
| public void getState(AccessibleControlEvent e) { } |
| /** @see AccessibleControlListener#getValue(AccessibleControlEvent) */ |
| public void getValue(AccessibleControlEvent e) { } |
| } |
| |
| /** |
| * @see EventDispatcher#dispatchFocusGained(org.eclipse.swt.events.FocusEvent) |
| */ |
| public void dispatchFocusGained(org.eclipse.swt.events.FocusEvent e) { |
| IFigure currentFocusOwner = getFocusTraverseManager().getCurrentFocusOwner(); |
| |
| /* |
| * Upon focus gained, if there is no current focus owner, |
| * set focus on first focusable child. |
| */ |
| if (currentFocusOwner == null) |
| currentFocusOwner = |
| getFocusTraverseManager().getNextFocusableFigure(root, focusOwner); |
| setFocus(currentFocusOwner); |
| } |
| |
| /** |
| * @see EventDispatcher#dispatchFocusLost(org.eclipse.swt.events.FocusEvent) |
| */ |
| public void dispatchFocusLost(org.eclipse.swt.events.FocusEvent e) { |
| setFocus(null); |
| } |
| |
| /** |
| * @see EventDispatcher#dispatchKeyPressed(org.eclipse.swt.events.KeyEvent) |
| */ |
| public void dispatchKeyPressed(org.eclipse.swt.events.KeyEvent e) { |
| if (focusOwner != null) { |
| KeyEvent event = new KeyEvent(this, focusOwner, e); |
| focusOwner.handleKeyPressed(event); |
| } |
| } |
| |
| /** |
| * @see EventDispatcher#dispatchKeyReleased(org.eclipse.swt.events.KeyEvent) |
| */ |
| public void dispatchKeyReleased(org.eclipse.swt.events.KeyEvent e) { |
| if (focusOwner != null) { |
| KeyEvent event = new KeyEvent(this, focusOwner, e); |
| focusOwner.handleKeyReleased(event); |
| } |
| } |
| |
| /** |
| * @see EventDispatcher#dispatchKeyTraversed(TraverseEvent) |
| */ |
| public void dispatchKeyTraversed(TraverseEvent e) { |
| if (!figureTraverse) |
| return; |
| IFigure nextFigure = null; |
| |
| if (e.detail == SWT.TRAVERSE_TAB_NEXT) |
| nextFigure = getFocusTraverseManager().getNextFocusableFigure(root, focusOwner); |
| else if (e.detail == SWT.TRAVERSE_TAB_PREVIOUS) |
| nextFigure = |
| getFocusTraverseManager().getPreviousFocusableFigure(root, focusOwner); |
| |
| if (nextFigure != null) { |
| e.doit = false; |
| setFocus(nextFigure); |
| } |
| } |
| |
| /** |
| * @see EventDispatcher#dispatchMouseHover(org.eclipse.swt.events.MouseEvent) |
| */ |
| public void dispatchMouseHover(org.eclipse.swt.events.MouseEvent me) { |
| receive(me); |
| if (mouseTarget != null) |
| mouseTarget.handleMouseHover(currentEvent); |
| /* |
| * Check Tooltip source. |
| * Get Tooltip source's Figure. |
| * Set that tooltip as the lws contents on the helper. |
| */ |
| if (hoverSource != null) { |
| toolTipHelper = getToolTipHelper(); |
| IFigure tip = hoverSource.getToolTip(); |
| Control control = (Control)me.getSource(); |
| org.eclipse.swt.graphics.Point absolute; |
| absolute = control.toDisplay(new org.eclipse.swt.graphics.Point(me.x, me.y)); |
| toolTipHelper.displayToolTipNear(hoverSource, tip, absolute.x, absolute.y); |
| } |
| } |
| |
| /** |
| * @see EventDispatcher#dispatchMouseDoubleClicked(org.eclipse.swt.events.MouseEvent) |
| */ |
| public void dispatchMouseDoubleClicked(org.eclipse.swt.events.MouseEvent me) { |
| receive(me); |
| if (mouseTarget != null) |
| mouseTarget.handleMouseDoubleClicked(currentEvent); |
| } |
| |
| /** |
| * @see EventDispatcher#dispatchMouseEntered(org.eclipse.swt.events.MouseEvent) |
| */ |
| public void dispatchMouseEntered(org.eclipse.swt.events.MouseEvent me) { |
| receive(me); |
| } |
| |
| /** |
| * @see EventDispatcher#dispatchMouseExited(org.eclipse.swt.events.MouseEvent) |
| */ |
| public void dispatchMouseExited(org.eclipse.swt.events.MouseEvent me) { |
| setHoverSource(null, me); |
| if (mouseTarget != null) { |
| currentEvent = |
| new MouseEvent(me.x, me.y, this, mouseTarget, me.button, me.stateMask); |
| mouseTarget.handleMouseExited(currentEvent); |
| releaseCapture(); |
| mouseTarget = null; |
| } |
| } |
| |
| /** |
| * @see EventDispatcher#dispatchMousePressed(org.eclipse.swt.events.MouseEvent) |
| */ |
| public void dispatchMousePressed(org.eclipse.swt.events.MouseEvent me) { |
| receive(me); |
| if (mouseTarget != null) { |
| mouseTarget.handleMousePressed(currentEvent); |
| if (currentEvent.isConsumed()) |
| setCapture(mouseTarget); |
| } |
| } |
| |
| /** |
| * @see EventDispatcher#dispatchMouseMoved(org.eclipse.swt.events.MouseEvent) |
| */ |
| public void dispatchMouseMoved(org.eclipse.swt.events.MouseEvent me) { |
| receive(me); |
| if (mouseTarget != null) { |
| if ((me.stateMask & SWT.BUTTON_MASK) != 0) |
| mouseTarget.handleMouseDragged(currentEvent); |
| else |
| mouseTarget.handleMouseMoved(currentEvent); |
| } |
| } |
| |
| /** |
| * @see EventDispatcher#dispatchMouseReleased(org.eclipse.swt.events.MouseEvent) |
| */ |
| public void dispatchMouseReleased(org.eclipse.swt.events.MouseEvent me) { |
| receive(me); |
| if (mouseTarget != null) { |
| mouseTarget.handleMouseReleased(currentEvent); |
| } |
| releaseCapture(); |
| receive(me); |
| } |
| |
| /** |
| * @see EventDispatcher#getAccessibilityDispatcher() |
| */ |
| protected AccessibilityDispatcher getAccessibilityDispatcher() { |
| return null; |
| } |
| |
| /** |
| * Returns the current mouse event. |
| * @return the current mouse event |
| */ |
| protected MouseEvent getCurrentEvent() { |
| return currentEvent; |
| } |
| |
| private IFigure getCurrentToolTip() { |
| if (hoverSource != null) |
| return hoverSource.getToolTip(); |
| else |
| return null; |
| } |
| |
| /** |
| * Returns the figure that the cursor is over. |
| * @return the cursor target |
| */ |
| protected IFigure getCursorTarget() { |
| return cursorTarget; |
| } |
| |
| /** |
| * Returns the ToolTipHelper used to display tooltips on hover events. |
| * @return the ToolTipHelper |
| */ |
| protected ToolTipHelper getToolTipHelper() { |
| if (toolTipHelper == null) |
| toolTipHelper = new ToolTipHelper(control); |
| return toolTipHelper; |
| } |
| |
| /** |
| * Returns the FocusTraverseManager which is used to determine which figure will get focus |
| * when a TAB or ALT+TAB key sequence occurs. |
| * @return the FocusTraverseManager |
| */ |
| protected final FocusTraverseManager getFocusTraverseManager() { |
| if (focusManager == null) { |
| focusManager = new FocusTraverseManager(); |
| } |
| return focusManager; |
| } |
| |
| /** |
| * @see EventDispatcher#getFocusOwner() |
| */ |
| /*package*/ IFigure getFocusOwner() { |
| return focusOwner; |
| } |
| |
| /** |
| * Returns the figure that is the target of mouse events. This may not be the figure |
| * beneath the cursor because another figure may have captured the mouse and will continue |
| * to get mouse events until capture is released. |
| * @return the mouse target |
| */ |
| protected IFigure getMouseTarget() { |
| return mouseTarget; |
| } |
| |
| /** |
| * Returns the root figure for this dispatcher. |
| * @return the root figure |
| */ |
| protected IFigure getRoot() { |
| return root; |
| } |
| |
| /** |
| * @see EventDispatcher#isCaptured() |
| */ |
| public boolean isCaptured() { |
| return captured; |
| } |
| |
| private void receive(org.eclipse.swt.events.MouseEvent me) { |
| updateFigureUnderCursor(me); |
| int state = me.stateMask; |
| if (captured) { |
| if (mouseTarget != null) |
| currentEvent = new MouseEvent(me.x, me.y, this, mouseTarget, me.button, state); |
| } else { |
| IFigure f = root.findMouseEventTargetAt(me.x, me.y); |
| if (f == mouseTarget) { |
| if (mouseTarget != null) |
| currentEvent = |
| new MouseEvent(me.x, me.y, this, mouseTarget, me.button, state); |
| return; |
| } |
| if (mouseTarget != null) { |
| currentEvent = new MouseEvent(me.x, me.y, this, mouseTarget, me.button, state); |
| mouseTarget.handleMouseExited(currentEvent); |
| } |
| setMouseTarget(f); |
| if (mouseTarget != null) { |
| currentEvent = new MouseEvent(me.x, me.y, this, mouseTarget, me.button, state); |
| mouseTarget.handleMouseEntered(currentEvent); |
| } |
| } |
| } |
| |
| /** |
| * @see EventDispatcher#releaseCapture() |
| */ |
| protected void releaseCapture() { |
| captured = false; |
| } |
| |
| /** |
| * @see EventDispatcher#requestFocus(IFigure) |
| */ |
| public void requestFocus(IFigure fig) { |
| setFocus(fig); |
| } |
| |
| /** |
| * @see EventDispatcher#requestRemoveFocus(IFigure) |
| */ |
| public void requestRemoveFocus(IFigure fig) { |
| if (getFocusOwner() == fig) |
| setFocus(null); |
| if (mouseTarget == fig) |
| mouseTarget = null; |
| if (cursorTarget == fig) |
| cursorTarget = null; |
| if (hoverSource == fig) |
| hoverSource = null; |
| getFocusTraverseManager().setCurrentFocusOwner(null); |
| } |
| |
| /** |
| * @see EventDispatcher#setCapture(IFigure) |
| */ |
| protected void setCapture(IFigure figure) { |
| captured = true; |
| mouseTarget = figure; |
| } |
| |
| /** |
| * @see EventDispatcher#setControl(Control) |
| */ |
| public void setControl(Control c) { |
| if (c == control) |
| return; |
| if (control != null && !control.isDisposed()) |
| throw new RuntimeException( |
| "Can not set control again once it has been set"); //$NON-NLS-1$ |
| if (c != null) |
| c.addDisposeListener(new org.eclipse.swt.events.DisposeListener() { |
| public void widgetDisposed(DisposeEvent e) { |
| if (toolTipHelper != null) |
| toolTipHelper.dispose(); |
| } |
| }); |
| control = c; |
| } |
| |
| /** |
| * Sets the mouse cursor. |
| * @param c the new cursor |
| */ |
| protected void setCursor(Cursor c) { |
| if (c == null && cursor == null) { |
| return; |
| } else if ((c != cursor) || (!c.equals(cursor))) { |
| cursor = c; |
| if (control != null && !control.isDisposed()) |
| control.setCursor(c); |
| } |
| } |
| |
| /** |
| * Enables key traversal via TAB and ALT+TAB if <i>traverse</i> is <code>true</code>. |
| * Disables it otherwise. |
| * @param traverse whether key traversal should be enabled |
| */ |
| public void setEnableKeyTraversal(boolean traverse) { |
| figureTraverse = traverse; |
| } |
| |
| /** |
| * Sets the figure under the mouse cursor. |
| * @param f the new figure under the cursor |
| */ |
| protected void setFigureUnderCursor(IFigure f) { |
| if (cursorTarget == f) |
| return; |
| cursorTarget = f; |
| updateCursor(); |
| } |
| |
| /** |
| * Sets the focus figure. If the figure currently with focus is not <code>null</code>, |
| * {@link IFigure#handleFocusLost(FocusEvent)} is called on the current focused figure. If |
| * the new focus figure is not <code>null</code>, this will call |
| * {@link IFigure#handleFocusGained(FocusEvent)} on the new focused figure. |
| * @param fig the new focus figure |
| */ |
| protected void setFocus(IFigure fig) { |
| if (fig == focusOwner) |
| return; |
| FocusEvent fe = new FocusEvent(focusOwner, fig); |
| IFigure oldOwner = focusOwner; |
| focusOwner = fig; |
| if (oldOwner != null) |
| oldOwner.handleFocusLost(fe); |
| if (fig != null) |
| getFocusTraverseManager().setCurrentFocusOwner(fig); |
| if (focusOwner != null) |
| focusOwner.handleFocusGained(fe); |
| } |
| |
| /** |
| * Sets the figure that the mouse cursor is hovering over. |
| * @param figure the new hover source |
| * @param me the mouse event |
| */ |
| protected void setHoverSource(Figure figure, org.eclipse.swt.events.MouseEvent me) { |
| hoverSource = figure; |
| if (figure != null) { |
| Control control = (Control)me.getSource(); |
| org.eclipse.swt.graphics.Point absolute; |
| absolute = control.toDisplay(new org.eclipse.swt.graphics.Point(me.x, me.y)); |
| toolTipHelper = getToolTipHelper(); |
| toolTipHelper.updateToolTip( |
| hoverSource, getCurrentToolTip(), absolute.x, absolute.y); |
| } else if (toolTipHelper != null) { |
| // Update with null to clear hoverSource in ToolTipHelper |
| toolTipHelper.updateToolTip(hoverSource, getCurrentToolTip(), me.x, me.y); |
| } |
| } |
| |
| /** |
| * Sets the given figure to be the target of future mouse events. |
| * @param figure the new mouse target |
| */ |
| protected void setMouseTarget(IFigure figure) { |
| mouseTarget = figure; |
| } |
| |
| /** |
| * @see EventDispatcher#setRoot(IFigure) |
| */ |
| public void setRoot(IFigure figure) { |
| root = figure; |
| } |
| |
| /** |
| * @see EventDispatcher#updateCursor() |
| */ |
| protected void updateCursor() { |
| Cursor newCursor = null; |
| if (cursorTarget != null) |
| newCursor = cursorTarget.getCursor(); |
| setCursor(newCursor); |
| } |
| |
| /** |
| * Updates the figure under the cursor, unless the mouse is captured, in which case all |
| * mouse events will be routed to the figure that captured the mouse. |
| * @param me the mouse event |
| */ |
| protected void updateFigureUnderCursor(org.eclipse.swt.events.MouseEvent me) { |
| if (!captured) { |
| IFigure f = root.findFigureAt(me.x, me.y); |
| setFigureUnderCursor(f); |
| if ((Figure)cursorTarget != hoverSource) |
| updateHoverSource(me); |
| } |
| } |
| |
| /** |
| * Updates the figure that will receive hover events. The hover source must have a |
| * tooltip. If the figure under the mouse doesn't have a tooltip set, this method will |
| * walk up the ancestor hierarchy until either a figure with a tooltip is found or it |
| * gets to the root figure. |
| * @param me the mouse event |
| */ |
| protected void updateHoverSource(org.eclipse.swt.events.MouseEvent me) { |
| /* |
| * Derive source from figure under cursor. |
| * Set the source in setHoverSource(); |
| * If figure.getToolTip() is null, get parent's toolTip |
| * Continue parent traversal until a toolTip is found or root is reached. |
| */ |
| if (cursorTarget != null) { |
| boolean sourceFound = false; |
| Figure source = (Figure)cursorTarget; |
| while (!sourceFound && source.getParent() != null) { |
| if (source.getToolTip() != null) |
| sourceFound = true; |
| else |
| source = (Figure)source.getParent(); |
| } |
| setHoverSource(source, me); |
| } else { |
| setHoverSource(null, me); |
| } |
| } |
| |
| } |