
org.eclipse.jface.window.ToolTip Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jface Show documentation
Show all versions of jface Show documentation
JFace is a UI toolkit with classes for handling many common UI programming tasks. JFace is window-system-independent in both its API and implementation, and is designed to work with SWT without hiding it. JFace includes the usual UI toolkit components of image and font registries, text, dialog, preference and wizard frameworks, and progress reporting for long running operations. Two of its more interesting features are actions and viewers. The action mechanism allows user commands to be defined independently from their exact whereabouts in the UI. Viewers are model based adapters for certain SWT widgets, simplifying the presentation of application data structured as lists, tables or trees.
The newest version!
/*******************************************************************************
* Copyright (c) 2006, 2007 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:
* Tom Schindl - initial API and implementation
*******************************************************************************/
package org.eclipse.jface.window;
import java.util.HashMap;
import org.eclipse.jface.viewers.ColumnViewer;
import org.eclipse.jface.viewers.ViewerCell;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Monitor;
import org.eclipse.swt.widgets.Shell;
/**
* This class gives implementors to provide customized tooltips for any control.
*
* @since 3.3
*/
public abstract class ToolTip {
private Control control;
private int xShift = 3;
private int yShift = 0;
private int popupDelay = 0;
private int hideDelay = 0;
private ToolTipOwnerControlListener listener;
private HashMap data;
// Ensure that only one tooltip is active in time
private static Shell CURRENT_TOOLTIP;
/**
* Recreate the tooltip on every mouse move
*/
public static final int RECREATE = 1;
/**
* Don't recreate the tooltip as long the mouse doesn't leave the area
* triggering the Tooltip creation
*/
public static final int NO_RECREATE = 1 << 1;
private TooltipHideListener hideListener = new TooltipHideListener();
private boolean hideOnMouseDown = true;
private boolean respectDisplayBounds = true;
private boolean respectMonitorBounds = true;
private int style;
private Object currentArea;
/**
* Create new instance which add TooltipSupport to the widget
*
* @param control
* the control on whose action the tooltip is shown
*/
public ToolTip(Control control) {
this(control, RECREATE, false);
}
/**
* @param control
* the control to which the tooltip is bound
* @param style
* style passed to control tooltip behaviour
*
* @param manualActivation
* true
if the activation is done manually using
* {@link #show(Point)}
* @see #RECREATE
* @see #NO_RECREATE
*/
public ToolTip(Control control, int style, boolean manualActivation) {
this.control = control;
this.style = style;
this.control.addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
deactivate();
}
});
this.listener = new ToolTipOwnerControlListener();
if (!manualActivation) {
activate();
}
}
/**
* Restore arbitary data under the given key
*
* @param key
* the key
* @param value
* the value
*/
public void setData(String key, Object value) {
if (data == null) {
data = new HashMap();
}
data.put(key, value);
}
/**
* Get the data restored under the key
*
* @param key
* the key
* @return data or null
if no entry is restored under the key
*/
public Object getData(String key) {
if (data != null) {
return data.get(key);
}
return null;
}
/**
* Set the shift (from the mouse position triggered the event) used to
* display the tooltip. By default the tooltip is shifted 3 pixels to the
* left
*
* @param p
* the new shift
*/
public void setShift(Point p) {
xShift = p.x;
yShift = p.y;
}
/**
* Activate tooltip support for this control
*/
public void activate() {
deactivate();
control.addListener(SWT.Dispose, listener);
control.addListener(SWT.MouseHover, listener);
control.addListener(SWT.MouseMove, listener);
control.addListener(SWT.MouseExit, listener);
control.addListener(SWT.MouseDown, listener);
}
/**
* Deactivate tooltip support for the underlying control
*/
public void deactivate() {
control.removeListener(SWT.Dispose, listener);
control.removeListener(SWT.MouseHover, listener);
control.removeListener(SWT.MouseMove, listener);
control.removeListener(SWT.MouseExit, listener);
control.removeListener(SWT.MouseDown, listener);
}
/**
* Return whther the tooltip respects bounds of the display.
*
* @return true
if the tooltip respects bounds of the display
*/
public boolean isRespectDisplayBounds() {
return respectDisplayBounds;
}
/**
* Set to false
if display bounds should not be respected or
* to true
if the tooltip is should repositioned to not
* overlap the display bounds.
*
* Default is true
*
*
* @param respectDisplayBounds
*/
public void setRespectDisplayBounds(boolean respectDisplayBounds) {
this.respectDisplayBounds = respectDisplayBounds;
}
/**
* Return whther the tooltip respects bounds of the monitor.
*
* @return true
if tooltip respects the bounds of the monitor
*/
public boolean isRespectMonitorBounds() {
return respectMonitorBounds;
}
/**
* Set to false
if monitor bounds should not be respected or
* to true
if the tooltip is should repositioned to not
* overlap the monitors bounds. The monitor the tooltip belongs to is the
* same is control's monitor the tooltip is shown for.
*
* Default is true
*
*
* @param respectMonitorBounds
*/
public void setRespectMonitorBounds(boolean respectMonitorBounds) {
this.respectMonitorBounds = respectMonitorBounds;
}
/**
* Should the tooltip displayed because of the given event.
*
* Subclasses may overwrite this to get custom behaviour
*
*
* @param event
* the event
* @return true
if tooltip should be displayed
*/
protected boolean shouldCreateToolTip(Event event) {
if ((style & NO_RECREATE) != 0) {
Object tmp = getToolTipArea(event);
// No new area close the current tooltip
if (tmp == null) {
hide();
return false;
}
boolean rv = !tmp.equals(currentArea);
return rv;
}
return true;
}
/**
* This method is called before the tooltip is hidden
*
* @param event
* the event trying to hide the tooltip
* @return true
if the tooltip should be hidden
*/
private boolean shouldHideToolTip(Event event) {
if (event != null && event.type == SWT.MouseMove
&& (style & NO_RECREATE) != 0) {
Object tmp = getToolTipArea(event);
// No new area close the current tooltip
if (tmp == null) {
hide();
return false;
}
boolean rv = !tmp.equals(currentArea);
return rv;
}
return true;
}
/**
* This method is called to check for which area the tooltip is
* created/hidden for. In case of {@link #NO_RECREATE} this is used to
* decide if the tooltip is hidden recreated.
*
* By the default it is the widget the tooltip is created for but could be any object. To decide if
* the area changed the {@link Object#equals(Object)} method is used.
*
* @param event
* the event
* @return the area responsible for the tooltip creation or
* null
this could be any object describing the area
* (e.g. the {@link Control} onto which the tooltip is bound to, a part of
* this area e.g. for {@link ColumnViewer} this could be a
* {@link ViewerCell})
*/
protected Object getToolTipArea(Event event) {
return control;
}
/**
* Start up the tooltip programmatically
*
* @param location
* the location relative to the control the tooltip is shown
*/
public void show(Point location) {
Event event = new Event();
event.x = location.x;
event.y = location.y;
event.widget = control;
toolTipCreate(event);
}
private Shell toolTipCreate(final Event event) {
if (shouldCreateToolTip(event)) {
Shell shell = new Shell(control.getShell(), SWT.ON_TOP | SWT.TOOL
| SWT.NO_FOCUS);
shell.setLayout(new FillLayout());
toolTipOpen(shell, event);
return shell;
}
return null;
}
private void toolTipShow(Shell tip, Event event) {
if (!tip.isDisposed()) {
currentArea = getToolTipArea(event);
createToolTipContentArea(event, tip);
if (isHideOnMouseDown()) {
toolTipHookBothRecursively(tip);
} else {
toolTipHookByTypeRecursively(tip, true, SWT.MouseExit);
}
tip.pack();
tip.setLocation(fixupDisplayBounds(tip.getSize(), getLocation(tip
.getSize(), event)));
tip.setVisible(true);
}
}
private Point fixupDisplayBounds(Point tipSize, Point location) {
if (respectDisplayBounds || respectMonitorBounds) {
Rectangle bounds;
Point rightBounds = new Point(tipSize.x + location.x, tipSize.y
+ location.y);
Monitor[] ms = control.getDisplay().getMonitors();
if (respectMonitorBounds && ms.length > 1) {
// By default present in the monitor of the control
bounds = control.getMonitor().getBounds();
Point p = new Point(location.x, location.y);
// Search on which monitor the event occurred
Rectangle tmp;
for (int i = 0; i < ms.length; i++) {
tmp = ms[i].getBounds();
if (tmp.contains(p)) {
bounds = tmp;
break;
}
}
} else {
bounds = control.getDisplay().getBounds();
}
if (!(bounds.contains(location) && bounds.contains(rightBounds))) {
if (rightBounds.x > bounds.width) {
location.x -= rightBounds.x - bounds.width;
}
if (rightBounds.y > bounds.height) {
location.y -= rightBounds.y - bounds.height;
}
if (location.x < bounds.x) {
location.x = bounds.x;
}
if (location.y < bounds.y) {
location.y = bounds.y;
}
}
}
return location;
}
/**
* Get the display relative location where the tooltip is displayed.
* Subclasses may overwrite to implement custom positioning.
*
* @param tipSize
* the size of the tooltip to be shown
* @param event
* the event triggered showing the tooltip
* @return the absolute position on the display
*/
public Point getLocation(Point tipSize, Event event) {
return control.toDisplay(event.x + xShift, event.y + yShift);
}
private void toolTipHide(Shell tip, Event event) {
if (tip != null && !tip.isDisposed() && shouldHideToolTip(event)) {
currentArea = null;
tip.dispose();
CURRENT_TOOLTIP = null;
afterHideToolTip(event);
}
}
private void toolTipOpen(final Shell shell, final Event event) {
// Ensure that only one Tooltip is shown in time
if (CURRENT_TOOLTIP != null) {
toolTipHide(CURRENT_TOOLTIP, null);
}
CURRENT_TOOLTIP = shell;
if (popupDelay > 0) {
control.getDisplay().timerExec(popupDelay, new Runnable() {
public void run() {
toolTipShow(shell, event);
}
});
} else {
toolTipShow(CURRENT_TOOLTIP, event);
}
if (hideDelay > 0) {
control.getDisplay().timerExec(popupDelay + hideDelay,
new Runnable() {
public void run() {
toolTipHide(shell, null);
}
});
}
}
private void toolTipHookByTypeRecursively(Control c, boolean add, int type) {
if (add) {
c.addListener(type, hideListener);
} else {
c.removeListener(type, hideListener);
}
if (c instanceof Composite) {
Control[] children = ((Composite) c).getChildren();
for (int i = 0; i < children.length; i++) {
toolTipHookByTypeRecursively(children[i], add, type);
}
}
}
private void toolTipHookBothRecursively(Control c) {
c.addListener(SWT.MouseDown, hideListener);
c.addListener(SWT.MouseExit, hideListener);
if (c instanceof Composite) {
Control[] children = ((Composite) c).getChildren();
for (int i = 0; i < children.length; i++) {
toolTipHookBothRecursively(children[i]);
}
}
}
/**
* Creates the content area of the the tooltip.
*
* @param event
* the event that triggered the activation of the tooltip
* @param parent
* the parent of the content area
* @return the content area created
*/
protected abstract Composite createToolTipContentArea(Event event,
Composite parent);
/**
* This method is called after a Tooltip is hidden.
*
* Subclasses may override to clean up requested system resources
*
*
* @param event
* event triggered the hiding action (may be null
* if event wasn't triggered by user actions directly)
*/
protected void afterHideToolTip(Event event) {
}
/**
* Set the hide delay.
*
* @param hideDelay
* the delay before the tooltip is hidden. If 0
* the tooltip is shown until user moves to other item
*/
public void setHideDelay(int hideDelay) {
this.hideDelay = hideDelay;
}
/**
* Set the popup delay.
*
* @param popupDelay
* the delay before the tooltip is shown to the user. If
* 0
the tooltip is shown immediately
*/
public void setPopupDelay(int popupDelay) {
this.popupDelay = popupDelay;
}
/**
* Return if hiding on mouse down is set.
*
* @return true
if hiding on mouse down in the tool tip is on
*/
public boolean isHideOnMouseDown() {
return hideOnMouseDown;
}
/**
* If you don't want the tool tip to be hidden when the user clicks inside
* the tool tip set this to false
. You maybe also need to
* hide the tool tip yourself depending on what you do after clicking in the
* tooltip (e.g. if you open a new {@link Shell})
*
* @param hideOnMouseDown
* flag to indicate of tooltip is hidden automatically on mouse
* down inside the tool tip
*/
public void setHideOnMouseDown(final boolean hideOnMouseDown) {
// Only needed if there's currently a tooltip active
if (CURRENT_TOOLTIP != null && !CURRENT_TOOLTIP.isDisposed()) {
// Only change if value really changed
if (hideOnMouseDown != this.hideOnMouseDown) {
control.getDisplay().syncExec(new Runnable() {
public void run() {
if (CURRENT_TOOLTIP != null
&& CURRENT_TOOLTIP.isDisposed()) {
toolTipHookByTypeRecursively(CURRENT_TOOLTIP,
hideOnMouseDown, SWT.MouseDown);
}
}
});
}
}
this.hideOnMouseDown = hideOnMouseDown;
}
/**
* Hide the currently active tool tip
*/
public void hide() {
toolTipHide(CURRENT_TOOLTIP, null);
}
private class ToolTipOwnerControlListener implements Listener {
public void handleEvent(Event event) {
switch (event.type) {
case SWT.Dispose:
case SWT.KeyDown:
case SWT.MouseDown:
case SWT.MouseMove:
toolTipHide(CURRENT_TOOLTIP, event);
break;
case SWT.MouseHover:
toolTipCreate(event);
break;
case SWT.MouseExit:
/*
* Check if the mouse exit happend because we move over the
* tooltip
*/
if (CURRENT_TOOLTIP != null && !CURRENT_TOOLTIP.isDisposed()) {
if (CURRENT_TOOLTIP.getBounds().contains(
control.toDisplay(event.x, event.y))) {
break;
}
}
toolTipHide(CURRENT_TOOLTIP, event);
break;
}
}
}
private class TooltipHideListener implements Listener {
public void handleEvent(Event event) {
if (event.widget instanceof Control) {
Control c = (Control) event.widget;
Shell shell = c.getShell();
switch (event.type) {
case SWT.MouseDown:
if (isHideOnMouseDown()) {
toolTipHide(shell, event);
}
break;
case SWT.MouseExit:
/*
* Give some insets to ensure we get exit informations from
* a wider area ;-)
*/
Rectangle rect = shell.getBounds();
rect.x += 5;
rect.y += 5;
rect.width -= 10;
rect.height -= 10;
if (!rect.contains(c.getDisplay().getCursorLocation())) {
toolTipHide(shell, event);
}
break;
}
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy