FileDocCategorySizeDatePackage
ToolTipManager.javaAPI DocJava SE 5 API28791Fri Aug 26 14:57:58 BST 2005javax.swing

ToolTipManager

public class ToolTipManager extends MouseAdapter implements MouseMotionListener
Manages all the ToolTips in the system.

ToolTipManager contains numerous properties for configuring how long it will take for the tooltips to become visible, and how long till they hide. Consider a component that has a different tooltip based on where the mouse is, such as JTree. When the mouse moves into the JTree and over a region that has a valid tooltip, the tooltip will become visibile after initialDelay milliseconds. After dismissDelay milliseconds the tooltip will be hidden. If the mouse is over a region that has a valid tooltip, and the tooltip is currently visible, when the mouse moves to a region that doesn't have a valid tooltip the tooltip will be hidden. If the mouse then moves back into a region that has a valid tooltip within reshowDelay milliseconds, the tooltip will immediately be shown, otherwise the tooltip will be shown again after initialDelay milliseconds.

see
JComponent#createToolTip
version
1.70 01/16/04
author
Dave Moore
author
Rich Schiavi

Fields Summary
Timer
enterTimer
Timer
exitTimer
Timer
insideTimer
String
toolTipText
Point
preferredLocation
JComponent
insideComponent
MouseEvent
mouseEvent
boolean
showImmediately
static final ToolTipManager
sharedInstance
transient Popup
tipWindow
private Window
window
The Window tip is being displayed in. This will be non-null if the Window tip is in differs from that of insideComponent's Window.
JToolTip
tip
private Rectangle
popupRect
private Rectangle
popupFrameRect
boolean
enabled
private boolean
tipShowing
private KeyStroke
postTip
private KeyStroke
hideTip
private Action
postTipAction
private Action
hideTipAction
private FocusListener
focusChangeListener
private MouseMotionListener
moveBeforeEnterListener
protected boolean
lightWeightPopupEnabled
protected boolean
heavyWeightPopupEnabled
Constructors Summary
ToolTipManager()


     
        enterTimer = new Timer(750, new insideTimerAction());
        enterTimer.setRepeats(false);
        exitTimer = new Timer(500, new outsideTimerAction());
        exitTimer.setRepeats(false);
        insideTimer = new Timer(4000, new stillInsideTimerAction());
        insideTimer.setRepeats(false);

	// create accessibility actions 
	postTip = KeyStroke.getKeyStroke(KeyEvent.VK_F1,Event.CTRL_MASK);
	postTipAction = new Actions(Actions.SHOW);
	hideTip = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE,0);
	hideTipAction = new Actions(Actions.HIDE);

	moveBeforeEnterListener = new MoveBeforeEnterListener();
    
Methods Summary
private voidcheckForTipChange(java.awt.event.MouseEvent event)
Checks to see if the tooltip needs to be changed in response to the MouseMoved event event.

        JComponent component = (JComponent)event.getSource();
        String newText = component.getToolTipText(event);
        Point  newPreferredLocation = component.getToolTipLocation(event);

        if (newText != null || newPreferredLocation != null) {
            mouseEvent = event;
            if (((newText != null && newText.equals(toolTipText)) || newText == null) &&
                ((newPreferredLocation != null && newPreferredLocation.equals(preferredLocation)) 
                 || newPreferredLocation == null)) {
                if (tipWindow != null) {
                    insideTimer.restart();
                } else {
                    enterTimer.restart();
                }
            } else {
                toolTipText = newText;
                preferredLocation = newPreferredLocation;
                if (showImmediately) {
                    hideTipWindow();
                    showTipWindow();
                    exitTimer.stop();
                } else {
                    enterTimer.restart();
                }
            }
        } else {
            toolTipText = null;
            preferredLocation = null;
            mouseEvent = null;
            insideComponent = null;
            hideTipWindow();
            enterTimer.stop();
            exitTimer.restart();
        }
    
private java.awt.event.FocusListenercreateFocusChangeListener()

    return new FocusAdapter(){
      public void focusLost(FocusEvent evt){
	hideTipWindow();
        insideComponent = null;
	JComponent c = (JComponent)evt.getSource();
	c.removeFocusListener(focusChangeListener);
      }
    };
  
static java.awt.FrameframeForComponent(java.awt.Component component)

        while (!(component instanceof Frame)) {
            component = component.getParent();
        }
        return (Frame)component;
    
