GNU Classpath (0.91) | |
Frames | No Frames |
1: /* ToolTipManager.java -- 2: Copyright (C) 2002, 2004 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 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) 9: any later version. 10: 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. 15: 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 19: 02110-1301 USA. 20: 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 24: combination. 25: 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. */ 37: 38: package javax.swing; 39: 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; 49: 50: /** 51: * This class is responsible for the registration of JToolTips to Components 52: * and for displaying them when appropriate. 53: */ 54: public class ToolTipManager extends MouseAdapter implements MouseMotionListener 55: { 56: /** 57: * This ActionListener is associated with the Timer that listens to whether 58: * the JToolTip can be hidden after four seconds. 59: */ 60: protected class stillInsideTimerAction implements ActionListener 61: { 62: /** 63: * This method creates a new stillInsideTimerAction object. 64: */ 65: protected stillInsideTimerAction() 66: { 67: // Nothing to do here. 68: } 69: 70: /** 71: * This method hides the JToolTip when the Timer has finished. 72: * 73: * @param event The ActionEvent. 74: */ 75: public void actionPerformed(ActionEvent event) 76: { 77: hideTip(); 78: } 79: } 80: 81: /** 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. 85: */ 86: protected class outsideTimerAction implements ActionListener 87: { 88: /** 89: * This method creates a new outsideTimerAction object. 90: */ 91: protected outsideTimerAction() 92: { 93: // Nothing to do here. 94: } 95: 96: /** 97: * This method is called when the Timer that listens to whether the mouse 98: * cursor has re-entered the JComponent has run out. 99: * 100: * @param event The ActionEvent. 101: */ 102: public void actionPerformed(ActionEvent event) 103: { 104: // TODO: What should be done here, if anything? 105: } 106: } 107: 108: /** 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 111: * the JComponent. 112: */ 113: protected class insideTimerAction implements ActionListener 114: { 115: /** 116: * This method creates a new insideTimerAction object. 117: */ 118: protected insideTimerAction() 119: { 120: // Nothing to do here. 121: } 122: 123: /** 124: * This method displays the JToolTip when the Mouse has been still for the 125: * delay. 126: * 127: * @param event The ActionEvent. 128: */ 129: public void actionPerformed(ActionEvent event) 130: { 131: showTip(); 132: } 133: } 134: 135: /** 136: * The Timer that determines whether the Mouse has been still long enough 137: * for the JToolTip to be displayed. 138: */ 139: Timer enterTimer; 140: 141: /** 142: * The Timer that determines whether the Mouse has re-entered the JComponent 143: * quickly enough for the JToolTip to be displayed immediately. 144: */ 145: Timer exitTimer; 146: 147: /** 148: * The Timer that determines whether the JToolTip has been displayed long 149: * enough for it to be hidden. 150: */ 151: Timer insideTimer; 152: 153: /** A global enabled setting for the ToolTipManager. */ 154: private transient boolean enabled = true; 155: 156: /** lightWeightPopupEnabled */ 157: protected boolean lightWeightPopupEnabled = true; 158: 159: /** heavyWeightPopupEnabled */ 160: protected boolean heavyWeightPopupEnabled = false; 161: 162: /** The shared instance of the ToolTipManager. */ 163: private static ToolTipManager shared; 164: 165: /** The current component the tooltip is being displayed for. */ 166: private static Component currentComponent; 167: 168: /** The current tooltip. */ 169: private static JToolTip currentTip; 170: 171: /** The last known position of the mouse cursor. */ 172: private static Point currentPoint; 173: 174: /** */ 175: private static Popup popup; 176: 177: /** 178: * Creates a new ToolTipManager and sets up the timers. 179: */ 180: ToolTipManager() 181: { 182: enterTimer = new Timer(750, new insideTimerAction()); 183: enterTimer.setRepeats(false); 184: 185: insideTimer = new Timer(4000, new stillInsideTimerAction()); 186: insideTimer.setRepeats(false); 187: 188: exitTimer = new Timer(500, new outsideTimerAction()); 189: exitTimer.setRepeats(false); 190: } 191: 192: /** 193: * This method returns the shared instance of ToolTipManager used by all 194: * JComponents. 195: * 196: * @return The shared instance of ToolTipManager. 197: */ 198: public static ToolTipManager sharedInstance() 199: { 200: if (shared == null) 201: shared = new ToolTipManager(); 202: 203: return shared; 204: } 205: 206: /** 207: * This method sets whether ToolTips are enabled or disabled for all 208: * JComponents. 209: * 210: * @param enabled Whether ToolTips are enabled or disabled for all 211: * JComponents. 212: */ 213: public void setEnabled(boolean enabled) 214: { 215: if (! enabled) 216: { 217: enterTimer.stop(); 218: exitTimer.stop(); 219: insideTimer.stop(); 220: } 221: 222: this.enabled = enabled; 223: } 224: 225: /** 226: * This method returns whether ToolTips are enabled. 227: * 228: * @return Whether ToolTips are enabled. 229: */ 230: public boolean isEnabled() 231: { 232: return enabled; 233: } 234: 235: /** 236: * This method returns whether LightweightToolTips are enabled. 237: * 238: * @return Whether LighweightToolTips are enabled. 239: */ 240: public boolean isLightWeightPopupEnabled() 241: { 242: return lightWeightPopupEnabled; 243: } 244: 245: /** 246: * This method sets whether LightweightToolTips are enabled. If you mix 247: * Lightweight and Heavyweight components, you must set this to false to 248: * ensure that the ToolTips popup above all other components. 249: * 250: * @param enabled Whether LightweightToolTips will be enabled. 251: */ 252: public void setLightWeightPopupEnabled(boolean enabled) 253: { 254: lightWeightPopupEnabled = enabled; 255: heavyWeightPopupEnabled = ! enabled; 256: } 257: 258: /** 259: * This method returns the initial delay before the ToolTip is shown when 260: * the mouse enters a Component. 261: * 262: * @return The initial delay before the ToolTip is shown. 263: */ 264: public int getInitialDelay() 265: { 266: return enterTimer.getDelay(); 267: } 268: 269: /** 270: * This method sets the initial delay before the ToolTip is shown when the 271: * mouse enters a Component. 272: * 273: * @param delay The initial delay before the ToolTip is shown. 274: */ 275: public void setInitialDelay(int delay) 276: { 277: enterTimer.setDelay(delay); 278: } 279: 280: /** 281: * This method returns the time the ToolTip will be shown before being 282: * hidden. 283: * 284: * @return The time the ToolTip will be shown before being hidden. 285: */ 286: public int getDismissDelay() 287: { 288: return insideTimer.getDelay(); 289: } 290: 291: /** 292: * This method sets the time the ToolTip will be shown before being hidden. 293: * 294: * @param delay The time the ToolTip will be shown before being hidden. 295: */ 296: public void setDismissDelay(int delay) 297: { 298: insideTimer.setDelay(delay); 299: } 300: 301: /** 302: * This method returns the amount of delay where if the mouse re-enters a 303: * Component, the tooltip will be shown immediately. 304: * 305: * @return The reshow delay. 306: */ 307: public int getReshowDelay() 308: { 309: return exitTimer.getDelay(); 310: } 311: 312: /** 313: * This method sets the amount of delay where if the mouse re-enters a 314: * Component, the tooltip will be shown immediately. 315: * 316: * @param delay The reshow delay. 317: */ 318: public void setReshowDelay(int delay) 319: { 320: exitTimer.setDelay(delay); 321: } 322: 323: /** 324: * This method registers a JComponent with the ToolTipManager. 325: * 326: * @param component The JComponent to register with the ToolTipManager. 327: */ 328: public void registerComponent(JComponent component) 329: { 330: component.addMouseListener(this); 331: component.addMouseMotionListener(this); 332: } 333: 334: /** 335: * This method unregisters a JComponent with the ToolTipManager. 336: * 337: * @param component The JComponent to unregister with the ToolTipManager. 338: */ 339: public void unregisterComponent(JComponent component) 340: { 341: component.removeMouseMotionListener(this); 342: component.removeMouseListener(this); 343: } 344: 345: /** 346: * This method is called whenever the mouse enters a JComponent registered 347: * with the ToolTipManager. When the mouse enters within the period of time 348: * specified by the reshow delay, the tooltip will be displayed 349: * immediately. Otherwise, it must wait for the initial delay before 350: * displaying the tooltip. 351: * 352: * @param event The MouseEvent. 353: */ 354: public void mouseEntered(MouseEvent event) 355: { 356: if (currentComponent != null 357: && getContentPaneDeepestComponent(event) == currentComponent) 358: return; 359: currentPoint = event.getPoint(); 360: 361: currentComponent = (Component) event.getSource(); 362: 363: if (exitTimer.isRunning()) 364: { 365: exitTimer.stop(); 366: showTip(); 367: return; 368: } 369: // This should always be stopped unless we have just fake-exited. 370: if (!enterTimer.isRunning()) 371: enterTimer.start(); 372: } 373: 374: /** 375: * This method is called when the mouse exits a JComponent registered with the 376: * ToolTipManager. When the mouse exits, the tooltip should be hidden 377: * immediately. 378: * 379: * @param event 380: * The MouseEvent. 381: */ 382: public void mouseExited(MouseEvent event) 383: { 384: if (getContentPaneDeepestComponent(event) == currentComponent) 385: return; 386: 387: currentPoint = event.getPoint(); 388: currentComponent = null; 389: hideTip(); 390: 391: if (! enterTimer.isRunning()) 392: exitTimer.start(); 393: if (enterTimer.isRunning()) 394: enterTimer.stop(); 395: if (insideTimer.isRunning()) 396: insideTimer.stop(); 397: } 398: 399: /** 400: * This method is called when the mouse is pressed on a JComponent 401: * registered with the ToolTipManager. When the mouse is pressed, the 402: * tooltip (if it is shown) must be hidden immediately. 403: * 404: * @param event The MouseEvent. 405: */ 406: public void mousePressed(MouseEvent event) 407: { 408: currentPoint = event.getPoint(); 409: if (enterTimer.isRunning()) 410: enterTimer.restart(); 411: else if (insideTimer.isRunning()) 412: { 413: insideTimer.stop(); 414: hideTip(); 415: } 416: } 417: 418: /** 419: * This method is called when the mouse is dragged in a JComponent 420: * registered with the ToolTipManager. 421: * 422: * @param event The MouseEvent. 423: */ 424: public void mouseDragged(MouseEvent event) 425: { 426: currentPoint = event.getPoint(); 427: if (enterTimer.isRunning()) 428: enterTimer.restart(); 429: } 430: 431: /** 432: * This method is called when the mouse is moved in a JComponent registered 433: * with the ToolTipManager. 434: * 435: * @param event The MouseEvent. 436: */ 437: public void mouseMoved(MouseEvent event) 438: { 439: currentPoint = event.getPoint(); 440: if (enterTimer.isRunning()) 441: enterTimer.restart(); 442: } 443: 444: /** 445: * This method displays the ToolTip. It can figure out the method needed to 446: * show it as well (whether to display it in heavyweight/lightweight panel 447: * or a window.) This is package-private to avoid an accessor method. 448: */ 449: void showTip() 450: { 451: if (!enabled || currentComponent == null || !currentComponent.isEnabled() 452: || !currentComponent.isShowing()) 453: { 454: popup = null; 455: return; 456: } 457: 458: if (currentTip == null || currentTip.getComponent() != currentComponent 459: && currentComponent instanceof JComponent) 460: currentTip = ((JComponent) currentComponent).createToolTip(); 461: 462: Point p = currentPoint; 463: Point cP = currentComponent.getLocationOnScreen(); 464: Dimension dims = currentTip.getPreferredSize(); 465: 466: JLayeredPane pane = null; 467: JRootPane r = ((JRootPane) SwingUtilities.getAncestorOfClass(JRootPane.class, 468: currentComponent)); 469: if (r != null) 470: pane = r.getLayeredPane(); 471: if (pane == null) 472: return; 473: 474: p.translate(cP.x, cP.y); 475: adjustLocation(p, pane, dims); 476: 477: currentTip.setBounds(0, 0, dims.width, dims.height); 478: 479: PopupFactory factory = PopupFactory.getSharedInstance(); 480: popup = factory.getPopup(currentComponent, currentTip, p.x, p.y); 481: popup.show(); 482: } 483: 484: /** 485: * Adjusts the point to a new location on the component, 486: * using the currentTip's dimensions. 487: * 488: * @param p - the point to convert. 489: * @param c - the component the point is on. 490: * @param d - the dimensions of the currentTip. 491: */ 492: private Point adjustLocation(Point p, Component c, Dimension d) 493: { 494: if (p.x + d.width > c.getWidth()) 495: p.x -= d.width; 496: if (p.x < 0) 497: p.x = 0; 498: if (p.y + d.height < c.getHeight()) 499: p.y += d.height; 500: if (p.y + d.height > c.getHeight()) 501: p.y -= d.height; 502: 503: return p; 504: } 505: 506: /** 507: * This method hides the ToolTip. 508: * This is package-private to avoid an accessor method. 509: */ 510: void hideTip() 511: { 512: if (popup != null) 513: popup.hide(); 514: } 515: 516: /** 517: * This method returns the deepest component in the content pane for the 518: * first RootPaneContainer up from the currentComponent. This method is 519: * used in conjunction with one of the mouseXXX methods. 520: * 521: * @param e The MouseEvent. 522: * 523: * @return The deepest component in the content pane. 524: */ 525: private Component getContentPaneDeepestComponent(MouseEvent e) 526: { 527: Component source = (Component) e.getSource(); 528: Container parent = (Container) SwingUtilities.getAncestorOfClass(JRootPane.class, 529: currentComponent); 530: if (parent == null) 531: return null; 532: parent = ((JRootPane) parent).getContentPane(); 533: Point p = e.getPoint(); 534: p = SwingUtilities.convertPoint(source, p, parent); 535: Component target = SwingUtilities.getDeepestComponentAt(parent, p.x, p.y); 536: return target; 537: } 538: }
GNU Classpath (0.91) |