All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.alee.managers.tooltip.TooltipManager Maven / Gradle / Ivy

There is a newer version: 1.2.14
Show newest version
/*
 * This file is part of WebLookAndFeel library.
 *
 * WebLookAndFeel library is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * WebLookAndFeel library 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 for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with WebLookAndFeel library.  If not, see .
 */

package com.alee.managers.tooltip;

import com.alee.api.annotations.NotNull;
import com.alee.api.jdk.BiConsumer;
import com.alee.managers.glasspane.GlassPaneManager;
import com.alee.managers.glasspane.WebGlassPane;
import com.alee.managers.hotkey.Hotkey;
import com.alee.managers.hotkey.HotkeyData;
import com.alee.managers.hotkey.HotkeyManager;
import com.alee.managers.hotkey.HotkeyRunnable;
import com.alee.utils.CollectionUtils;
import com.alee.utils.CoreSwingUtils;
import com.alee.utils.swing.WeakComponentData;
import com.alee.utils.swing.WeakComponentDataList;
import com.alee.utils.swing.WebTimer;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.List;

/**
 * This manager allows you to set extended tooltips for any Swing component with any possible content (would it be simple text or some
 * JComponent ancestor) or show one-time tooltips at custom location inside any window.
 *
 * Also this manager is integrated with {@link HotkeyManager} to provide components hotkeys on their tooltips.
 *
 * @author Mikle Garin
 * @see com.alee.managers.glasspane.GlassPaneManager
 * @see com.alee.managers.hotkey.HotkeyManager
 */
public final class TooltipManager
{
    /**
     * todo 1. Cleanup methods and JavaDoc
     * todo 2. Separate mapping of listeners for each tooltip?
     */

    // Default settings
    private static int defaultDelay = 400;
    private static boolean allowMultipleTooltips = true;
    private static boolean showHotkeysInTooltips = true;
    private static boolean showHotkeysInOneTimeTooltips = false;

    // Standart tooltips
    private static final WeakComponentDataList webTooltips =
            new WeakComponentDataList ( "TooltipManager.WebCustomTooltip", 50 );
    private static final WeakComponentData adapters =
            new WeakComponentData ( "TooltipManager.MouseAdapter", 50 );
    private static final WeakComponentData timers =
            new WeakComponentData ( "TooltipManager.WebTimer", 50 );

    // One-time tooltips
    private static final List oneTimeTooltips = new ArrayList ();

    // Initialization mark
    private static boolean initialized = false;

    /**
     * TooltipManager initialization
     */

    public static synchronized void initialize ()
    {
        if ( !initialized )
        {
            initialized = true;

            // Tooltips hide listener
            Toolkit.getDefaultToolkit ().addAWTEventListener ( new AWTEventListener ()
            {
                @Override
                public void eventDispatched ( final AWTEvent event )
                {
                    if ( event instanceof MouseWheelEvent )
                    {
                        hideAllTooltips ();
                    }
                }
            }, AWTEvent.MOUSE_WHEEL_EVENT_MASK );
        }
    }

    /**
     * Hides all visible tooltips.
     */
    public static void hideAllTooltips ()
    {
        // Stopping any display timers
        timers.forEach ( new BiConsumer ()
        {
            @Override
            public void accept ( final JComponent component, final WebTimer webTimer )
            {
                webTimer.stop ();
            }
        } );

        // Hiding standart tooltips
        webTooltips.forEachData ( new BiConsumer ()
        {
            @Override
            public void accept ( final JComponent component, final WebCustomTooltip webCustomTooltip )
            {
                webCustomTooltip.closeTooltip ();
            }
        } );

        // Hiding one-time tooltips
        for ( final WebCustomTooltip tooltip : CollectionUtils.copy ( oneTimeTooltips ) )
        {
            tooltip.closeTooltip ();
        }
    }

    /**
     * Registers standart tooltip
     */

    public static WebCustomTooltip setTooltip ( final JComponent component, final String tooltip )
    {
        return setTooltip ( component, tooltip, null );
    }

    public static WebCustomTooltip setTooltip ( final JComponent component, final String tooltip, final int delay )
    {
        return setTooltip ( component, tooltip, null, delay );
    }

    public static WebCustomTooltip setTooltip ( final JComponent component, final Icon icon, final String tooltip )
    {
        return setTooltip ( component, icon, tooltip, null );
    }