public intgetDismissDelay()
Returns the dismissal delay value.

return
an integer representing the dismissal delay value, in milliseconds
see
#setDismissDelay

        return insideTimer.getInitialDelay();
    
private intgetHeightAdjust(java.awt.Rectangle a, java.awt.Rectangle b)

    if (b.y >= a.y && (b.y + b.height) <= (a.y + a.height))
      return 0;
    else
      return (((b.y + b.height) - (a.y + a.height)) + 5);
  
public intgetInitialDelay()
Returns the initial delay value.

return
an integer representing the initial delay value, in milliseconds
see
#setInitialDelay

        return enterTimer.getInitialDelay();
    
private intgetPopupFitHeight(java.awt.Rectangle popupRectInScreen, java.awt.Component invoker)

    if (invoker != null){
      Container parent;
      for (parent = invoker.getParent(); parent != null; parent = parent.getParent()){
	if(parent instanceof JFrame || parent instanceof JDialog ||
	   parent instanceof JWindow) {
	  return getHeightAdjust(parent.getBounds(),popupRectInScreen);
	} else if (parent instanceof JApplet || parent instanceof JInternalFrame) {
	  if (popupFrameRect == null){
	    popupFrameRect = new Rectangle();
	  }
	  Point p = parent.getLocationOnScreen();
	  popupFrameRect.setBounds(p.x,p.y,
				   parent.getBounds().width,
				   parent.getBounds().height);
	  return getHeightAdjust(popupFrameRect,popupRectInScreen);
	}
      }
    }
    return 0;
  
private intgetPopupFitWidth(java.awt.Rectangle popupRectInScreen, java.awt.Component invoker)

    if (invoker != null){
      Container parent;
      for (parent = invoker.getParent(); parent != null; parent = parent.getParent()){
	// fix internal frame size bug: 4139087 - 4159012
	if(parent instanceof JFrame || parent instanceof JDialog ||
	   parent instanceof JWindow) { // no check for awt.Frame since we use Heavy tips
	  return getWidthAdjust(parent.getBounds(),popupRectInScreen);
	} else if (parent instanceof JApplet || parent instanceof JInternalFrame) {
	  if (popupFrameRect == null){
	    popupFrameRect = new Rectangle();
	  }
	  Point p = parent.getLocationOnScreen();
	  popupFrameRect.setBounds(p.x,p.y,
				   parent.getBounds().width,
				   parent.getBounds().height);
	  return getWidthAdjust(popupFrameRect,popupRectInScreen);
	}
      }
    }
    return 0;
  
public intgetReshowDelay()
Returns the reshow delay property.

return
reshown delay property
see
#setReshowDelay

        return exitTimer.getInitialDelay();
    
private intgetWidthAdjust(java.awt.Rectangle a, java.awt.Rectangle b)

    //    System.out.println("width b.x/b.width: " + b.x + "/" + b.width +
    //		       "a.x/a.width: " + a.x + "/" + a.width);
    if (b.x >= a.x && (b.x + b.width) <= (a.x + a.width)){
      return 0;
    }
    else {
      return (((b.x + b.width) - (a.x +a.width)) + 5);
    }
  
private voidhide(javax.swing.JComponent source)

        hideTipWindow();
        source.removeFocusListener(focusChangeListener);
        preferredLocation = null;
        insideComponent = null;
    
voidhideTipWindow()

        if (tipWindow != null) {
            if (window != null) {
                window.removeMouseListener(this);
                window = null;
            }
            tipWindow.hide();
	    tipWindow = null;
	    tipShowing = false;
	    (tip.getUI()).uninstallUI(tip);
            tip = null;
            insideTimer.stop();
        }
    
