1 /* ToolTipManager.java --
2 Copyright (C) 2002, 2004, 2006, Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
40 import java
.awt
.Component
;
41 import java
.awt
.Container
;
42 import java
.awt
.Dimension
;
43 import java
.awt
.Point
;
44 import java
.awt
.event
.ActionEvent
;
45 import java
.awt
.event
.ActionListener
;
46 import java
.awt
.event
.MouseAdapter
;
47 import java
.awt
.event
.MouseEvent
;
48 import java
.awt
.event
.MouseMotionListener
;
51 * This class is responsible for the registration of JToolTips to Components
52 * and for displaying them when appropriate.
54 public class ToolTipManager
extends MouseAdapter
implements MouseMotionListener
57 * This ActionListener is associated with the Timer that listens to whether
58 * the JToolTip can be hidden after four seconds.
60 protected class stillInsideTimerAction
implements ActionListener
63 * This method creates a new stillInsideTimerAction object.
65 protected stillInsideTimerAction()
67 // Nothing to do here.
71 * This method hides the JToolTip when the Timer has finished.
73 * @param event The ActionEvent.
75 public void actionPerformed(ActionEvent event
)
82 * This Actionlistener is associated with the Timer that listens to whether
83 * the mouse cursor has re-entered the JComponent in time for an immediate
84 * redisplay of the JToolTip.
86 protected class outsideTimerAction
implements ActionListener
89 * This method creates a new outsideTimerAction object.
91 protected outsideTimerAction()
93 // Nothing to do here.
97 * This method is called when the Timer that listens to whether the mouse
98 * cursor has re-entered the JComponent has run out.
100 * @param event The ActionEvent.
102 public void actionPerformed(ActionEvent event
)
104 // TODO: What should be done here, if anything?
109 * This ActionListener is associated with the Timer that listens to whether
110 * it is time for the JToolTip to be displayed after the mouse has entered
113 protected class insideTimerAction
implements ActionListener
116 * This method creates a new insideTimerAction object.
118 protected insideTimerAction()
120 // Nothing to do here.
124 * This method displays the JToolTip when the Mouse has been still for the
127 * @param event The ActionEvent.
129 public void actionPerformed(ActionEvent event
)
136 * The Timer that determines whether the Mouse has been still long enough
137 * for the JToolTip to be displayed.
142 * The Timer that determines whether the Mouse has re-entered the JComponent
143 * quickly enough for the JToolTip to be displayed immediately.
148 * The Timer that determines whether the JToolTip has been displayed long
149 * enough for it to be hidden.
153 /** A global enabled setting for the ToolTipManager. */
154 private transient boolean enabled
= true;
156 /** lightWeightPopupEnabled */
157 protected boolean lightWeightPopupEnabled
= true;
159 /** heavyWeightPopupEnabled */
160 protected boolean heavyWeightPopupEnabled
= false;
162 /** The shared instance of the ToolTipManager. */
163 private static ToolTipManager shared
;
165 /** The current component the tooltip is being displayed for. */
166 private JComponent currentComponent
;
168 /** The current tooltip. */
169 private JToolTip currentTip
;
174 private String toolTipText
;
176 /** The last known position of the mouse cursor. */
177 private Point currentPoint
;
183 * Creates a new ToolTipManager and sets up the timers.
187 enterTimer
= new Timer(750, new insideTimerAction());
188 enterTimer
.setRepeats(false);
190 insideTimer
= new Timer(4000, new stillInsideTimerAction());
191 insideTimer
.setRepeats(false);
193 exitTimer
= new Timer(500, new outsideTimerAction());
194 exitTimer
.setRepeats(false);
198 * This method returns the shared instance of ToolTipManager used by all
201 * @return The shared instance of ToolTipManager.
203 public static ToolTipManager
sharedInstance()
206 shared
= new ToolTipManager();
212 * This method sets whether ToolTips are enabled or disabled for all
215 * @param enabled Whether ToolTips are enabled or disabled for all
218 public void setEnabled(boolean enabled
)
227 this.enabled
= enabled
;
231 * This method returns whether ToolTips are enabled.
233 * @return Whether ToolTips are enabled.
235 public boolean isEnabled()
241 * This method returns whether LightweightToolTips are enabled.
243 * @return Whether LighweightToolTips are enabled.
245 public boolean isLightWeightPopupEnabled()
247 return lightWeightPopupEnabled
;
251 * This method sets whether LightweightToolTips are enabled. If you mix
252 * Lightweight and Heavyweight components, you must set this to false to
253 * ensure that the ToolTips popup above all other components.
255 * @param enabled Whether LightweightToolTips will be enabled.
257 public void setLightWeightPopupEnabled(boolean enabled
)
259 lightWeightPopupEnabled
= enabled
;
260 heavyWeightPopupEnabled
= ! enabled
;
264 * This method returns the initial delay before the ToolTip is shown when
265 * the mouse enters a Component.
267 * @return The initial delay before the ToolTip is shown.
269 public int getInitialDelay()
271 return enterTimer
.getDelay();
275 * Sets the initial delay before the ToolTip is shown when the
276 * mouse enters a Component.
278 * @param delay The initial delay before the ToolTip is shown.
280 * @throws IllegalArgumentException if <code>delay</code> is less than zero.
282 public void setInitialDelay(int delay
)
284 enterTimer
.setDelay(delay
);
288 * This method returns the time the ToolTip will be shown before being
291 * @return The time the ToolTip will be shown before being hidden.
293 public int getDismissDelay()
295 return insideTimer
.getDelay();
299 * Sets the time the ToolTip will be shown before being hidden.
301 * @param delay the delay (in milliseconds) before tool tips are hidden.
303 * @throws IllegalArgumentException if <code>delay</code> is less than zero.
305 public void setDismissDelay(int delay
)
307 insideTimer
.setDelay(delay
);
311 * This method returns the amount of delay where if the mouse re-enters a
312 * Component, the tooltip will be shown immediately.
314 * @return The reshow delay.
316 public int getReshowDelay()
318 return exitTimer
.getDelay();
322 * Sets the amount of delay where if the mouse re-enters a
323 * Component, the tooltip will be shown immediately.
325 * @param delay The reshow delay (in milliseconds).
327 * @throws IllegalArgumentException if <code>delay</code> is less than zero.
329 public void setReshowDelay(int delay
)
331 exitTimer
.setDelay(delay
);
335 * This method registers a JComponent with the ToolTipManager.
337 * @param component The JComponent to register with the ToolTipManager.
339 public void registerComponent(JComponent component
)
341 component
.addMouseListener(this);
342 component
.addMouseMotionListener(this);
346 * This method unregisters a JComponent with the ToolTipManager.
348 * @param component The JComponent to unregister with the ToolTipManager.
350 public void unregisterComponent(JComponent component
)
352 component
.removeMouseMotionListener(this);
353 component
.removeMouseListener(this);
357 * This method is called whenever the mouse enters a JComponent registered
358 * with the ToolTipManager. When the mouse enters within the period of time
359 * specified by the reshow delay, the tooltip will be displayed
360 * immediately. Otherwise, it must wait for the initial delay before
361 * displaying the tooltip.
363 * @param event The MouseEvent.
365 public void mouseEntered(MouseEvent event
)
367 if (currentComponent
!= null
368 && getContentPaneDeepestComponent(event
) == currentComponent
)
370 currentPoint
= event
.getPoint();
372 currentComponent
= (JComponent
) event
.getSource();
373 toolTipText
= currentComponent
.getToolTipText(event
);
374 if (exitTimer
.isRunning())
380 // This should always be stopped unless we have just fake-exited.
381 if (!enterTimer
.isRunning())
386 * This method is called when the mouse exits a JComponent registered with the
387 * ToolTipManager. When the mouse exits, the tooltip should be hidden
393 public void mouseExited(MouseEvent event
)
395 if (getContentPaneDeepestComponent(event
) == currentComponent
)
398 currentPoint
= event
.getPoint();
399 currentComponent
= null;
402 if (! enterTimer
.isRunning())
404 if (enterTimer
.isRunning())
406 if (insideTimer
.isRunning())
411 * This method is called when the mouse is pressed on a JComponent
412 * registered with the ToolTipManager. When the mouse is pressed, the
413 * tooltip (if it is shown) must be hidden immediately.
415 * @param event The MouseEvent.
417 public void mousePressed(MouseEvent event
)
419 currentPoint
= event
.getPoint();
420 if (enterTimer
.isRunning())
421 enterTimer
.restart();
422 else if (insideTimer
.isRunning())
430 * This method is called when the mouse is dragged in a JComponent
431 * registered with the ToolTipManager.
433 * @param event The MouseEvent.
435 public void mouseDragged(MouseEvent event
)
437 currentPoint
= event
.getPoint();
438 if (enterTimer
.isRunning())
439 enterTimer
.restart();
443 * This method is called when the mouse is moved in a JComponent registered
444 * with the ToolTipManager.
446 * @param event The MouseEvent.
448 public void mouseMoved(MouseEvent event
)
450 currentPoint
= event
.getPoint();
451 if (currentTip
!= null && currentTip
.isShowing())
452 checkTipUpdate(event
);
455 if (enterTimer
.isRunning())
456 enterTimer
.restart();
461 * Checks if the tooltip's text or location changes when the mouse is moved
462 * over the component.
464 private void checkTipUpdate(MouseEvent ev
)
466 JComponent comp
= (JComponent
) ev
.getSource();
467 String newText
= comp
.getToolTipText(ev
);
468 String oldText
= toolTipText
;
471 if (((newText
!= null && newText
.equals(oldText
)) || newText
== null))
473 // No change at all. Restart timers.
475 enterTimer
.restart();
477 insideTimer
.restart();
481 // Update the tooltip.
482 toolTipText
= newText
;
500 * This method displays the ToolTip. It can figure out the method needed to
501 * show it as well (whether to display it in heavyweight/lightweight panel
502 * or a window.) This is package-private to avoid an accessor method.
506 if (!enabled
|| currentComponent
== null || !currentComponent
.isEnabled()
507 || !currentComponent
.isShowing())
513 if (currentTip
== null || currentTip
.getComponent() != currentComponent
)
514 currentTip
= currentComponent
.createToolTip();
515 currentTip
.setTipText(toolTipText
);
517 Point p
= currentPoint
;
518 Point cP
= currentComponent
.getLocationOnScreen();
519 Dimension dims
= currentTip
.getPreferredSize();
521 JLayeredPane pane
= null;
522 JRootPane r
= ((JRootPane
) SwingUtilities
.getAncestorOfClass(JRootPane
.class,
525 pane
= r
.getLayeredPane();
529 p
.translate(cP
.x
, cP
.y
);
530 adjustLocation(p
, pane
, dims
);
532 currentTip
.setBounds(0, 0, dims
.width
, dims
.height
);
534 PopupFactory factory
= PopupFactory
.getSharedInstance();
535 popup
= factory
.getPopup(currentComponent
, currentTip
, p
.x
, p
.y
);
540 * Adjusts the point to a new location on the component,
541 * using the currentTip's dimensions.
543 * @param p - the point to convert.
544 * @param c - the component the point is on.
545 * @param d - the dimensions of the currentTip.
547 private Point
adjustLocation(Point p
, Component c
, Dimension d
)
549 if (p
.x
+ d
.width
> c
.getWidth())
553 if (p
.y
+ d
.height
< c
.getHeight())
555 if (p
.y
+ d
.height
> c
.getHeight())
562 * This method hides the ToolTip.
563 * This is package-private to avoid an accessor method.
572 * This method returns the deepest component in the content pane for the
573 * first RootPaneContainer up from the currentComponent. This method is
574 * used in conjunction with one of the mouseXXX methods.
576 * @param e The MouseEvent.
578 * @return The deepest component in the content pane.
580 private Component
getContentPaneDeepestComponent(MouseEvent e
)
582 Component source
= (Component
) e
.getSource();
583 Container parent
= SwingUtilities
.getAncestorOfClass(JRootPane
.class,
587 parent
= ((JRootPane
) parent
).getContentPane();
588 Point p
= e
.getPoint();
589 p
= SwingUtilities
.convertPoint(source
, p
, parent
);
590 Component target
= SwingUtilities
.getDeepestComponentAt(parent
, p
.x
, p
.y
);