Home » openjdk-7 » javax » swing » [javadoc | source]

    1   /*
    2    * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22    * or visit www.oracle.com if you need additional information or have any
   23    * questions.
   24    */
   25   
   26   
   27   package javax.swing;
   28   
   29   import java.awt.event;
   30   import java.awt;
   31   
   32   /**
   33    * Manages all the <code>ToolTips</code> in the system.
   34    * <p>
   35    * ToolTipManager contains numerous properties for configuring how long it
   36    * will take for the tooltips to become visible, and how long till they
   37    * hide. Consider a component that has a different tooltip based on where
   38    * the mouse is, such as JTree. When the mouse moves into the JTree and
   39    * over a region that has a valid tooltip, the tooltip will become
   40    * visibile after <code>initialDelay</code> milliseconds. After
   41    * <code>dismissDelay</code> milliseconds the tooltip will be hidden. If
   42    * the mouse is over a region that has a valid tooltip, and the tooltip
   43    * is currently visible, when the mouse moves to a region that doesn't have
   44    * a valid tooltip the tooltip will be hidden. If the mouse then moves back
   45    * into a region that has a valid tooltip within <code>reshowDelay</code>
   46    * milliseconds, the tooltip will immediately be shown, otherwise the
   47    * tooltip will be shown again after <code>initialDelay</code> milliseconds.
   48    *
   49    * @see JComponent#createToolTip
   50    * @author Dave Moore
   51    * @author Rich Schiavi
   52    */
   53   public class ToolTipManager extends MouseAdapter implements MouseMotionListener  {
   54       Timer enterTimer, exitTimer, insideTimer;
   55       String toolTipText;
   56       Point  preferredLocation;
   57       JComponent insideComponent;
   58       MouseEvent mouseEvent;
   59       boolean showImmediately;
   60       private static final Object TOOL_TIP_MANAGER_KEY = new Object();
   61       transient Popup tipWindow;
   62       /** The Window tip is being displayed in. This will be non-null if
   63        * the Window tip is in differs from that of insideComponent's Window.
   64        */
   65       private Window window;
   66       JToolTip tip;
   67   
   68       private Rectangle popupRect = null;
   69       private Rectangle popupFrameRect = null;
   70   
   71       boolean enabled = true;
   72       private boolean tipShowing = false;
   73   
   74       private FocusListener focusChangeListener = null;
   75       private MouseMotionListener moveBeforeEnterListener = null;
   76       private KeyListener accessibilityKeyListener = null;
   77   
   78       private KeyStroke postTip;
   79       private KeyStroke hideTip;
   80   
   81       // PENDING(ges)
   82       protected boolean lightWeightPopupEnabled = true;
   83       protected boolean heavyWeightPopupEnabled = false;
   84   
   85       ToolTipManager() {
   86           enterTimer = new Timer(750, new insideTimerAction());
   87           enterTimer.setRepeats(false);
   88           exitTimer = new Timer(500, new outsideTimerAction());
   89           exitTimer.setRepeats(false);
   90           insideTimer = new Timer(4000, new stillInsideTimerAction());
   91           insideTimer.setRepeats(false);
   92   
   93           moveBeforeEnterListener = new MoveBeforeEnterListener();
   94           accessibilityKeyListener = new AccessibilityKeyListener();
   95   
   96           postTip = KeyStroke.getKeyStroke(KeyEvent.VK_F1, InputEvent.CTRL_MASK);
   97           hideTip =  KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
   98       }
   99   
  100       /**
  101        * Enables or disables the tooltip.
  102        *
  103        * @param flag  true to enable the tip, false otherwise
  104        */
  105       public void setEnabled(boolean flag) {
  106           enabled = flag;
  107           if (!flag) {
  108               hideTipWindow();
  109           }
  110       }
  111   
  112       /**
  113        * Returns true if this object is enabled.
  114        *
  115        * @return true if this object is enabled, false otherwise
  116        */
  117       public boolean isEnabled() {
  118           return enabled;
  119       }
  120   
  121       /**
  122        * When displaying the <code>JToolTip</code>, the
  123        * <code>ToolTipManager</code> chooses to use a lightweight
  124        * <code>JPanel</code> if it fits. This method allows you to
  125        * disable this feature. You have to do disable it if your
  126        * application mixes light weight and heavy weights components.
  127        *
  128        * @param aFlag true if a lightweight panel is desired, false otherwise
  129        *
  130        */
  131       public void setLightWeightPopupEnabled(boolean aFlag){
  132           lightWeightPopupEnabled = aFlag;
  133       }
  134   
  135       /**
  136        * Returns true if lightweight (all-Java) <code>Tooltips</code>
  137        * are in use, or false if heavyweight (native peer)
  138        * <code>Tooltips</code> are being used.
  139        *
  140        * @return true if lightweight <code>ToolTips</code> are in use
  141        */
  142       public boolean isLightWeightPopupEnabled() {
  143           return lightWeightPopupEnabled;
  144       }
  145   
  146   
  147       /**
  148        * Specifies the initial delay value.
  149        *
  150        * @param milliseconds  the number of milliseconds to delay
  151        *        (after the cursor has paused) before displaying the
  152        *        tooltip
  153        * @see #getInitialDelay
  154        */
  155       public void setInitialDelay(int milliseconds) {
  156           enterTimer.setInitialDelay(milliseconds);
  157       }
  158   
  159       /**
  160        * Returns the initial delay value.
  161        *
  162        * @return an integer representing the initial delay value,
  163        *          in milliseconds
  164        * @see #setInitialDelay
  165        */
  166       public int getInitialDelay() {
  167           return enterTimer.getInitialDelay();
  168       }
  169   
  170       /**
  171        * Specifies the dismissal delay value.
  172        *
  173        * @param milliseconds  the number of milliseconds to delay
  174        *        before taking away the tooltip
  175        * @see #getDismissDelay
  176        */
  177       public void setDismissDelay(int milliseconds) {
  178           insideTimer.setInitialDelay(milliseconds);
  179       }
  180   
  181       /**
  182        * Returns the dismissal delay value.
  183        *
  184        * @return an integer representing the dismissal delay value,
  185        *          in milliseconds
  186        * @see #setDismissDelay
  187        */
  188       public int getDismissDelay() {
  189           return insideTimer.getInitialDelay();
  190       }
  191   
  192       /**
  193        * Used to specify the amount of time before the user has to wait
  194        * <code>initialDelay</code> milliseconds before a tooltip will be
  195        * shown. That is, if the tooltip is hidden, and the user moves into
  196        * a region of the same Component that has a valid tooltip within
  197        * <code>milliseconds</code> milliseconds the tooltip will immediately
  198        * be shown. Otherwise, if the user moves into a region with a valid
  199        * tooltip after <code>milliseconds</code> milliseconds, the user
  200        * will have to wait an additional <code>initialDelay</code>
  201        * milliseconds before the tooltip is shown again.
  202        *
  203        * @param milliseconds time in milliseconds
  204        * @see #getReshowDelay
  205        */
  206       public void setReshowDelay(int milliseconds) {
  207           exitTimer.setInitialDelay(milliseconds);
  208       }
  209   
  210       /**
  211        * Returns the reshow delay property.
  212        *
  213        * @return reshown delay property
  214        * @see #setReshowDelay
  215        */
  216       public int getReshowDelay() {
  217           return exitTimer.getInitialDelay();
  218       }
  219   
  220       void showTipWindow() {
  221           if(insideComponent == null || !insideComponent.isShowing())
  222               return;
  223           String mode = UIManager.getString("ToolTipManager.enableToolTipMode");
  224           if ("activeApplication".equals(mode)) {
  225               KeyboardFocusManager kfm =
  226                       KeyboardFocusManager.getCurrentKeyboardFocusManager();
  227               if (kfm.getFocusedWindow() == null) {
  228                   return;
  229               }
  230           }
  231           if (enabled) {
  232               Dimension size;
  233               Point screenLocation = insideComponent.getLocationOnScreen();
  234               Point location = new Point();
  235               GraphicsConfiguration gc;
  236               gc = insideComponent.getGraphicsConfiguration();
  237               Rectangle sBounds = gc.getBounds();
  238               Insets screenInsets = Toolkit.getDefaultToolkit()
  239                                                .getScreenInsets(gc);
  240               // Take into account screen insets, decrease viewport
  241               sBounds.x += screenInsets.left;
  242               sBounds.y += screenInsets.top;
  243               sBounds.width -= (screenInsets.left + screenInsets.right);
  244               sBounds.height -= (screenInsets.top + screenInsets.bottom);
  245           boolean leftToRight
  246                   = SwingUtilities.isLeftToRight(insideComponent);
  247   
  248               // Just to be paranoid
  249               hideTipWindow();
  250   
  251               tip = insideComponent.createToolTip();
  252               tip.setTipText(toolTipText);
  253               size = tip.getPreferredSize();
  254   
  255               if(preferredLocation != null) {
  256                   location.x = screenLocation.x + preferredLocation.x;
  257                   location.y = screenLocation.y + preferredLocation.y;
  258           if (!leftToRight) {
  259               location.x -= size.width;
  260           }
  261               } else {
  262                   location.x = screenLocation.x + mouseEvent.getX();
  263                   location.y = screenLocation.y + mouseEvent.getY() + 20;
  264           if (!leftToRight) {
  265               if(location.x - size.width>=0) {
  266                   location.x -= size.width;
  267               }
  268           }
  269   
  270               }
  271   
  272           // we do not adjust x/y when using awt.Window tips
  273           if (popupRect == null){
  274           popupRect = new Rectangle();
  275           }
  276           popupRect.setBounds(location.x,location.y,
  277                   size.width,size.height);
  278   
  279           // Fit as much of the tooltip on screen as possible
  280               if (location.x < sBounds.x) {
  281                   location.x = sBounds.x;
  282               }
  283               else if (location.x - sBounds.x + size.width > sBounds.width) {
  284                   location.x = sBounds.x + Math.max(0, sBounds.width - size.width)
  285   ;
  286               }
  287               if (location.y < sBounds.y) {
  288                   location.y = sBounds.y;
  289               }
  290               else if (location.y - sBounds.y + size.height > sBounds.height) {
  291                   location.y = sBounds.y + Math.max(0, sBounds.height - size.height);
  292               }
  293   
  294               PopupFactory popupFactory = PopupFactory.getSharedInstance();
  295   
  296               if (lightWeightPopupEnabled) {
  297           int y = getPopupFitHeight(popupRect, insideComponent);
  298           int x = getPopupFitWidth(popupRect,insideComponent);
  299           if (x>0 || y>0) {
  300               popupFactory.setPopupType(PopupFactory.MEDIUM_WEIGHT_POPUP);
  301           } else {
  302               popupFactory.setPopupType(PopupFactory.LIGHT_WEIGHT_POPUP);
  303           }
  304               }
  305               else {
  306                   popupFactory.setPopupType(PopupFactory.MEDIUM_WEIGHT_POPUP);
  307               }
  308           tipWindow = popupFactory.getPopup(insideComponent, tip,
  309                             location.x,
  310                             location.y);
  311               popupFactory.setPopupType(PopupFactory.LIGHT_WEIGHT_POPUP);
  312   
  313           tipWindow.show();
  314   
  315               Window componentWindow = SwingUtilities.windowForComponent(
  316                                                       insideComponent);
  317   
  318               window = SwingUtilities.windowForComponent(tip);
  319               if (window != null && window != componentWindow) {
  320                   window.addMouseListener(this);
  321               }
  322               else {
  323                   window = null;
  324               }
  325   
  326               insideTimer.start();
  327           tipShowing = true;
  328           }
  329       }
  330   
  331       void hideTipWindow() {
  332           if (tipWindow != null) {
  333               if (window != null) {
  334                   window.removeMouseListener(this);
  335                   window = null;
  336               }
  337               tipWindow.hide();
  338               tipWindow = null;
  339               tipShowing = false;
  340               tip = null;
  341               insideTimer.stop();
  342           }
  343       }
  344   
  345       /**
  346        * Returns a shared <code>ToolTipManager</code> instance.
  347        *
  348        * @return a shared <code>ToolTipManager</code> object
  349        */
  350       public static ToolTipManager sharedInstance() {
  351           Object value = SwingUtilities.appContextGet(TOOL_TIP_MANAGER_KEY);
  352           if (value instanceof ToolTipManager) {
  353               return (ToolTipManager) value;
  354           }
  355           ToolTipManager manager = new ToolTipManager();
  356           SwingUtilities.appContextPut(TOOL_TIP_MANAGER_KEY, manager);
  357           return manager;
  358       }
  359   
  360       // add keylistener here to trigger tip for access
  361       /**
  362        * Registers a component for tooltip management.
  363        * <p>
  364        * This will register key bindings to show and hide the tooltip text
  365        * only if <code>component</code> has focus bindings. This is done
  366        * so that components that are not normally focus traversable, such
  367        * as <code>JLabel</code>, are not made focus traversable as a result
  368        * of invoking this method.
  369        *
  370        * @param component  a <code>JComponent</code> object to add
  371        * @see JComponent#isFocusTraversable
  372        */
  373       public void registerComponent(JComponent component) {
  374           component.removeMouseListener(this);
  375           component.addMouseListener(this);
  376           component.removeMouseMotionListener(moveBeforeEnterListener);
  377           component.addMouseMotionListener(moveBeforeEnterListener);
  378           component.removeKeyListener(accessibilityKeyListener);
  379           component.addKeyListener(accessibilityKeyListener);
  380       }
  381   
  382       /**
  383        * Removes a component from tooltip control.
  384        *
  385        * @param component  a <code>JComponent</code> object to remove
  386        */
  387       public void unregisterComponent(JComponent component) {
  388           component.removeMouseListener(this);
  389           component.removeMouseMotionListener(moveBeforeEnterListener);
  390           component.removeKeyListener(accessibilityKeyListener);
  391       }
  392   
  393       // implements java.awt.event.MouseListener
  394       /**
  395        *  Called when the mouse enters the region of a component.
  396        *  This determines whether the tool tip should be shown.
  397        *
  398        *  @param event  the event in question
  399        */
  400       public void mouseEntered(MouseEvent event) {
  401           initiateToolTip(event);
  402       }
  403   
  404       private void initiateToolTip(MouseEvent event) {
  405           if (event.getSource() == window) {
  406               return;
  407           }
  408           JComponent component = (JComponent)event.getSource();
  409           component.removeMouseMotionListener(moveBeforeEnterListener);
  410   
  411           exitTimer.stop();
  412   
  413           Point location = event.getPoint();
  414           // ensure tooltip shows only in proper place
  415           if (location.x < 0 ||
  416               location.x >=component.getWidth() ||
  417               location.y < 0 ||
  418               location.y >= component.getHeight()) {
  419               return;
  420           }
  421   
  422           if (insideComponent != null) {
  423               enterTimer.stop();
  424           }
  425           // A component in an unactive internal frame is sent two
  426           // mouseEntered events, make sure we don't end up adding
  427           // ourselves an extra time.
  428           component.removeMouseMotionListener(this);
  429           component.addMouseMotionListener(this);
  430   
  431           boolean sameComponent = (insideComponent == component);
  432   
  433           insideComponent = component;
  434       if (tipWindow != null){
  435               mouseEvent = event;
  436               if (showImmediately) {
  437                   String newToolTipText = component.getToolTipText(event);
  438                   Point newPreferredLocation = component.getToolTipLocation(
  439                                                            event);
  440                   boolean sameLoc = (preferredLocation != null) ?
  441                               preferredLocation.equals(newPreferredLocation) :
  442                               (newPreferredLocation == null);
  443   
  444                   if (!sameComponent || !toolTipText.equals(newToolTipText) ||
  445                            !sameLoc) {
  446                       toolTipText = newToolTipText;
  447                       preferredLocation = newPreferredLocation;
  448                       showTipWindow();
  449                   }
  450               } else {
  451                   enterTimer.start();
  452               }
  453           }
  454       }
  455   
  456       // implements java.awt.event.MouseListener
  457       /**
  458        *  Called when the mouse exits the region of a component.
  459        *  Any tool tip showing should be hidden.
  460        *
  461        *  @param event  the event in question
  462        */
  463       public void mouseExited(MouseEvent event) {
  464           boolean shouldHide = true;
  465           if (insideComponent == null) {
  466               // Drag exit
  467           }
  468           if (window != null && event.getSource() == window && insideComponent != null) {
  469             // if we get an exit and have a heavy window
  470             // we need to check if it if overlapping the inside component
  471               Container insideComponentWindow = insideComponent.getTopLevelAncestor();
  472               // insideComponent may be removed after tooltip is made visible
  473               if (insideComponentWindow != null) {
  474                   Point location = event.getPoint();
  475                   SwingUtilities.convertPointToScreen(location, window);
  476   
  477                   location.x -= insideComponentWindow.getX();
  478                   location.y -= insideComponentWindow.getY();
  479   
  480                   location = SwingUtilities.convertPoint(null, location, insideComponent);
  481                   if (location.x >= 0 && location.x < insideComponent.getWidth() &&
  482                           location.y >= 0 && location.y < insideComponent.getHeight()) {
  483                       shouldHide = false;
  484                   } else {
  485                       shouldHide = true;
  486                   }
  487               }
  488           } else if(event.getSource() == insideComponent && tipWindow != null) {
  489               Window win = SwingUtilities.getWindowAncestor(insideComponent);
  490               if (win != null) {  // insideComponent may have been hidden (e.g. in a menu)
  491                   Point location = SwingUtilities.convertPoint(insideComponent,
  492                                                                event.getPoint(),
  493                                                                win);
  494                   Rectangle bounds = insideComponent.getTopLevelAncestor().getBounds();
  495                   location.x += bounds.x;
  496                   location.y += bounds.y;
  497   
  498                   Point loc = new Point(0, 0);
  499                   SwingUtilities.convertPointToScreen(loc, tip);
  500                   bounds.x = loc.x;
  501                   bounds.y = loc.y;
  502                   bounds.width = tip.getWidth();
  503                   bounds.height = tip.getHeight();
  504   
  505                   if (location.x >= bounds.x && location.x < (bounds.x + bounds.width) &&
  506                       location.y >= bounds.y && location.y < (bounds.y + bounds.height)) {
  507                       shouldHide = false;
  508                   } else {
  509                       shouldHide = true;
  510                   }
  511               }
  512           }
  513   
  514           if (shouldHide) {
  515               enterTimer.stop();
  516           if (insideComponent != null) {
  517                   insideComponent.removeMouseMotionListener(this);
  518               }
  519               insideComponent = null;
  520               toolTipText = null;
  521               mouseEvent = null;
  522               hideTipWindow();
  523               exitTimer.restart();
  524           }
  525       }
  526   
  527       // implements java.awt.event.MouseListener
  528       /**
  529        *  Called when the mouse is pressed.
  530        *  Any tool tip showing should be hidden.
  531        *
  532        *  @param event  the event in question
  533        */
  534       public void mousePressed(MouseEvent event) {
  535           hideTipWindow();
  536           enterTimer.stop();
  537           showImmediately = false;
  538           insideComponent = null;
  539           mouseEvent = null;
  540       }
  541   
  542       // implements java.awt.event.MouseMotionListener
  543       /**
  544        *  Called when the mouse is pressed and dragged.
  545        *  Does nothing.
  546        *
  547        *  @param event  the event in question
  548        */
  549       public void mouseDragged(MouseEvent event) {
  550       }
  551   
  552       // implements java.awt.event.MouseMotionListener
  553       /**
  554        *  Called when the mouse is moved.
  555        *  Determines whether the tool tip should be displayed.
  556        *
  557        *  @param event  the event in question
  558        */
  559       public void mouseMoved(MouseEvent event) {
  560           if (tipShowing) {
  561               checkForTipChange(event);
  562           }
  563           else if (showImmediately) {
  564               JComponent component = (JComponent)event.getSource();
  565               toolTipText = component.getToolTipText(event);
  566               if (toolTipText != null) {
  567                   preferredLocation = component.getToolTipLocation(event);
  568                   mouseEvent = event;
  569                   insideComponent = component;
  570                   exitTimer.stop();
  571                   showTipWindow();
  572               }
  573           }
  574           else {
  575               // Lazily lookup the values from within insideTimerAction
  576               insideComponent = (JComponent)event.getSource();
  577               mouseEvent = event;
  578               toolTipText = null;
  579               enterTimer.restart();
  580           }
  581       }
  582   
  583       /**
  584        * Checks to see if the tooltip needs to be changed in response to
  585        * the MouseMoved event <code>event</code>.
  586        */
  587       private void checkForTipChange(MouseEvent event) {
  588           JComponent component = (JComponent)event.getSource();
  589           String newText = component.getToolTipText(event);
  590           Point  newPreferredLocation = component.getToolTipLocation(event);
  591   
  592           if (newText != null || newPreferredLocation != null) {
  593               mouseEvent = event;
  594               if (((newText != null && newText.equals(toolTipText)) || newText == null) &&
  595                   ((newPreferredLocation != null && newPreferredLocation.equals(preferredLocation))
  596                    || newPreferredLocation == null)) {
  597                   if (tipWindow != null) {
  598                       insideTimer.restart();
  599                   } else {
  600                       enterTimer.restart();
  601                   }
  602               } else {
  603                   toolTipText = newText;
  604                   preferredLocation = newPreferredLocation;
  605                   if (showImmediately) {
  606                       hideTipWindow();
  607                       showTipWindow();
  608                       exitTimer.stop();
  609                   } else {
  610                       enterTimer.restart();
  611                   }
  612               }
  613           } else {
  614               toolTipText = null;
  615               preferredLocation = null;
  616               mouseEvent = null;
  617               insideComponent = null;
  618               hideTipWindow();
  619               enterTimer.stop();
  620               exitTimer.restart();
  621           }
  622       }
  623   
  624       protected class insideTimerAction implements ActionListener {
  625           public void actionPerformed(ActionEvent e) {
  626               if(insideComponent != null && insideComponent.isShowing()) {
  627                   // Lazy lookup
  628                   if (toolTipText == null && mouseEvent != null) {
  629                       toolTipText = insideComponent.getToolTipText(mouseEvent);
  630                       preferredLocation = insideComponent.getToolTipLocation(
  631                                                 mouseEvent);
  632                   }
  633                   if(toolTipText != null) {
  634                       showImmediately = true;
  635                       showTipWindow();
  636                   }
  637                   else {
  638                       insideComponent = null;
  639                       toolTipText = null;
  640                       preferredLocation = null;
  641                       mouseEvent = null;
  642                       hideTipWindow();
  643                   }
  644               }
  645           }
  646       }
  647   
  648       protected class outsideTimerAction implements ActionListener {
  649           public void actionPerformed(ActionEvent e) {
  650               showImmediately = false;
  651           }
  652       }
  653   
  654       protected class stillInsideTimerAction implements ActionListener {
  655           public void actionPerformed(ActionEvent e) {
  656               hideTipWindow();
  657               enterTimer.stop();
  658               showImmediately = false;
  659               insideComponent = null;
  660               mouseEvent = null;
  661           }
  662       }
  663   
  664     /* This listener is registered when the tooltip is first registered
  665      * on a component in order to catch the situation where the tooltip
  666      * was turned on while the mouse was already within the bounds of
  667      * the component.  This way, the tooltip will be initiated on a
  668      * mouse-entered or mouse-moved, whichever occurs first.  Once the
  669      * tooltip has been initiated, we can remove this listener and rely
  670      * solely on mouse-entered to initiate the tooltip.
  671      */
  672       private class MoveBeforeEnterListener extends MouseMotionAdapter {
  673           public void mouseMoved(MouseEvent e) {
  674               initiateToolTip(e);
  675           }
  676       }
  677   
  678       static Frame frameForComponent(Component component) {
  679           while (!(component instanceof Frame)) {
  680               component = component.getParent();
  681           }
  682           return (Frame)component;
  683       }
  684   
  685     private FocusListener createFocusChangeListener(){
  686       return new FocusAdapter(){
  687         public void focusLost(FocusEvent evt){
  688           hideTipWindow();
  689           insideComponent = null;
  690           JComponent c = (JComponent)evt.getSource();
  691           c.removeFocusListener(focusChangeListener);
  692         }
  693       };
  694     }
  695   
  696     // Returns: 0 no adjust
  697     //         -1 can't fit
  698     //         >0 adjust value by amount returned
  699     private int getPopupFitWidth(Rectangle popupRectInScreen, Component invoker){
  700       if (invoker != null){
  701         Container parent;
  702         for (parent = invoker.getParent(); parent != null; parent = parent.getParent()){
  703           // fix internal frame size bug: 4139087 - 4159012
  704           if(parent instanceof JFrame || parent instanceof JDialog ||
  705              parent instanceof JWindow) { // no check for awt.Frame since we use Heavy tips
  706             return getWidthAdjust(parent.getBounds(),popupRectInScreen);
  707           } else if (parent instanceof JApplet || parent instanceof JInternalFrame) {
  708             if (popupFrameRect == null){
  709               popupFrameRect = new Rectangle();
  710             }
  711             Point p = parent.getLocationOnScreen();
  712             popupFrameRect.setBounds(p.x,p.y,
  713                                      parent.getBounds().width,
  714                                      parent.getBounds().height);
  715             return getWidthAdjust(popupFrameRect,popupRectInScreen);
  716           }
  717         }
  718       }
  719       return 0;
  720     }
  721   
  722     // Returns:  0 no adjust
  723     //          >0 adjust by value return
  724     private int getPopupFitHeight(Rectangle popupRectInScreen, Component invoker){
  725       if (invoker != null){
  726         Container parent;
  727         for (parent = invoker.getParent(); parent != null; parent = parent.getParent()){
  728           if(parent instanceof JFrame || parent instanceof JDialog ||
  729              parent instanceof JWindow) {
  730             return getHeightAdjust(parent.getBounds(),popupRectInScreen);
  731           } else if (parent instanceof JApplet || parent instanceof JInternalFrame) {
  732             if (popupFrameRect == null){
  733               popupFrameRect = new Rectangle();
  734             }
  735             Point p = parent.getLocationOnScreen();
  736             popupFrameRect.setBounds(p.x,p.y,
  737                                      parent.getBounds().width,
  738                                      parent.getBounds().height);
  739             return getHeightAdjust(popupFrameRect,popupRectInScreen);
  740           }
  741         }
  742       }
  743       return 0;
  744     }
  745   
  746     private int getHeightAdjust(Rectangle a, Rectangle b){
  747       if (b.y >= a.y && (b.y + b.height) <= (a.y + a.height))
  748         return 0;
  749       else
  750         return (((b.y + b.height) - (a.y + a.height)) + 5);
  751     }
  752   
  753     // Return the number of pixels over the edge we are extending.
  754     // If we are over the edge the ToolTipManager can adjust.
  755     // REMIND: what if the Tooltip is just too big to fit at all - we currently will just clip
  756     private int getWidthAdjust(Rectangle a, Rectangle b){
  757       //    System.out.println("width b.x/b.width: " + b.x + "/" + b.width +
  758       //                 "a.x/a.width: " + a.x + "/" + a.width);
  759       if (b.x >= a.x && (b.x + b.width) <= (a.x + a.width)){
  760         return 0;
  761       }
  762       else {
  763         return (((b.x + b.width) - (a.x +a.width)) + 5);
  764       }
  765     }
  766   
  767   
  768       //
  769       // Actions
  770       //
  771       private void show(JComponent source) {
  772           if (tipWindow != null) { // showing we unshow
  773               hideTipWindow();
  774               insideComponent = null;
  775           }
  776           else {
  777               hideTipWindow(); // be safe
  778               enterTimer.stop();
  779               exitTimer.stop();
  780               insideTimer.stop();
  781               insideComponent = source;
  782               if (insideComponent != null){
  783                   toolTipText = insideComponent.getToolTipText();
  784                   preferredLocation = new Point(10,insideComponent.getHeight()+
  785                                                 10);  // manual set
  786                   showTipWindow();
  787                   // put a focuschange listener on to bring the tip down
  788                   if (focusChangeListener == null){
  789                       focusChangeListener = createFocusChangeListener();
  790                   }
  791                   insideComponent.addFocusListener(focusChangeListener);
  792               }
  793           }
  794       }
  795   
  796       private void hide(JComponent source) {
  797           hideTipWindow();
  798           source.removeFocusListener(focusChangeListener);
  799           preferredLocation = null;
  800           insideComponent = null;
  801       }
  802   
  803       /* This listener is registered when the tooltip is first registered
  804        * on a component in order to process accessibility keybindings.
  805        * This will apply globally across L&F
  806        *
  807        * Post Tip: Ctrl+F1
  808        * Unpost Tip: Esc and Ctrl+F1
  809        */
  810       private class AccessibilityKeyListener extends KeyAdapter {
  811           public void keyPressed(KeyEvent e) {
  812               if (!e.isConsumed()) {
  813                   JComponent source = (JComponent) e.getComponent();
  814                   KeyStroke keyStrokeForEvent = KeyStroke.getKeyStrokeForEvent(e);
  815                   if (hideTip.equals(keyStrokeForEvent)) {
  816                       if (tipWindow != null) {
  817                           hide(source);
  818                           e.consume();
  819                       }
  820                   } else if (postTip.equals(keyStrokeForEvent)) {
  821                       // Shown tooltip will be hidden
  822                       ToolTipManager.this.show(source);
  823                       e.consume();
  824                   }
  825               }
  826           }
  827       }
  828   }

Home » openjdk-7 » javax » swing » [javadoc | source]