private voidinitiateToolTip(java.awt.event.MouseEvent event)

        if (event.getSource() == window) {
            return;
        }
        JComponent component = (JComponent)event.getSource();
	component.removeMouseMotionListener(moveBeforeEnterListener);

        exitTimer.stop();

	Point location = event.getPoint();
	// ensure tooltip shows only in proper place
	if (location.x < 0 || 
	    location.x >=component.getWidth() ||
	    location.y < 0 ||
	    location.y >= component.getHeight()) {
	    return;
	}

        if (insideComponent != null) {
            enterTimer.stop();
        }
	// A component in an unactive internal frame is sent two
	// mouseEntered events, make sure we don't end up adding
	// ourselves an extra time.
        component.removeMouseMotionListener(this);
        component.addMouseMotionListener(this);

        boolean sameComponent = (insideComponent == component);

        insideComponent = component;
	if (tipWindow != null){
            mouseEvent = event;
            if (showImmediately) {
                String newToolTipText = component.getToolTipText(event);
                Point newPreferredLocation = component.getToolTipLocation(
                                                         event);
                boolean sameLoc = (preferredLocation != null) ?
                            preferredLocation.equals(newPreferredLocation) :
                            (newPreferredLocation == null);

                if (!sameComponent || !toolTipText.equals(newToolTipText) || 
                         !sameLoc) {
                    toolTipText = newToolTipText;
                    preferredLocation = newPreferredLocation;
                    showTipWindow();
                }
            } else {
                enterTimer.start();
            }
        }
    
public booleanisEnabled()
Returns true if this object is enabled.

return
true if this object is enabled, false otherwise

        return enabled;
    
public booleanisLightWeightPopupEnabled()
Returns true if lightweight (all-Java) Tooltips are in use, or false if heavyweight (native peer) Tooltips are being used.

return
true if lightweight ToolTips are in use

 
        return lightWeightPopupEnabled;
    
public voidmouseDragged(java.awt.event.MouseEvent event)
Called when the mouse is pressed and dragged. Does nothing.

param
event the event in question

    
public voidmouseEntered(java.awt.event.MouseEvent event)
Called when the mouse enters the region of a component. This determines whether the tool tip should be shown.

param
event the event in question

        initiateToolTip(event);
    
public voidmouseExited(java.awt.event.MouseEvent event)
Called when the mouse exits the region of a component. Any tool tip showing should be hidden.

param
event the event in question

        boolean shouldHide = true;
        if (insideComponent == null) {
            // Drag exit
        } 
        if (window != null && event.getSource() == window) {
	  // if we get an exit and have a heavy window
	  // we need to check if it if overlapping the inside component
            Container insideComponentWindow = insideComponent.getTopLevelAncestor();
            Point location = event.getPoint();
            SwingUtilities.convertPointToScreen(location, window);

            location.x -= insideComponentWindow.getX();
            location.y -= insideComponentWindow.getY();
            
            location = SwingUtilities.convertPoint(null,location,insideComponent);
            if (location.x >= 0 && location.x < insideComponent.getWidth() &&
               location.y >= 0 && location.y < insideComponent.getHeight()) {
                shouldHide = false;
            } else {
	        shouldHide = true;
	    }
        } else if(event.getSource() == insideComponent && tipWindow != null) {
	    Window win = SwingUtilities.getWindowAncestor(insideComponent);
	    if (win != null) {	// insideComponent may have been hidden (e.g. in a menu)
		Point location = SwingUtilities.convertPoint(insideComponent,
							     event.getPoint(),
							     win);
		Rectangle bounds = insideComponent.getTopLevelAncestor().getBounds();
		location.x += bounds.x;
		location.y += bounds.y;
		
		Point loc = new Point(0, 0);
		SwingUtilities.convertPointToScreen(loc, tip);
		bounds.x = loc.x;
		bounds.y = loc.y;
		bounds.width = tip.getWidth();
		bounds.height = tip.getHeight();
		
		if (location.x >= bounds.x && location.x < (bounds.x + bounds.width) &&
		    location.y >= bounds.y && location.y < (bounds.y + bounds.height)) {
		    shouldHide = false;
		} else {
		    shouldHide = true;
		}
	    }
        } 
        
        if (shouldHide) {        
            enterTimer.stop();
	    if (insideComponent != null) {
	        insideComponent.removeMouseMotionListener(this);
	    }
            insideComponent = null;
            toolTipText = null;
            mouseEvent = null;
            hideTipWindow();
            exitTimer.restart();
        }
    
public voidmouseMoved(java.awt.event.MouseEvent event)
Called when the mouse is moved. Determines whether the tool tip should be displayed.

param
event the event in question

        if (tipShowing) {
            checkForTipChange(event);
        }
        else if (showImmediately) {
            JComponent component = (JComponent)event.getSource();
            toolTipText = component.getToolTipText(event);
            if (toolTipText != null) {
                preferredLocation = component.getToolTipLocation(event);
                mouseEvent = event;
                insideComponent = component;
                exitTimer.stop();
                showTipWindow();
            }
        }
        else {
            // Lazily lookup the values from within insideTimerAction
            insideComponent = (JComponent)event.getSource();
            mouseEvent = event;
            toolTipText = null;
            enterTimer.restart();
        }
    
