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