828 lines · 29.5 KB · Java
RawDownload
/* * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */  package javax.swing; import java.awt.event.*;import java.awt.*; /** * Manages all the <code>ToolTips</code> in the system. * <p> * ToolTipManager contains numerous properties for configuring how long it * will take for the tooltips to become visible, and how long till they * hide. Consider a component that has a different tooltip based on where * the mouse is, such as JTree. When the mouse moves into the JTree and * over a region that has a valid tooltip, the tooltip will become * visibile after <code>initialDelay</code> milliseconds. After * <code>dismissDelay</code> milliseconds the tooltip will be hidden. If * the mouse is over a region that has a valid tooltip, and the tooltip * is currently visible, when the mouse moves to a region that doesn't have * a valid tooltip the tooltip will be hidden. If the mouse then moves back * into a region that has a valid tooltip within <code>reshowDelay</code> * milliseconds, the tooltip will immediately be shown, otherwise the * tooltip will be shown again after <code>initialDelay</code> milliseconds. * * @see JComponent#createToolTip * @author Dave Moore * @author Rich Schiavi */public class ToolTipManager extends MouseAdapter implements MouseMotionListener  {    Timer enterTimer, exitTimer, insideTimer;    String toolTipText;    Point  preferredLocation;    JComponent insideComponent;    MouseEvent mouseEvent;    boolean showImmediately;    private static final Object TOOL_TIP_MANAGER_KEY = new Object();    transient Popup tipWindow;    /** The Window tip is being displayed in. This will be non-null if     * the Window tip is in differs from that of insideComponent's Window.     */    private Window window;    JToolTip tip;     private Rectangle popupRect = null;    private Rectangle popupFrameRect = null;     boolean enabled = true;    private boolean tipShowing = false;     private FocusListener focusChangeListener = null;    private MouseMotionListener moveBeforeEnterListener = null;    private KeyListener accessibilityKeyListener = null;     private KeyStroke postTip;    private KeyStroke hideTip;     // PENDING(ges)    protected boolean lightWeightPopupEnabled = true;    protected boolean heavyWeightPopupEnabled = false;     ToolTipManager() {        enterTimer = new Timer(750, new insideTimerAction());        enterTimer.setRepeats(false);        exitTimer = new Timer(500, new outsideTimerAction());        exitTimer.setRepeats(false);        insideTimer = new Timer(4000, new stillInsideTimerAction());        insideTimer.setRepeats(false);         moveBeforeEnterListener = new MoveBeforeEnterListener();        accessibilityKeyListener = new AccessibilityKeyListener();         postTip = KeyStroke.getKeyStroke(KeyEvent.VK_F1, InputEvent.CTRL_MASK);        hideTip =  KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);    }     /**     * Enables or disables the tooltip.     *     * @param flag  true to enable the tip, false otherwise     */    public void setEnabled(boolean flag) {        enabled = flag;        if (!flag) {            hideTipWindow();        }    }     /**     * Returns true if this object is enabled.     *     * @return true if this object is enabled, false otherwise     */    public boolean isEnabled() {        return enabled;    }     /**     * When displaying the <code>JToolTip</code>, the     * <code>ToolTipManager</code> chooses to use a lightweight     * <code>JPanel</code> if it fits. This method allows you to     * disable this feature. You have to do disable it if your     * application mixes light weight and heavy weights components.     *     * @param aFlag true if a lightweight panel is desired, false otherwise     *     */    public void setLightWeightPopupEnabled(boolean aFlag){        lightWeightPopupEnabled = aFlag;    }     /**     * Returns true if lightweight (all-Java) <code>Tooltips</code>     * are in use, or false if heavyweight (native peer)     * <code>Tooltips</code> are being used.     *     * @return true if lightweight <code>ToolTips</code> are in use     */    public boolean isLightWeightPopupEnabled() {        return lightWeightPopupEnabled;    }      /**     * Specifies the initial delay value.     *     * @param milliseconds  the number of milliseconds to delay     *        (after the cursor has paused) before displaying the     *        tooltip     * @see #getInitialDelay     */    public void setInitialDelay(int milliseconds) {        enterTimer.setInitialDelay(milliseconds);    }     /**     * Returns the initial delay value.     *     * @return an integer representing the initial delay value,     *          in milliseconds     * @see #setInitialDelay     */    public int getInitialDelay() {        return enterTimer.getInitialDelay();    }     /**     * Specifies the dismissal delay value.     *     * @param milliseconds  the number of milliseconds to delay     *        before taking away the tooltip     * @see #getDismissDelay     */    public void setDismissDelay(int milliseconds) {        insideTimer.setInitialDelay(milliseconds);    }     /**     * Returns the dismissal delay value.     *     * @return an integer representing the dismissal delay value,     *          in milliseconds     * @see #setDismissDelay     */    public int getDismissDelay() {        return insideTimer.getInitialDelay();    }     /**     * Used to specify the amount of time before the user has to wait     * <code>initialDelay</code> milliseconds before a tooltip will be     * shown. That is, if the tooltip is hidden, and the user moves into     * a region of the same Component that has a valid tooltip within     * <code>milliseconds</code> milliseconds the tooltip will immediately     * be shown. Otherwise, if the user moves into a region with a valid     * tooltip after <code>milliseconds</code> milliseconds, the user     * will have to wait an additional <code>initialDelay</code>     * milliseconds before the tooltip is shown again.     *     * @param milliseconds time in milliseconds     * @see #getReshowDelay     */    public void setReshowDelay(int milliseconds) {        exitTimer.setInitialDelay(milliseconds);    }     /**     * Returns the reshow delay property.     *     * @return reshown delay property     * @see #setReshowDelay     */    public int getReshowDelay() {        return exitTimer.getInitialDelay();    }     void showTipWindow() {        if(insideComponent == null || !insideComponent.isShowing())            return;        String mode = UIManager.getString("ToolTipManager.enableToolTipMode");        if ("activeApplication".equals(mode)) {            KeyboardFocusManager kfm =                    KeyboardFocusManager.getCurrentKeyboardFocusManager();            if (kfm.getFocusedWindow() == null) {                return;            }        }        if (enabled) {            Dimension size;            Point screenLocation = insideComponent.getLocationOnScreen();            Point location = new Point();            GraphicsConfiguration gc;            gc = insideComponent.getGraphicsConfiguration();            Rectangle sBounds = gc.getBounds();            Insets screenInsets = Toolkit.getDefaultToolkit()                                             .getScreenInsets(gc);            // Take into account screen insets, decrease viewport            sBounds.x += screenInsets.left;            sBounds.y += screenInsets.top;            sBounds.width -= (screenInsets.left + screenInsets.right);            sBounds.height -= (screenInsets.top + screenInsets.bottom);        boolean leftToRight                = SwingUtilities.isLeftToRight(insideComponent);             // Just to be paranoid            hideTipWindow();             tip = insideComponent.createToolTip();            tip.setTipText(toolTipText);            size = tip.getPreferredSize();             if(preferredLocation != null) {                location.x = screenLocation.x + preferredLocation.x;                location.y = screenLocation.y + preferredLocation.y;        if (!leftToRight) {            location.x -= size.width;        }            } else {                location.x = screenLocation.x + mouseEvent.getX();                location.y = screenLocation.y + mouseEvent.getY() + 20;        if (!leftToRight) {            if(location.x - size.width>=0) {                location.x -= size.width;            }        }             }         // we do not adjust x/y when using awt.Window tips        if (popupRect == null){        popupRect = new Rectangle();        }        popupRect.setBounds(location.x,location.y,                size.width,size.height);         // Fit as much of the tooltip on screen as possible            if (location.x < sBounds.x) {                location.x = sBounds.x;            }            else if (location.x - sBounds.x + size.width > sBounds.width) {                location.x = sBounds.x + Math.max(0, sBounds.width - size.width);            }            if (location.y < sBounds.y) {                location.y = sBounds.y;            }            else if (location.y - sBounds.y + size.height > sBounds.height) {                location.y = sBounds.y + Math.max(0, sBounds.height - size.height);            }             PopupFactory popupFactory = PopupFactory.getSharedInstance();             if (lightWeightPopupEnabled) {        int y = getPopupFitHeight(popupRect, insideComponent);        int x = getPopupFitWidth(popupRect,insideComponent);        if (x>0 || y>0) {            popupFactory.setPopupType(PopupFactory.MEDIUM_WEIGHT_POPUP);        } else {            popupFactory.setPopupType(PopupFactory.LIGHT_WEIGHT_POPUP);        }            }            else {                popupFactory.setPopupType(PopupFactory.MEDIUM_WEIGHT_POPUP);            }        tipWindow = popupFactory.getPopup(insideComponent, tip,                          location.x,                          location.y);            popupFactory.setPopupType(PopupFactory.LIGHT_WEIGHT_POPUP);         tipWindow.show();             Window componentWindow = SwingUtilities.windowForComponent(                                                    insideComponent);             window = SwingUtilities.windowForComponent(tip);            if (window != null && window != componentWindow) {                window.addMouseListener(this);            }            else {                window = null;            }             insideTimer.start();        tipShowing = true;        }    }     void hideTipWindow() {        if (tipWindow != null) {            if (window != null) {                window.removeMouseListener(this);                window = null;            }            tipWindow.hide();            tipWindow = null;            tipShowing = false;            tip = null;            insideTimer.stop();        }    }     /**     * Returns a shared <code>ToolTipManager</code> instance.     *     * @return a shared <code>ToolTipManager</code> object     */    public static ToolTipManager sharedInstance() {        Object value = SwingUtilities.appContextGet(TOOL_TIP_MANAGER_KEY);        if (value instanceof ToolTipManager) {            return (ToolTipManager) value;        }        ToolTipManager manager = new ToolTipManager();        SwingUtilities.appContextPut(TOOL_TIP_MANAGER_KEY, manager);        return manager;    }     // add keylistener here to trigger tip for access    /**     * Registers a component for tooltip management.     * <p>     * This will register key bindings to show and hide the tooltip text     * only if <code>component</code> has focus bindings. This is done     * so that components that are not normally focus traversable, such     * as <code>JLabel</code>, are not made focus traversable as a result     * of invoking this method.     *     * @param component  a <code>JComponent</code> object to add     * @see JComponent#isFocusTraversable     */    public void registerComponent(JComponent component) {        component.removeMouseListener(this);        component.addMouseListener(this);        component.removeMouseMotionListener(moveBeforeEnterListener);        component.addMouseMotionListener(moveBeforeEnterListener);        component.removeKeyListener(accessibilityKeyListener);        component.addKeyListener(accessibilityKeyListener);    }     /**     * Removes a component from tooltip control.     *     * @param component  a <code>JComponent</code> object to remove     */    public void unregisterComponent(JComponent component) {        component.removeMouseListener(this);        component.removeMouseMotionListener(moveBeforeEnterListener);        component.removeKeyListener(accessibilityKeyListener);    }     // implements java.awt.event.MouseListener    /**     *  Called when the mouse enters the region of a component.     *  This determines whether the tool tip should be shown.     *     *  @param event  the event in question     */    public void mouseEntered(MouseEvent event) {        initiateToolTip(event);    }     private void initiateToolTip(MouseEvent event) {        if (event.getSource() == window) {            return;        }        JComponent component = (JComponent)event.getSource();        component.removeMouseMotionListener(moveBeforeEnterListener);         exitTimer.stop();         Point location = event.getPoint();        // ensure tooltip shows only in proper place        if (location.x < 0 ||            location.x >=component.getWidth() ||            location.y < 0 ||            location.y >= component.getHeight()) {            return;        }         if (insideComponent != null) {            enterTimer.stop();        }        // A component in an unactive internal frame is sent two        // mouseEntered events, make sure we don't end up adding        // ourselves an extra time.        component.removeMouseMotionListener(this);        component.addMouseMotionListener(this);         boolean sameComponent = (insideComponent == component);         insideComponent = component;    if (tipWindow != null){            mouseEvent = event;            if (showImmediately) {                String newToolTipText = component.getToolTipText(event);                Point newPreferredLocation = component.getToolTipLocation(                                                         event);                boolean sameLoc = (preferredLocation != null) ?                            preferredLocation.equals(newPreferredLocation) :                            (newPreferredLocation == null);                 if (!sameComponent || !toolTipText.equals(newToolTipText) ||                         !sameLoc) {                    toolTipText = newToolTipText;                    preferredLocation = newPreferredLocation;                    showTipWindow();                }            } else {                enterTimer.start();            }        }    }     // implements java.awt.event.MouseListener    /**     *  Called when the mouse exits the region of a component.     *  Any tool tip showing should be hidden.     *     *  @param event  the event in question     */    public void mouseExited(MouseEvent event) {        boolean shouldHide = true;        if (insideComponent == null) {            // Drag exit        }        if (window != null && event.getSource() == window && insideComponent != null) {          // if we get an exit and have a heavy window          // we need to check if it if overlapping the inside component            Container insideComponentWindow = insideComponent.getTopLevelAncestor();            // insideComponent may be removed after tooltip is made visible            if (insideComponentWindow != null) {                Point location = event.getPoint();                SwingUtilities.convertPointToScreen(location, window);                 location.x -= insideComponentWindow.getX();                location.y -= insideComponentWindow.getY();                 location = SwingUtilities.convertPoint(null, location, insideComponent);                if (location.x >= 0 && location.x < insideComponent.getWidth() &&                        location.y >= 0 && location.y < insideComponent.getHeight()) {                    shouldHide = false;                } else {                    shouldHide = true;                }            }        } else if(event.getSource() == insideComponent && tipWindow != null) {            Window win = SwingUtilities.getWindowAncestor(insideComponent);            if (win != null) {  // insideComponent may have been hidden (e.g. in a menu)                Point location = SwingUtilities.convertPoint(insideComponent,                                                             event.getPoint(),                                                             win);                Rectangle bounds = insideComponent.getTopLevelAncestor().getBounds();                location.x += bounds.x;                location.y += bounds.y;                 Point loc = new Point(0, 0);                SwingUtilities.convertPointToScreen(loc, tip);                bounds.x = loc.x;

Lines 1–500 of 828.