public voidmousePressed(java.awt.event.MouseEvent event)
Called when the mouse is pressed. Any tool tip showing should be hidden.

param
event the event in question

        hideTipWindow();
        enterTimer.stop();
        showImmediately = false;
        insideComponent = null;
        mouseEvent = null;
    
public voidregisterComponent(javax.swing.JComponent component)
Registers a component for tooltip management.

This will register key bindings to show and hide the tooltip text only if component has focus bindings. This is done so that components that are not normally focus traversable, such as JLabel, are not made focus traversable as a result of invoking this method.

param
component a JComponent object to add
see
JComponent#isFocusTraversable

        component.removeMouseListener(this);
        component.addMouseListener(this);
        component.removeMouseMotionListener(moveBeforeEnterListener);
	component.addMouseMotionListener(moveBeforeEnterListener);

	if (shouldRegisterBindings(component)) {
	    // register our accessibility keybindings for this component
	    // this will apply globally across L&F
	    // Post Tip: Ctrl+F1
	    // Unpost Tip: Esc and Ctrl+F1
	    InputMap inputMap = component.getInputMap(JComponent.WHEN_FOCUSED);
	    ActionMap actionMap = component.getActionMap();

	    if (inputMap != null && actionMap != null) {
		inputMap.put(postTip, "postTip");
		inputMap.put(hideTip, "hideTip");
		actionMap.put("postTip", postTipAction);
		actionMap.put("hideTip", hideTipAction);
	    }
	}
    
public voidsetDismissDelay(int milliseconds)
Specifies the dismissal delay value.

param
milliseconds the number of milliseconds to delay before taking away the tooltip
see
#getDismissDelay

        insideTimer.setInitialDelay(milliseconds);
    
public voidsetEnabled(boolean flag)
Enables or disables the tooltip.

param
flag true to enable the tip, false otherwise

        enabled = flag;
        if (!flag) {
            hideTipWindow();
        }
    
public voidsetInitialDelay(int milliseconds)
Specifies the initial delay value.

param
milliseconds the number of milliseconds to delay (after the cursor has paused) before displaying the tooltip
see
#getInitialDelay

        enterTimer.setInitialDelay(milliseconds);
    
public voidsetLightWeightPopupEnabled(boolean aFlag)
When displaying the JToolTip, the ToolTipManager chooses to use a lightweight JPanel if it fits. This method allows you to disable this feature. You have to do disable it if your application mixes light weight and heavy weights components.

param
aFlag true if a lightweight panel is desired, false otherwise

        lightWeightPopupEnabled = aFlag;
    
public voidsetReshowDelay(int milliseconds)
Used to specify the amount of time before the user has to wait initialDelay milliseconds before a tooltip will be shown. That is, if the tooltip is hidden, and the user moves into a region of the same Component that has a valid tooltip within milliseconds milliseconds the tooltip will immediately be shown. Otherwise, if the user moves into a region with a valid tooltip after milliseconds milliseconds, the user will have to wait an additional initialDelay milliseconds before the tooltip is shown again.

param
milliseconds time in milliseconds
see
#getReshowDelay

        exitTimer.setInitialDelay(milliseconds);
    
public static javax.swing.ToolTipManagersharedInstance()
Returns a shared ToolTipManager instance.

return
a shared ToolTipManager object

        return sharedInstance;
    
private booleanshouldRegisterBindings(javax.swing.JComponent component)
Returns whether or not bindings should be registered on the given JComponent. This is implemented to return true if the tool tip manager has a binding in any one of the InputMaps registered under the condition WHEN_FOCUSED.

This does not use isFocusTraversable as some components may override isFocusTraversable and base the return value on something other than bindings. For example, JButton bases its return value on its enabled state.

param
component the JComponent in question

	InputMap inputMap = component.getInputMap(JComponent.WHEN_FOCUSED,
						  false);
	while (inputMap != null && inputMap.size() == 0) {
	    inputMap = inputMap.getParent();
	}
	return (inputMap != null);
    
