home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 November / Chip_1998-11_cd.bin / tema / Cafe / jfc.bin / ToolTipManager.java < prev    next >
Text File  |  1998-02-26  |  14KB  |  460 lines

  1. /*
  2.  * @(#)ToolTipManager.java    1.24 98/01/30
  3.  *
  4.  * Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
  5.  *
  6.  * This software is the confidential and proprietary information of Sun
  7.  * Microsystems, Inc. ("Confidential Information").  You shall not
  8.  * disclose such Confidential Information and shall use it only in
  9.  * accordance with the terms of the license agreement you entered into
  10.  * with Sun.
  11.  *
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  15.  * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
  16.  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
  17.  * THIS SOFTWARE OR ITS DERIVATIVES.
  18.  *
  19.  */
  20.  
  21.  
  22. package com.sun.java.swing;
  23.  
  24. import java.awt.event.*;
  25. import java.awt.*;
  26.  
  27. /**
  28.  * Manages all the ToolTips in the system.
  29.  *
  30.  * @see JComponent#createToolTip
  31.  * @version 1.24 01/30/98
  32.  * @author Dave Moore
  33.  * @author Rich Schiavi
  34.  */
  35. public class ToolTipManager extends MouseAdapter implements MouseMotionListener{
  36.     Timer enterTimer, exitTimer, insideTimer;
  37.     String toolTipText;
  38.     Point  preferredLocation;
  39.     JComponent insideComponent;
  40.     MouseEvent mouseEvent;
  41.     boolean showImmediately;
  42.     final static ToolTipManager sharedInstance = new ToolTipManager();
  43.     Popup tipWindow;
  44.     JToolTip tip;
  45.     boolean enabled = true;
  46.     boolean mouseAboveToolTip = false;
  47.     
  48.     private static final int INIT_POPUP = 0;
  49.     private static final int MEDIUM_POPUP = 1;
  50.     private static final int HEAVY_POPUP = 2;
  51.  
  52.     private int tipType = INIT_POPUP;
  53.  
  54.  
  55.     ToolTipManager() {
  56.         enterTimer = new Timer(750, new insideTimerAction());
  57.         enterTimer.setRepeats(false);
  58.         exitTimer = new Timer(500, new outsideTimerAction());
  59.         exitTimer.setRepeats(false);
  60.         insideTimer = new Timer(4000, new stillInsideTimerAction());
  61.         insideTimer.setRepeats(false);
  62.     }
  63.  
  64.     public void setEnabled(boolean flag) {
  65.         enabled = flag;
  66.         if (!flag) {
  67.             hideTipWindow();
  68.         }
  69.     }
  70.  
  71.     public boolean isEnabled() {
  72.         return enabled;
  73.     }
  74.  
  75.     public void setInitialDelay(int microSeconds) {
  76.         enterTimer.setInitialDelay(microSeconds);
  77.     }
  78.  
  79.     public int getInitialDelay() {
  80.         return enterTimer.getInitialDelay();
  81.     }
  82.  
  83.     public void setDismissDelay(int microSeconds) {
  84.         insideTimer.setDelay(microSeconds);
  85.     }
  86.  
  87.     public int getDismissDelay() {
  88.         return insideTimer.getDelay();
  89.     }
  90.  
  91.     public void setReshowDelay(int microSeconds) {
  92.         exitTimer.setDelay(microSeconds);
  93.     }
  94.  
  95.     public int getReshowDelay() {
  96.         return exitTimer.getDelay();
  97.     }
  98.  
  99.     void showTipWindow() {
  100.         if(insideComponent == null || !insideComponent.isShowing())
  101.             return;
  102.         if (enabled) {
  103.             Dimension size;
  104.             Point screenLocation = insideComponent.getLocationOnScreen();
  105.             Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
  106.             Point location = new Point();
  107.  
  108.             // Just to be paranoid
  109.             hideTipWindow();
  110.  
  111.             tip = insideComponent.createToolTip();
  112.             tip.setTipText(toolTipText);
  113.             size = tip.getPreferredSize();
  114.  
  115.         /* REMIND: should recycle these - L&F doesn't seem to
  116.          * be working in browsers when using a Panel
  117.          */
  118.  
  119.         switch (tipType){
  120.         case INIT_POPUP:
  121.         Container parent;
  122.         for (parent = insideComponent.getParent(); parent != null; parent = parent.getParent()){
  123.             if (parent instanceof JApplet){
  124.             tipType = MEDIUM_POPUP;
  125.             tipWindow = new PanelPopup(tip, size);
  126.             }
  127.         }
  128.         if (tipType == INIT_POPUP)
  129.         {
  130.             tipWindow = new WindowPopup((frameForComponent(insideComponent)),tip,size);
  131.             tipType = HEAVY_POPUP;
  132.         }
  133.         break;
  134.         case HEAVY_POPUP:
  135.         tipWindow = new WindowPopup((frameForComponent(insideComponent)),tip,size);
  136.         break;
  137.         case MEDIUM_POPUP:
  138.         tipWindow = new PanelPopup(tip,size);
  139.         break;
  140.         default:
  141.         tipWindow = new WindowPopup((frameForComponent(insideComponent)),tip,size);
  142.         break;
  143.         }
  144.  
  145.             tipWindow.addMouseListener(this);
  146.  
  147.             if(preferredLocation != null) {
  148.                 location.x = screenLocation.x + preferredLocation.x;
  149.                 location.y = screenLocation.y + preferredLocation.y;
  150.             } else {
  151.                 location.x = screenLocation.x + mouseEvent.getX();
  152.                 location.y = screenLocation.y + mouseEvent.getY() + 20;
  153.  
  154.                 if (location.x + size.width > screenSize.width) {
  155.                     location.x -= size.width;
  156.                 }
  157.                 if (location.y + size.height > screenSize.height) {
  158.                     location.y -= (size.height + 20);
  159.                 }
  160.             }
  161.  
  162.         tipWindow.show(insideComponent,location.x,location.y);
  163.             insideTimer.start();
  164.         }
  165.     }
  166.  
  167.     void hideTipWindow() {
  168.         if (tipWindow != null) {
  169.             tipWindow.removeMouseListener(this);
  170.         tipWindow.hide();
  171.             tipWindow = null;
  172.         (tip.getUI()).uninstallUI(tip);
  173.             tip = null;
  174.             insideTimer.stop();
  175.         }
  176.     }
  177.  
  178.     public static ToolTipManager sharedInstance() {
  179.         return sharedInstance;
  180.     }
  181.  
  182.     public void registerComponent(JComponent component) {
  183.         component.removeMouseListener(this);
  184.         component.addMouseListener(this);
  185.     }
  186.  
  187.     public void unregisterComponent(JComponent component) {
  188.         component.removeMouseListener(this);
  189.     }
  190.  
  191.     public void mouseEntered(MouseEvent event) {
  192.         if(event.getSource() == tipWindow)
  193.             return;
  194.         JComponent component = (JComponent)event.getSource();
  195.         toolTipText = component.getToolTipText(event);
  196.         preferredLocation = component.getToolTipLocation(event);
  197.  
  198.         exitTimer.stop();
  199.  
  200.     Point location = event.getPoint();
  201.     // ensure tooltip shows only in proper place
  202.     if (location.x < 0 || 
  203.         location.x >=component.getWidth() ||
  204.         location.y < 0 ||
  205.         location.y >= component.getHeight())
  206.       {
  207.         return;
  208.       }
  209.  
  210.         if (insideComponent != null) {
  211.             enterTimer.stop();
  212.             insideComponent = null;
  213.         }
  214.  
  215.         component.addMouseMotionListener(this);
  216.  
  217.         insideComponent = component;
  218.         if (toolTipText != null) {
  219.             mouseEvent = event;
  220.             if (showImmediately) {
  221.                 showTipWindow();
  222.             } else {
  223.                 enterTimer.start();
  224.             }
  225.         }
  226.     }
  227.  
  228.     public void mouseExited(MouseEvent event) {
  229.         boolean shouldHide = true;
  230.         if (insideComponent == null) {
  231.             // Drag exit
  232.         } 
  233.         if(event.getSource() == tipWindow) {
  234.             Container insideComponentWindow = insideComponent.getTopLevelAncestor();
  235.             Rectangle b = tipWindow.getBounds();
  236.             Point location = event.getPoint();
  237.             location.x += b.x;
  238.             location.y += b.y;
  239.  
  240.             b = insideComponentWindow.getBounds();
  241.             location.x -= b.x;
  242.             location.y -= b.y;
  243.             
  244.             location = SwingUtilities.convertPoint(null,location,insideComponent);
  245.             if(location.x >= 0 && location.x < insideComponent.getWidth() &&
  246.                location.y >= 0 && location.y < insideComponent.getHeight()) {
  247.                 shouldHide = false;
  248.             } else
  249.           shouldHide = true;
  250.         } else if(event.getSource() == insideComponent && tipWindow != null) {
  251.             Point location = SwingUtilities.convertPoint(insideComponent,
  252.                                                          event.getPoint(),
  253.                                                          null);
  254.             Rectangle bounds = insideComponent.getTopLevelAncestor().getBounds();
  255.             location.x += bounds.x;
  256.             location.y += bounds.y;
  257.  
  258.             bounds = tipWindow.getBounds();
  259.             if(location.x >= bounds.x && location.x < (bounds.x + bounds.width) &&
  260.                location.y >= bounds.y && location.y < (bounds.y + bounds.height)) {
  261.                 shouldHide = false;
  262.             } else
  263.                 shouldHide = true;
  264.         } 
  265.         
  266.         if(shouldHide) {        
  267.             enterTimer.stop();
  268.         if (insideComponent != null)
  269.           insideComponent.removeMouseMotionListener(this);
  270.             insideComponent = null;
  271.             toolTipText = null;
  272.             mouseEvent = null;
  273.             hideTipWindow();
  274.             exitTimer.start();
  275.         }
  276.     }
  277.  
  278.     public void mousePressed(MouseEvent event) {
  279.         hideTipWindow();
  280.         enterTimer.stop();
  281.         showImmediately = false;
  282.     }
  283.  
  284.     public void mouseDragged(MouseEvent event) {
  285.     }
  286.  
  287.     public void mouseMoved(MouseEvent event) {
  288.         JComponent component = (JComponent)event.getSource();
  289.         String newText = component.getToolTipText(event);
  290.         Point  newPreferredLocation = component.getToolTipLocation(event);
  291.  
  292.         if (newText != null || newPreferredLocation != null) {
  293.             mouseEvent = event;
  294.             if (((newText != null && newText.equals(toolTipText)) || newText == null) &&
  295.                 ((newPreferredLocation != null && newPreferredLocation.equals(preferredLocation)) 
  296.                  || newPreferredLocation == null)) {
  297.                 if (tipWindow != null) {
  298.                     insideTimer.restart();
  299.                 } else {
  300.                     enterTimer.restart();
  301.                 }
  302.             } else {
  303.                 toolTipText = newText;
  304.                 preferredLocation = newPreferredLocation;
  305.                 if (showImmediately) {
  306.                     hideTipWindow();
  307.                     showTipWindow();
  308.                 } else {
  309.                     enterTimer.restart();
  310.                 }
  311.             }
  312.         } else {
  313.             toolTipText = null;
  314.             preferredLocation = null;
  315.             mouseEvent = null;
  316.             hideTipWindow();
  317.             enterTimer.stop();
  318.             exitTimer.start();
  319.         }
  320.     }
  321.  
  322.     protected class insideTimerAction implements ActionListener {
  323.         public void actionPerformed(ActionEvent e) {
  324.             if(insideComponent != null && insideComponent.isShowing()) {
  325.                 showImmediately = true;
  326.                 showTipWindow();
  327.             }
  328.         }
  329.     }
  330.  
  331.     protected class outsideTimerAction implements ActionListener {
  332.         public void actionPerformed(ActionEvent e) {
  333.             showImmediately = false;
  334.         }
  335.     }
  336.  
  337.     protected class stillInsideTimerAction implements ActionListener {
  338.         public void actionPerformed(ActionEvent e) {
  339.             hideTipWindow();
  340.             enterTimer.stop();
  341.             showImmediately = false;
  342.         }
  343.     }
  344.  
  345.     static Frame frameForComponent(Component component) {
  346.         while (!(component instanceof Frame)) {
  347.             component = component.getParent();
  348.         }
  349.         return (Frame)component;
  350.     }
  351.  
  352.   /*
  353.    * The following interface describes what a popup should implement.
  354.    * We do this because the ToolTip manager uses popup that can be windows or
  355.    * panels. The reason is two-fold: Navigator does not display Windows properly,
  356.    * and there is a problem with layout when using a Panel with 
  357.    * Java Apps on the Solaris VM which doesn't occur in Applets or on Win32 VM apps.
  358.    * Solaris also has some strange behaviour with extra MOUSE_EXIT events when
  359.    * using a Panel which required a different workaround, hence Windows for Apps, 
  360.    * Panels for Applets.
  361.    */
  362.   private interface Popup {
  363.     public void show(JComponent invoker, int x, int y);
  364.     public void hide();
  365.     public void addMouseListener(ToolTipManager c);
  366.     public void removeMouseListener(ToolTipManager c);
  367.     public Rectangle getBounds();
  368.   }
  369.  
  370.  
  371.   // MEDIUM
  372.   class PanelPopup extends Panel implements Popup {
  373.  
  374.     public PanelPopup(JComponent t, Dimension s) {
  375.       super();
  376.       setLayout(new BorderLayout());
  377.       add(t, BorderLayout.CENTER);
  378.       setSize(s);
  379.     }
  380.  
  381.     public Rectangle getBounds(){
  382.     return super.getBounds();
  383.     }
  384.  
  385.     public void show(JComponent invoker, int x, int y) {
  386.     Point p = new Point(x,y);
  387.     SwingUtilities.convertPointFromScreen(p,invoker.getRootPane().getLayeredPane());
  388.     this.setBounds(p.x,p.y,getSize().width, getSize().height);
  389.     invoker.getRootPane().getLayeredPane().add(this,JLayeredPane.POPUP_LAYER,0);
  390.     }
  391.  
  392.     public void hide() {
  393.       Container parent = getParent();
  394.       Rectangle r = this.getBounds();
  395.       if(parent != null)
  396.     parent.remove(this);
  397.       parent.repaint(r.x,r.y,r.width,r.height);
  398.     }
  399.  
  400.     public void addMouseListener(ToolTipManager c){
  401.     super.addMouseListener(c);
  402.     }
  403.  
  404.     public void removeMouseListener(ToolTipManager c){
  405.     super.removeMouseListener(c);
  406.     }
  407.  
  408.   }
  409.  
  410.   // HEAVY
  411.   class WindowPopup extends Window implements Popup  {
  412.     boolean  firstShow = true;
  413.  
  414.     public WindowPopup(Frame f,JComponent t, Dimension size) {
  415.       super(f);
  416.       add(t);
  417.       setSize(size);
  418.     }
  419.  
  420.     public Rectangle getBounds(){
  421.     return super.getBounds();
  422.     }
  423.  
  424.     public void show(JComponent invoker, int x, int y) {
  425.       this.setBounds(x,y, getSize().width,getSize().height);
  426.       this.setLocation(x,y);
  427.       this.setVisible(true);
  428.  
  429.       /** This hack is to workaround a bug on Solaris where the windows does not really show
  430.        *  the first time
  431.        */
  432.       if(firstShow) {
  433.     this.hide();
  434.     this.setVisible(true);
  435.     firstShow = false;
  436.       }
  437.     }
  438.         
  439.     public void hide() {
  440.       super.hide();
  441.       /** We need to call removeNotify() here because hide() does something only if
  442.        *  Component.visible is true. When the app frame is miniaturized, the parent 
  443.        *  frame of this frame is invisible, causing AWT to believe that this frame
  444.        *  is invisible and causing hide() to do nothing
  445.        */
  446.       removeNotify();
  447.     }
  448.  
  449.     public void addMouseListener(ToolTipManager c){
  450.     super.addMouseListener(c);
  451.     }
  452.  
  453.     public void removeMouseListener(ToolTipManager c){
  454.     super.removeMouseListener(c);
  455.     }
  456.  
  457.   }
  458.  
  459. }
  460.