/******************************************************************************* * Copyright (c) 2000, 2010, 2012 IBM Corporation, Gerhardt Informatics Kft. 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 * Gerhardt Informatics Kft. - GEFGWT port *******************************************************************************/ 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(this, mouseTarget, me); 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; can be <code>null</code> */ 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() * @since 3.6 */ public 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) { currentEvent = null; updateFigureUnderCursor(me); if (captured) { if (mouseTarget != null) currentEvent = new MouseEvent(this, mouseTarget, me); } else { IFigure f = root.findMouseEventTargetAt(me.x, me.y); if (f == mouseTarget) { if (mouseTarget != null) currentEvent = new MouseEvent(this, mouseTarget, me); return; } if (mouseTarget != null) { currentEvent = new MouseEvent(this, mouseTarget, me); mouseTarget.handleMouseExited(currentEvent); } setMouseTarget(f); if (mouseTarget != null) { currentEvent = new MouseEvent(this, mouseTarget, me); 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 (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); } } }