private voidshow(javax.swing.JComponent source)

        if (tipWindow != null) { // showing we unshow
            hideTipWindow();
            insideComponent = null;
        }
        else {
            hideTipWindow(); // be safe
            enterTimer.stop();
            exitTimer.stop();
            insideTimer.stop();
            insideComponent = source;
            if (insideComponent != null){
                toolTipText = insideComponent.getToolTipText();
                preferredLocation = new Point(10,insideComponent.getHeight()+
                                              10);  // manual set
                showTipWindow();
                // put a focuschange listener on to bring the tip down
                if (focusChangeListener == null){
                    focusChangeListener = createFocusChangeListener();
                }
                insideComponent.addFocusListener(focusChangeListener); 
            }
        }
    
voidshowTipWindow()

        if(insideComponent == null || !insideComponent.isShowing())
            return;
	for (Container p = insideComponent.getParent(); p != null; p = p.getParent()) {
            if (p instanceof JPopupMenu) break;
	    if (p instanceof Window) {
		if (!((Window)p).isFocused()) {
		    return;
		}
		break;
	    }
	}
        if (enabled) {
            Dimension size;
            Point screenLocation = insideComponent.getLocationOnScreen();
            Point location = new Point();
            Rectangle sBounds = insideComponent.getGraphicsConfiguration().
                                                getBounds();
	    boolean leftToRight 
                = SwingUtilities.isLeftToRight(insideComponent);

            // Just to be paranoid
            hideTipWindow();

            tip = insideComponent.createToolTip();
            tip.setTipText(toolTipText);
            size = tip.getPreferredSize();

            if(preferredLocation != null) {
                location.x = screenLocation.x + preferredLocation.x;
                location.y = screenLocation.y + preferredLocation.y;
		if (!leftToRight) {
		    location.x -= size.width;
		}
            } else {
                location.x = screenLocation.x + mouseEvent.getX();
                location.y = screenLocation.y + mouseEvent.getY() + 20;
		if (!leftToRight) {
		    if(location.x - size.width>=0) {
		        location.x -= size.width;
		    }
		}

            }

	    // we do not adjust x/y when using awt.Window tips
	    if (popupRect == null){
		popupRect = new Rectangle();
	    }
	    popupRect.setBounds(location.x,location.y,
				size.width,size.height);
	    
	    // Fit as much of the tooltip on screen as possible
            if (location.x < sBounds.x) {
                location.x = sBounds.x;
            }
            else if (location.x - sBounds.x + size.width > sBounds.width) {
                location.x = sBounds.x + Math.max(0, sBounds.width - size.width)
;
            }
            if (location.y < sBounds.y) {
                location.y = sBounds.y;
            }
            else if (location.y - sBounds.y + size.height > sBounds.height) {
                location.y = sBounds.y + Math.max(0, sBounds.height - size.height);
            }

            PopupFactory popupFactory = PopupFactory.getSharedInstance();

            if (lightWeightPopupEnabled) {
		int y = getPopupFitHeight(popupRect, insideComponent);
		int x = getPopupFitWidth(popupRect,insideComponent);
		if (x>0 || y>0) {
		    popupFactory.setPopupType(PopupFactory.MEDIUM_WEIGHT_POPUP);
		} else {
		    popupFactory.setPopupType(PopupFactory.LIGHT_WEIGHT_POPUP);
		}
            }
            else {
                popupFactory.setPopupType(PopupFactory.MEDIUM_WEIGHT_POPUP);
            }
	    tipWindow = popupFactory.getPopup(insideComponent, tip,
					      location.x,
					      location.y);
            popupFactory.setPopupType(PopupFactory.LIGHT_WEIGHT_POPUP);

	    tipWindow.show();

            Window componentWindow = SwingUtilities.windowForComponent(
                                                    insideComponent);

            window = SwingUtilities.windowForComponent(tip);
            if (window != null && window != componentWindow) {
                window.addMouseListener(this);
            }
            else {
                window = null;
            }

            insideTimer.start();
	    tipShowing = true;
        }
    
public voidunregisterComponent(javax.swing.JComponent component)
Removes a component from tooltip control.

param
component a JComponent object to remove

        component.removeMouseListener(this);
	component.removeMouseMotionListener(moveBeforeEnterListener);

	if (shouldRegisterBindings(component)) {
	    InputMap inputMap = component.getInputMap(JComponent.WHEN_FOCUSED);
	    ActionMap actionMap = component.getActionMap();

	    if (inputMap != null && actionMap != null) {
		inputMap.remove(postTip);
		inputMap.remove(hideTip);
		actionMap.remove("postTip");
		actionMap.remove("hideTip");
	    }
	}