    public static WebCustomTooltip setTooltip ( final JComponent component, final String tooltip, final TooltipWay tooltipWay )
    {
        return setTooltip ( component, tooltip, tooltipWay, defaultDelay );
    }

    public static WebCustomTooltip setTooltip ( final JComponent component, final Icon icon, final String tooltip,
                                                final TooltipWay tooltipWay )
    {
        return setTooltip ( component, icon, tooltip, tooltipWay, defaultDelay );
    }

    public static WebCustomTooltip setTooltip ( final JComponent component, final String tooltip, final TooltipWay tooltipWay,
                                                final int delay )
    {
        return setTooltip ( component, null, tooltip, tooltipWay, delay );
    }

    public static WebCustomTooltip setTooltip ( final JComponent component, final Icon icon, final String tooltip,
                                                final TooltipWay tooltipWay, final int delay )
    {
        return setTooltip ( component, WebCustomTooltip.createDefaultComponent ( icon, tooltip ), tooltipWay, delay );
    }

    public static WebCustomTooltip setTooltip ( final JComponent component, final JComponent tooltip )
    {
        return setTooltip ( component, tooltip, null );
    }

    public static WebCustomTooltip setTooltip ( final JComponent component, final JComponent tooltip, final int delay )
    {
        return setTooltip ( component, tooltip, null, delay );
    }

    public static WebCustomTooltip setTooltip ( final JComponent component, final JComponent tooltip, final TooltipWay tooltipWay )
    {
        return setTooltip ( component, tooltip, tooltipWay, defaultDelay );
    }

    public static WebCustomTooltip setTooltip ( final JComponent component, final JComponent tooltip, final TooltipWay tooltipWay,
                                                final int delay )
    {
        return addTooltip ( component, tooltip, tooltipWay, delay, true );
    }

    public static WebCustomTooltip addTooltip ( final JComponent component, final String tooltip )
    {
        return addTooltip ( component, tooltip, null );
    }

    public static WebCustomTooltip addTooltip ( final JComponent component, final String tooltip, final int delay )
    {
        return addTooltip ( component, tooltip, null, delay );
    }

    public static WebCustomTooltip addTooltip ( final JComponent component, final Icon icon, final String tooltip )
    {
        return addTooltip ( component, icon, tooltip, null );
    }

    public static WebCustomTooltip addTooltip ( final JComponent component, final String tooltip, final TooltipWay tooltipWay )
    {
        return addTooltip ( component, tooltip, tooltipWay, defaultDelay );
    }

    public static WebCustomTooltip addTooltip ( final JComponent component, final Icon icon, final String tooltip,
                                                final TooltipWay tooltipWay )
    {
        return addTooltip ( component, icon, tooltip, tooltipWay, defaultDelay );
    }

    public static WebCustomTooltip addTooltip ( final JComponent component, final String tooltip, final TooltipWay tooltipWay,
                                                final int delay )
    {
        return addTooltip ( component, null, tooltip, tooltipWay, delay );
    }

    public static WebCustomTooltip addTooltip ( final JComponent component, final Icon icon, final String tooltip,
                                                final TooltipWay tooltipWay, final int delay )
    {
        return addTooltip ( component, WebCustomTooltip.createDefaultComponent ( icon, tooltip ), tooltipWay, delay );
    }

    public static WebCustomTooltip addTooltip ( final JComponent component, final JComponent tooltip )
    {
        return addTooltip ( component, tooltip, null );
    }

    public static WebCustomTooltip addTooltip ( final JComponent component, final JComponent tooltip, final int delay )
    {
        return addTooltip ( component, tooltip, null, delay );
    }

    public static WebCustomTooltip addTooltip ( final JComponent component, final JComponent tooltip, final TooltipWay tooltipWay )
    {
        return addTooltip ( component, tooltip, tooltipWay, defaultDelay );
    }

    public static WebCustomTooltip addTooltip ( final JComponent component, final JComponent tooltip, final TooltipWay tooltipWay,
                                                final int delay )
    {
        final boolean clear = webTooltips.containsData ( component ) && !allowMultipleTooltips;
        return addTooltip ( component, tooltip, tooltipWay, delay, clear );
    }

    private static WebCustomTooltip addTooltip ( final JComponent component, final JComponent tooltip, final TooltipWay tooltipWay,
                                                 final int delay, final boolean clear )
    {
        // Erase old tooltips if more than one not allowed in this case
        if ( clear )
        {
            removeTooltips ( component );
        }

        // Creating tooltip component
        final WebCustomTooltip customTooltip = new WebCustomTooltip ( component, tooltip, tooltipWay, showHotkeysInTooltips );
        webTooltips.add ( component, customTooltip );

        // Creating listeners for component if they aren't created yet
        if ( !timers.contains ( component ) )
        {
            // Tooltip pop timer
            final WebTimer showTips = new WebTimer ( "TooltipManager.displayTimer", delay );
            showTips.addActionListener ( new ActionListener ()
            {
                @Override
                public void actionPerformed ( final ActionEvent e )
                {
                    final Window window = CoreSwingUtils.getWindowAncestor ( component );
                    if ( window != null && window.isShowing () )
                    {
                        showTooltips ( component, false );
                    }
                }
            } );
            showTips.setRepeats ( false );
            timers.set ( component, showTips );

            // Show/hide listener
            final MouseAdapter mouseAdapter = new MouseAdapter ()
            {
                @Override
                public void mouseEntered ( final MouseEvent e )
                {
                    displayTooltips ();
                }

                @Override
                public void mouseExited ( final MouseEvent e )
                {
                    cancelTooltips ();
                }

                @Override
                public void mousePressed ( final MouseEvent e )
                {
                    cancelTooltips ();
                }

                @Override
                public void mouseReleased ( final MouseEvent e )
                {
                    cancelTooltips ();
                }

                /**
                 * Startup tooltips display timer.
                 */
                private void displayTooltips ()
                {
                    final Window window = CoreSwingUtils.getWindowAncestor ( component );
                    if ( window != null && window.isShowing () )
                    {
                        showTips.start ();
                    }
                }

                /**
                 * Cancel timers and hide displayed tooltips.
                 */
                private void cancelTooltips ()
                {
                    showTips.stop ();
                    hideTooltips ( component );
                }
            };
            component.addMouseListener ( mouseAdapter );
            adapters.set ( component, mouseAdapter );
        }

        return customTooltip;
    }

    private static void hideTooltips ( final JComponent component )
    {
        if ( webTooltips.get ( component ) != null )
        {
            final List tooltips = new ArrayList ();
            tooltips.addAll ( webTooltips.get ( component ) );
            for ( final WebCustomTooltip tooltip : tooltips )
            {
                tooltip.closeTooltip ();
            }
        }
    }

    /**
     * Displays component tooltips
     */

    public static boolean showTooltips ( final JComponent component )
    {
        return showTooltips ( component, false );
    }

    public static boolean showTooltips ( final JComponent component, final boolean delayed )
    {
        if ( webTooltips.contains ( component ) && component.isShowing () )
        {
            if ( delayed )
            {
                timers.get ( component ).restart ();
            }
            else
            {
                final WebGlassPane webGlassPane = GlassPaneManager.getGlassPane ( component );
                if ( webGlassPane != null )
                {
                    webTooltips.forEachData ( component, new BiConsumer ()
                    {
                        @Override
                        public void accept ( final JComponent component, final WebCustomTooltip webCustomTooltip )
                        {
                            webGlassPane.showComponent ( webCustomTooltip );
                        }
                    } );
                }
            }
            return true;
        }
        else
        {
            return false;
        }
    }

    /**
     * Displays all tooltips for component's window
     */

    public static void showAllTooltips ( final JComponent component )
    {
        // Hiding all tooltips
        TooltipManager.hideAllTooltips ();

        // Displaying tooltips
        showAllTooltips ( CoreSwingUtils.getNonNullWindowAncestor ( component ) );
    }

    private static void showAllTooltips ( final Window window )
    {
        if ( window.isShowing () )
        {
            webTooltips.forEachData ( new BiConsumer ()
            {
                @Override
                public void accept ( final JComponent component, final WebCustomTooltip webCustomTooltip )
                {
                    if ( CoreSwingUtils.getWindowAncestor ( component ) == window && component.isShowing () )
                    {
                        showOneTimeTooltip ( webCustomTooltip, false );
                    }
                }
            } );
        }
    }

    /**
     * Displays all tooltips for all visible windows
     */

    public static void showAllTooltips ()
    {
        webTooltips.forEachData ( new BiConsumer ()
        {
            @Override
            public void accept ( final JComponent component, final WebCustomTooltip webCustomTooltip )
            {
                if ( component.isShowing () )
                {
                    showOneTimeTooltip ( webCustomTooltip, false );
                }
            }
        } );
    }

    /**
     * Installs "show all hotkeys" action on window or component
     */

    public static void installShowAllTooltipsAction ( final JComponent topComponent )
    {
        installShowAllTooltipsAction ( topComponent, Hotkey.F2 );
    }

    public static void installShowAllTooltipsAction ( final JComponent topComponent, final HotkeyData hotkeyData )
    {
        HotkeyManager.registerHotkey ( topComponent, hotkeyData, new HotkeyRunnable ()
        {
            @Override
            public void run ( @NotNull final KeyEvent e )
            {
                showAllTooltips ( topComponent );
            }
        }, true );
    }

    /**
     * Removes component tooltips
     */

    public static void removeTooltips ( final JComponent component )
    {
        if ( webTooltips.get ( component ) != null )
        {
            for ( final WebCustomTooltip tooltip : CollectionUtils.copy ( webTooltips.get ( component ) ) )
            {
                removeTooltip ( component, tooltip );
            }
        }
    }

    public static void removeTooltips ( final JComponent component, final WebCustomTooltip... tooltips )
    {
        for ( final WebCustomTooltip tooltip : tooltips )
        {
            removeTooltip ( component, tooltip );
        }
    }

    public static void removeTooltips ( final JComponent component, final List tooltips )
    {
        for ( final WebCustomTooltip tooltip : tooltips )
        {
            removeTooltip ( component, tooltip );
        }
    }

    public static void removeTooltip ( final JComponent component, final WebCustomTooltip tooltip )
    {
        webTooltips.remove ( component, tooltip, new BiConsumer ()
        {
            @Override
            public void accept ( final JComponent component, final WebCustomTooltip webCustomTooltip )
            {
                // Removing all listeners in case its last component tooltip
                if ( webTooltips.size ( component ) <= 1 )
                {
                    // Removing mouse listeners
                    adapters.clear ( component, new BiConsumer ()
                    {
                        @Override
                        public void accept ( final JComponent component, final MouseAdapter mouseAdapter )
                        {
                            component.removeMouseListener ( mouseAdapter );
                        }
                    } );

                    // Clearing timers
                    timers.clear ( component, new BiConsumer ()
                    {
                        @Override
                        public void accept ( final JComponent component, final WebTimer webTimer )
                        {
                            webTimer.stop ();
                        }
                    } );
                }

                // Hiding and destroying tooltip
                webCustomTooltip.closeTooltip ();
                webCustomTooltip.destroyTooltip ();
            }
        } );
    }

    /**
     * Shows one-time tooltip
     */

    public static WebCustomTooltip showOneTimeTooltip ( final JComponent component, final Point point, final String tooltip )
    {
        return showOneTimeTooltip ( component, point, tooltip, null );
    }

    public static WebCustomTooltip showOneTimeTooltip ( final JComponent component, final Point point, final Icon icon,
                                                        final String tooltip )
    {
        return showOneTimeTooltip ( component, point, icon, tooltip, null );
    }

    public static WebCustomTooltip showOneTimeTooltip ( final JComponent component, final Point point, final String tooltip,
                                                        final TooltipWay tooltipWay )
    {
        return showOneTimeTooltip ( component, point, null, tooltip, tooltipWay );
    }

    public static WebCustomTooltip showOneTimeTooltip ( final JComponent component, final Point point, final Icon icon,
                                                        final String tooltip,
                                                        final TooltipWay tooltipWay )
    {
        final WebCustomTooltip customTooltip = new WebCustomTooltip ( component, icon, tooltip, tooltipWay, showHotkeysInOneTimeTooltips );
        customTooltip.setDisplayLocation ( point );
        return showOneTimeTooltip ( customTooltip, true );
    }

    public static WebCustomTooltip showOneTimeTooltip ( final JComponent component, final Point point, final JComponent tooltip )
    {
        return showOneTimeTooltip ( component, point, tooltip, null );
    }

    public static WebCustomTooltip showOneTimeTooltip ( final JComponent component, final Point point, final JComponent tooltip,
                                                        final TooltipWay tooltipWay )
    {
        final WebCustomTooltip customTooltip = new WebCustomTooltip ( component, tooltip, tooltipWay, showHotkeysInOneTimeTooltips );
        customTooltip.setDisplayLocation ( point );
        return showOneTimeTooltip ( customTooltip, true );
    }

    public static WebCustomTooltip showOneTimeTooltip ( final WebCustomTooltip customTooltip )
    {
        return showOneTimeTooltip ( customTooltip, true );
    }

    private static WebCustomTooltip showOneTimeTooltip ( final WebCustomTooltip customTooltip, final boolean destroyOnClose )
    {
        // Checking if component is properly set and showing
        if ( customTooltip.getComponent () == null || !customTooltip.getComponent ().isShowing () )
        {
            return null;
        }

        // Checking if glass pane is available
        final WebGlassPane webGlassPane = GlassPaneManager.getGlassPane ( customTooltip.getComponent () );

        // Adding relocate listener
        final ComponentAdapter componentAdapter = new ComponentAdapter ()
        {
            @Override
            public void componentResized ( final ComponentEvent e )
            {
                customTooltip.updateLocation ();
            }
        };
        webGlassPane.addComponentListener ( componentAdapter );

        // Global mouse listener
        final AWTEventListener closeListener = customTooltip.isDefaultCloseBehavior () ? new AWTEventListener ()
        {
            @Override
            public void eventDispatched ( final AWTEvent event )
            {
                if ( event instanceof MouseEvent && event.getID () == MouseEvent.MOUSE_PRESSED )
                {
                    customTooltip.closeTooltip ();
                }
            }
        } : null;

        // Adding destroy sequence
        customTooltip.addTooltipListener ( new TooltipAdapter ()
        {
            @Override
            public void tooltipShowing ()
            {
                if ( customTooltip.isDefaultCloseBehavior () )
                {
                    // Mouse press listener to close one-time tooltip
                    Toolkit.getDefaultToolkit ().addAWTEventListener ( closeListener, AWTEvent.MOUSE_EVENT_MASK );
                }
            }

            @Override
            public void tooltipHidden ()
            {
                // Removing tooltip listener
                customTooltip.removeTooltipListener ( this );

                if ( customTooltip.isDefaultCloseBehavior () )
                {
                    // Removing press listener
                    Toolkit.getDefaultToolkit ().removeAWTEventListener ( closeListener );
                }

                // Removing tooltip from list
                oneTimeTooltips.remove ( customTooltip );

                // Removing relocation listener
                webGlassPane.removeComponentListener ( componentAdapter );

                if ( destroyOnClose )
                {
                    // Destroying tooltip
                    customTooltip.destroyTooltip ();
                }
            }
        } );

        // Registering one-time tooltip
        oneTimeTooltips.add ( customTooltip );

        // Displaying one-time tooltip
        webGlassPane.showComponent ( customTooltip );

        return customTooltip;
    }

    /**
     * Default tooltip show delay
     */

    public static int getDefaultDelay ()
    {
        return defaultDelay;
    }

    public static void setDefaultDelay ( final int delay )
    {
        defaultDelay = delay;
    }

    /**
     * Allow more than one tooltip per component
     */

    public static boolean isAllowMultipleTooltips ()
    {
        return allowMultipleTooltips;
    }

    public static void setAllowMultipleTooltips ( final boolean allowMultipleTooltips )
    {
        TooltipManager.allowMultipleTooltips = allowMultipleTooltips;
    }

    /**
     * Show hotkeys in tooltips by default
     */

    public static boolean isShowHotkeysInTooltips ()
    {
        return showHotkeysInTooltips;
    }

    public static void setShowHotkeysInTooltips ( final boolean showHotkeysInTooltips )
    {
        TooltipManager.showHotkeysInTooltips = showHotkeysInTooltips;
    }

    /**
     * Show hotkeys in one-time tooltips by default
     */

    public static boolean isShowHotkeysInOneTimeTooltips ()
    {
        return showHotkeysInOneTimeTooltips;
    }

    public static void setShowHotkeysInOneTimeTooltips ( final boolean showHotkeysInOneTimeTooltips )
    {
        TooltipManager.showHotkeysInOneTimeTooltips = showHotkeysInOneTimeTooltips;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy