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

com.alee.managers.language.UILanguageManager Maven / Gradle / Ivy

/*
 * 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.language;

import com.alee.api.jdk.BiConsumer;
import com.alee.api.jdk.Objects;
import com.alee.managers.language.data.Dictionary;
import com.alee.managers.language.updaters.*;
import com.alee.utils.ArrayUtils;
import com.alee.utils.SwingUtils;
import com.alee.utils.swing.WeakComponentData;
import com.alee.utils.swing.WeakComponentDataList;

import javax.swing.*;
import java.awt.*;
import java.net.URL;
import java.util.*;
import java.util.List;

/**
 * {@link UILanguageManager} is an extension over {@link LanguageManager} that offers extensive Swing components translation support.
 * {@link UILanguageManager} provides various ways of translating components that are registered within this manager and also dynamically
 * updating their translation upon {@link Language} or {@link Dictionary} changes.
 *
 * @author Mikle Garin
 * @see How to use LanguageManager
 * @see LanguageManager
 * @see Language
 * @see Dictionary
 * @see LanguageUpdater
 */
public final class UILanguageManager
{
    /**
     * Unknown {@link Locale} icon.
     * todo Move into {@link com.alee.managers.icon.IconManager}
     *
     * @see #getLocaleIcon(Locale)
     */
    private static final ImageIcon UNKNOWN_LANGUAGE = new ImageIcon ( UILanguageManager.class.getResource ( "icons/unknown.png" ) );

    /**
     * {@link Locale} icons.
     *
     * Supported icons can be loaded without any effort as they are included in WebLaF library:
     * - {@link #getLanguageIcon(Language)}
     * - {@link #getLocaleIcon(Locale)}
     *
     * Custom icons can be provided from the code using either of two methods:
     * - {@link #setLanguageIcon(Language, Icon)}
     * - {@link #setLocaleIcon(Locale, Icon)}
     *
     * @see #getLanguageIcon(Language)
     * @see #getLocaleIcon(Locale)
     * @see #setLanguageIcon(Language, Icon)
     * @see #setLocaleIcon(Locale, Icon)
     */
    private static final Map localeIcons = new HashMap ();

    /**
     * Whether or not text-containing components should check passed text for translation or not.
     * This mostly affects only extended components like {@link com.alee.laf.label.WebLabel} or {@link com.alee.laf.button.WebButton}.
     */
    private static boolean checkComponentsTextForTranslations;

    /**
     * Components registered for auto-translation.
     * Specific implementations of LanguageUpdater interface used to translate them.
     *
     * @see #registerComponent(JComponent, String, Object...)
     * @see #updateComponent(JComponent, Object...)
     * @see #updateComponent(JComponent, String, Object...)
     * @see #unregisterComponent(JComponent)
     * @see #isRegisteredComponent(JComponent)
     */
    private static final WeakComponentData components =
            new WeakComponentData ( "WebLanguageManager.TranslationKey", 100 );

    /**
     * Special comparator for sorting LanguageUpdaters list.
     */
    private static final LanguageUpdaterComparator languageUpdaterComparator = new LanguageUpdaterComparator ();

    /**
     * Registered language updaters.
     * Language updaters are used to automatically update specific components translation when language changes occur.
     *
     * @see LanguageUpdater
     * @see #registerLanguageUpdater(LanguageUpdater)
     * @see #unregisterLanguageUpdater(LanguageUpdater)
     * @see #getLanguageUpdater(JComponent)
     */
    private static final List updaters = new ArrayList ( 20 );

    /**
     * Component-specific language updaters.
     * These are used only for the components they are bound to.
     *
     * @see LanguageUpdater
     * @see #registerLanguageUpdater(JComponent, LanguageUpdater)
     * @see #unregisterLanguageUpdater(JComponent)
     * @see #getLanguageUpdater(JComponent)
     */
    private static final WeakComponentData customUpdaters =
            new WeakComponentData ( "WebLanguageManager.LanguageUpdater", 2 );

    /**
     * {@link LanguageUpdater}s cached by specific class types.
     * Used to improve {@link LanguageUpdater} retrieval speed for language requests.
     * This cache gets fully updated when any {@link LanguageUpdater} is added or removed.
     *
     * @see LanguageUpdater
     * @see #getLanguageUpdater(JComponent)
     * @see #getLanguageUpdater(Class)
     */
    private static final Map updatersCache = new HashMap ();

    /**
     * {@link LanguageListener}s registered for specified {@link JComponent}s.
     *
     * @see LanguageListener
     * @see #addLanguageListener(JComponent, LanguageListener)
     * @see #removeLanguageListener(JComponent, LanguageListener)
     * @see #removeLanguageListeners(JComponent)
     */
    private static final WeakComponentDataList componentLanguageListeners =
            new WeakComponentDataList ( "WebLanguageManager.LanguageListener", 50 );

    /**
     * {@link DictionaryListener}s registered for specified {@link JComponent}s.
     *
     * @see DictionaryListener
     * @see #addDictionaryListener(JComponent, DictionaryListener)
     * @see #removeDictionaryListener(JComponent, DictionaryListener)
     * @see #removeDictionaryListeners(JComponent)
     */
    private static final WeakComponentDataList componentDictionaryListeners =
            new WeakComponentDataList ( "WebLanguageManager.LanguageListener", 5 );

    /**
     * Manager initialization mark.
     */
    private static boolean initialized = false;

    /**
     * Initializes LanguageManager settings.
     */
    public static synchronized void initialize ()
    {
        if ( !initialized )
        {
            // Initializing LanguageManager if it is not yet initialized
            LanguageManager.initialize ();

            // Initializing default settings
            setCheckComponentsTextForTranslations ( true );

            // Marking initialized
            initialized = true;

            // Basic language updaters
            registerLanguageUpdater ( new ToolTipLU () );
            registerLanguageUpdater ( new JLabelLU () );
            registerLanguageUpdater ( new AbstractButtonLU () );
            registerLanguageUpdater ( new JTextComponentLU () );
            registerLanguageUpdater ( new JTabbedPaneLU () );
            registerLanguageUpdater ( new JProgressBarLU () );
            registerLanguageUpdater ( new JFileChooserLU () );
            registerLanguageUpdater ( new JRootPaneLU () );
            registerLanguageUpdater ( new JInternalFrameLU () );
            registerLanguageUpdater ( new WebFileDropLU () );
            registerLanguageUpdater ( new WebCollapsiblePaneLU () );
            registerLanguageUpdater ( new WebDockableFrameLU () );

            // Special language updates
            registerLanguageUpdater ( new SwingToolTipLanguage () );
            registerLanguageUpdater ( new CustomToolTipLanguage () );

            // Default type of tooltips added from translations
            AbstractToolTipLanguage.setDefaultToolTipType ( CustomToolTipLanguage.TYPE );

            // Language listener for components update
            LanguageManager.addLanguageListener ( new LanguageListener ()
            {
                @Override
                public void languageChanged ( final Language oldLanguage, final Language newLanguage )
                {
                    // Updating components orientation
                    final ComponentOrientation oo = ComponentOrientation.getOrientation ( oldLanguage.getLocale () );
                    final ComponentOrientation no = ComponentOrientation.getOrientation ( newLanguage.getLocale () );
                    if ( oo.isLeftToRight () != no.isLeftToRight () )
                    {
                        SwingUtils.updateGlobalOrientation ();
                    }

                    // Updating registered components
                    updateComponents ();

                    // Informing listeners tied to components
                    fireLanguageChanged ( oldLanguage, newLanguage );
                }
            } );
            LanguageManager.addDictionaryListener ( new DictionaryListener ()
            {
                @Override
                public void dictionaryAdded ( final Dictionary dictionary )
                {
                    // Updating relevant components
                    updateComponents ( dictionary.getKeys () );

                    // Informing listeners tied to components
                    fireDictionaryAdded ( dictionary );
                }

                @Override
                public void dictionaryRemoved ( final Dictionary dictionary )
                {
                    // Updating relevant components
                    updateComponents ( dictionary.getKeys () );

                    // Informing listeners tied to components
                    fireDictionaryRemoved ( dictionary );
                }

                @Override
                public void dictionariesCleared ()
                {
                    // Updating registered components
                    updateComponents ();

                    // Informing listeners tied to components
                    fireDictionariesCleared ();
                }
            } );

            // Default WebLaF dictionary
            LanguageManager.addDictionary ( new Dictionary ( UILanguageManager.class, "resources/ui-language.xml" ) );
        }
    }

    /**
     * Throws {@link LanguageException} if manager is not yet initialized.
     *
     * @throws LanguageException if manager is not yet initialized
     */
    private static void mustBeInitialized () throws LanguageException
    {
        if ( !initialized )
        {
            throw new LanguageException ( "WebLanguageManager must be initialized first" );
        }
    }

    /**
     * Returns whether or not text-containing components should check passed text for translation or not.
     *
     * @return {@code true} if text-containing components should check passed text for translation, {@code false} otherwise
     */
    public static boolean isCheckComponentsTextForTranslations ()
    {
        return checkComponentsTextForTranslations;
    }

    /**
     * Sets whether or not text-containing components should check passed text for translation or not.
     *
     * @param check whether or not text-containing components should check passed text for translation or not
     */
    public static void setCheckComponentsTextForTranslations ( final boolean check )
    {
        checkComponentsTextForTranslations = check;
    }

    /**
     * Returns {@link Icon} for the specified {@link Language}.
     * By default there are {@link Icon}s only for languages supported by WebLaF.
     *
     * @param language language to retrieve {@link Icon} for
     * @return {@link Icon} for the specified {@link Language}
     */
    public static Icon getLanguageIcon ( final Language language )
    {
        return getLocaleIcon ( language.getLocale () );
    }

    /**
     * Returns {@link Icon} for the specified {@link Locale}.
     * By default there are {@link Icon}s only for languages supported by WebLaF.
     *
     * @param locale {@link Locale} to retrieve {@link Icon} for
     * @return {@link Icon} for the specified {@link Locale}
     */
    public static Icon getLocaleIcon ( final Locale locale )
    {
        final String key = LanguageUtils.toString ( locale );
        if ( localeIcons.containsKey ( key ) )
        {
            return localeIcons.get ( key );
        }
        else
        {
            ImageIcon icon;
            try
            {
                URL res = UILanguageManager.class.getResource ( "icons/" + key + ".png" );
                if ( res == null )
                {
                    res = UILanguageManager.class.getResource ( "icons/" + locale.getLanguage () + ".png" );
                }
                icon = new ImageIcon ( res );
            }
            catch ( final Exception e )
            {
                icon = UNKNOWN_LANGUAGE;
            }
            localeIcons.put ( key, icon );
            return icon;
        }
    }

    /**
     * Sets {@link Icon} for the specified {@link Language}.
     *
     * @param language {@link Language} to set {@link Icon} for
     * @param icon     {@link Icon}
     * @return {@link Icon} previously set for this {@link Language}
     */
    public static Icon setLanguageIcon ( final Language language, final Icon icon )
    {
        return setLocaleIcon ( language.getLocale (), icon );
    }

    /**
     * Sets {@link Icon} for the specified {@link Locale}.
     *
     * @param locale {@link Locale} to set {@link Icon} for
     * @param icon   {@link Icon}
     * @return {@link Icon} previously set for this {@link Locale}
     */
    public static Icon setLocaleIcon ( final Locale locale, final Icon icon )
    {
        final String key = LanguageUtils.toString ( locale );
        return localeIcons.put ( key, icon );
    }

    /**
     * Register custom {@link LanguageUpdater}.
     * Each {@link LanguageUpdater} is tied to a certain component class and can perform language updates only for that component type.
     *
     * @param updater new {@link LanguageUpdater}
     * @see LanguageUpdater
     */
    public static void registerLanguageUpdater ( final LanguageUpdater updater )
    {
        synchronized ( updaters )
        {
            // Removing LanguageUpdater for same class if exists
            final Iterator iterator = updaters.iterator ();
            while ( iterator.hasNext () )
            {
                if ( updater.getComponentClass () == iterator.next ().getComponentClass () )
                {
                    iterator.remove ();
                }
            }

            // Adding LanguageUpdater
            updaters.add ( updater );
            updatersCache.clear ();
        }
    }

    /**
     * Unregister custom {@link LanguageUpdater}.
     *
     * @param updater {@link LanguageUpdater} to unregister
     */
    public static void unregisterLanguageUpdater ( final LanguageUpdater updater )
    {
        synchronized ( updaters )
        {
            // Removing LanguageUpdater
            updaters.remove ( updater );
            updatersCache.clear ();
        }
    }

    /**
     * Registers custom {@link LanguageUpdater} for specific {@link JComponent}.
     *
     * @param component {@link JComponent} to register {@link LanguageUpdater} for
     * @param updater   custom {@link LanguageUpdater}
     */
    public static void registerLanguageUpdater ( final JComponent component, final LanguageUpdater updater )
    {
        customUpdaters.set ( component, updater );
    }

    /**
     * Unregisters {@link JComponent}'s custom {@link LanguageUpdater}.
     *
     * @param component {@link JComponent} to unregister custom {@link LanguageUpdater} from
     */
    public static void unregisterLanguageUpdater ( final JComponent component )
    {
        customUpdaters.clear ( component );
    }

    /**
     * Returns {@link LanguageUpdater} currently used for the specified component.
     * This method might return either a custom per-component {@link LanguageUpdater} or global LanguageUpdater.
     * In case {@link LanguageUpdater} cannot be found for the specified component an exception will be thrown.
     *
     * @param component component to retrieve {@link LanguageUpdater} for
     * @return {@link LanguageUpdater} currently used for the specified component
     */
    public static LanguageUpdater getLanguageUpdater ( final JComponent component )
    {
        final LanguageUpdater updater;
        final LanguageUpdater customUpdater = customUpdaters.get ( component );
        if ( customUpdater != null )
        {
            // Found custom updater
            updater = customUpdater;
        }
        else
        {
            synchronized ( updaters )
            {
                final LanguageUpdater cachedUpdater = updatersCache.get ( component.getClass () );
                if ( cachedUpdater != null )
                {
                    // Found cached updater
                    updater = cachedUpdater;
                }
                else
                {
                    // Searching for a suitable component updater if none cached yet
                    final List foundUpdaters = new ArrayList ();
                    for ( final LanguageUpdater lu : updaters )
                    {
                        if ( lu.getComponentClass ().isInstance ( component ) )
                        {
                            foundUpdaters.add ( lu );
                        }
                    }

                    // Determining the best updater according to class hierarchy
                    if ( foundUpdaters.size () == 1 )
                    {
                        // Single updater
                        updater = foundUpdaters.get ( 0 );
                    }
                    else if ( foundUpdaters.size () > 1 )
                    {
                        // More than one updater
                        Collections.sort ( foundUpdaters, languageUpdaterComparator );
                        updater = foundUpdaters.get ( 0 );
                    }
                    else
                    {
                        // Throw an exception in case no LanguageUpdater found
                        // Usually this shouldn't happen unless you try to register an unsupported component
                        throw new RuntimeException ( "Unable to find LanguageUpdater for component: " + component );
                    }

                    // Caching resolved updater
                    updatersCache.put ( component.getClass (), updater );
                }
            }
        }
        return updater;
    }

    /**
     * Returns {@link LanguageUpdater} currently used for the specified component class.
     * In case {@link LanguageUpdater} cannot be found for the specified component an exception will be thrown.
     *
     * @param clazz component class to retrieve {@link LanguageUpdater} for
     * @return {@link LanguageUpdater} currently used for the specified component class
     */
    public static LanguageUpdater getLanguageUpdater ( final Class clazz )
    {
        synchronized ( updaters )
        {
            // Retrieving cached updater
            LanguageUpdater updater = updatersCache.get ( clazz );

            // Checking found updater
            if ( updater != null )
            {
                // Returning cached updater
                return updater;
            }
            else
            {
                // Searching for a suitable component updater if none cached yet
                final List foundUpdaters = new ArrayList ();
                for ( final LanguageUpdater lu : updaters )
                {
                    if ( lu.getComponentClass ().isAssignableFrom ( clazz ) )
                    {
                        foundUpdaters.add ( lu );
                    }
                }

                // Determining the best updater according to class hierarchy
                if ( foundUpdaters.size () == 1 )
                {
                    // Single updater
                    updater = foundUpdaters.get ( 0 );
                }
                else if ( foundUpdaters.size () > 1 )
                {
                    // More than one updater
                    Collections.sort ( foundUpdaters, languageUpdaterComparator );
                    updater = foundUpdaters.get ( 0 );
                }
                else
                {
                    // Throw an exception in case no LanguageUpdater found
                    // Usually this shouldn't happen unless you try to register an unsupported component
                    throw new RuntimeException ( "Unable to find LanguageUpdater for component class: " + clazz );
                }

                // Caching resolved updater
                updatersCache.put ( clazz, updater );

                return updater;
            }
        }
    }

    /**
     * Returns proper initial component text.
     *
     * @param key  text provided into component constructor
     * @param data language data, may not be passed
     * @return proper initial component text
     */
    public static String getInitialText ( final String key, final Object... data )
    {
        // Must be initialized
        mustBeInitialized ();

        // Retrieving initial text
        final String text;
        if ( isCheckComponentsTextForTranslations () && LM.contains ( key ) )
        {
            // If record exists we try to find default text
            if ( LM.containsText ( key ) )
            {
                // Default text exists
                text = LM.get ( key, data );
            }
            else
            {
                // There is not default text
                text = null;
            }
        }
        else
        {
            // Language key cannot be recognized
            text = key;
        }
        return text;
    }

    /**
     * Registers proper initial component language key.
     *
     * @param component translated component
     * @param key       text provided into component constructor
     * @param data      language data, may not be passed
     */
    public static void registerInitialLanguage ( final LanguageMethods component, final String key, final Object... data )
    {
        // Must be initialized
        mustBeInitialized ();

        // Registering component
        if ( isCheckComponentsTextForTranslations () && LM.contains ( key ) )
        {
            component.setLanguage ( key, data );
        }
    }

    /**
     * Registers component for language updates.
     * This component language will be automatically updated using existing LanguageUpdater.
     *
     * @param component component to register
     * @param key       component language key
     * @param data      component language data
     * @see LanguageUpdater
     */
    public static void registerComponent ( final JComponent component, final String key, Object... data )
    {
        // Must be initialized
        mustBeInitialized ();

        // Properly remove previously installed language
        unregisterComponent ( component );

        // Simply unregister component if {@code null} key was provided
        if ( key == null )
        {
            return;
        }

        // Nullifying data if it has no values
        if ( data != null && data.length == 0 )
        {
            data = null;
        }

        // Registering component
        components.set ( component, TranslationKey.of ( key, data ) );

        // Updating component language
        updateComponent ( component );
    }

    /**
     * Unregisters component from language updates.
     *
     * @param component component to unregister
     */
    public static void unregisterComponent ( final JComponent component )
    {
        // Must be initialized
        mustBeInitialized ();

        // Unregistering component
        components.clear ( component );
    }

    /**
     * Returns whether component is registered for language updates or not.
     *
     * @param component component to check
     * @return {@code true} if component is registered for language updates, {@code false} otherwise
     */
    public static boolean isRegisteredComponent ( final JComponent component )
    {
        // Must be initialized
        mustBeInitialized ();

        // Checking whether or not component is registered
        return components.contains ( component );
    }

    /**
     * Returns language key which was used to register specified component.
     *
     * @param component component to retrieve language key for
     * @return language key which was used to register specified component
     */
    public static String getComponentKey ( final JComponent component )
    {
        // Must be initialized
        mustBeInitialized ();

        // Retrieving registered component key
        final TranslationKey translationKey = components.get ( component );
        return translationKey != null ? translationKey.getKey () : null;
    }

    /**
     * Forces full language update for all registered components.
     */
    public static void updateComponents ()
    {
        // Must be initialized
        mustBeInitialized ();

        // Updating all registered components
        components.forEach ( new BiConsumer ()
        {
            @Override
            public void accept ( final JComponent component, final TranslationKey translationKey )
            {
                updateComponent ( component );
            }
        } );
    }

    /**
     * Forces language update for components with the specified keys.
     *
     * @param keys language keys of the components to update
     */
    public static void updateComponents ( final Set keys )
    {
        // Must be initialized
        mustBeInitialized ();

        // Updating components registered for provided keys
        components.forEach ( new BiConsumer ()
        {
            @Override
            public void accept ( final JComponent component, final TranslationKey translationKey )
            {
                if ( keys.contains ( translationKey.getKey () ) )
                {
                    updateComponent ( component );
                }
            }
        } );
    }

    /**
     * Forces {@link JComponent} language update.
     *
     * @param component {@link JComponent} to update
     * @param data      new formatting data
     */
    public static void updateComponent ( final JComponent component, final Object... data )
    {
        // Must be initialized
        mustBeInitialized ();

        // Checking that component is registered
        if ( isRegisteredComponent ( component ) )
        {
            // Retrieving actual data for update
            final TranslationKey translationKey = components.get ( component );
            final Object[] actualData = getActualData ( component, translationKey.getKey (), data );

            // Updating component translation data
            translationKey.setData ( actualData );

            // Checking component updater existence
            final LanguageUpdater updater = getLanguageUpdater ( component );
            if ( updater != null )
            {
                // Updating component language
                updater.update ( component, LM.getLanguage (), translationKey.getKey (), translationKey.getData () );
            }
            else
            {
                // Missing language updater
                throw new LanguageException ( "Component LanguageUpdater is missing: " + component );
            }
        }
        else
        {
            // Premature update call
            throw new LanguageException ( "Component is not registered yet: " + component );
        }
    }

    /**
     * Forces {@link JComponent} language update.
     *
     * @param component {@link JComponent} to update
     * @param key       new language key
     * @param data      new formatting data
     */
    public static void updateComponent ( final JComponent component, final String key, final Object... data )
    {
        // Must be initialized
        mustBeInitialized ();

        // Checking that component is registered
        if ( isRegisteredComponent ( component ) )
        {
            // Retrieving actual data for update
            final Object[] actualData = getActualData ( component, key, data );

            // Updating component translation settings
            final TranslationKey translationKey = TranslationKey.of ( key, actualData );
            components.set ( component, translationKey );

            // Checking component updater existence
            final LanguageUpdater updater = getLanguageUpdater ( component );
            if ( updater != null )
            {
                // Updating component language
                updater.update ( component, LM.getLanguage (), translationKey.getKey (), translationKey.getData () );
            }
            else
            {
                // Missing language updater
                throw new LanguageException ( "Component LanguageUpdater is missing: " + component );
            }
        }
        else
        {
            // Premature update call
            throw new LanguageException ( "Component is not registered yet: " + component );
        }
    }

    /**
     * Returns actual {@link JComponent} translation data based on its translation settings.
     *
     * @param component {@link JComponent} to get actual data for
     * @param key       translation key
     * @param data      translation data
     * @return actual {@link JComponent} translation data based on its translation settings
     */
    private static Object[] getActualData ( final JComponent component, final String key, final Object[] data )
    {
        final Object[] actualData;
        final TranslationKey oldKey = components.get ( component );
        if ( Objects.equals ( oldKey.getKey (), key ) )
        {
            // When keys are identical we want to compare passed data
            // This is just an extra layer of checks to indentify issues with data usage
            if ( ArrayUtils.notEmpty ( data ) )
            {
                // Checking sizes of new and old data arrays
                if ( !ArrayUtils.isEmpty ( oldKey.getData () ) && oldKey.getData ().length == data.length )
                {
                    // Everything is good, data size is the same
                    actualData = data;
                }
                else
                {
                    // Data size has changed, this is not really acceptable without key change
                    // This identifies an issue with updating component translation and therefore exception is thrown
                    throw new LanguageException ( "Translation" );
                }
            }
            else
            {
                // Whenever new data is empty we can use old data
                // This is important to avoid issues with the vararg method usage and for general convenience
                actualData = oldKey.getData ();
            }
        }
        else
        {
            // New key always should bring new data
            // We will accept even empty data here
            actualData = data;
        }
        return actualData;
    }

    /**
     * Adds new {@link LanguageListener} tied to the specified {@link JComponent}.
     * Unlike {@link LanguageManager#addLanguageListener(LanguageListener)} using this method will not store hard references
     * to the {@link LanguageListener} outside of the {@link JComponent} to avoid any mermory leaks. So if specified {@link JComponent}
     * will for instance be destroyed provided {@link LanguageListener} will also be destroyed.
     *
     * @param component {@link JComponent} to tie {@link LanguageListener} to
     * @param listener  {@link LanguageListener} to add
     */
    public static void addLanguageListener ( final JComponent component, final LanguageListener listener )
    {
        componentLanguageListeners.add ( component, listener );
    }

    /**
     * Removes {@link LanguageListener} tied to the specified {@link JComponent}.
     *
     * @param component {@link JComponent} to remove tied {@link LanguageListener} from
     * @param listener  {@link LanguageListener} to remove
     */
    public static void removeLanguageListener ( final JComponent component, final LanguageListener listener )
    {
        componentLanguageListeners.remove ( component, listener );
    }

    /**
     * Removes all {@link LanguageListener}s tied to the specified {@link JComponent}.
     *
     * @param component {@link JComponent} to remove all tied {@link LanguageListener}s from
     */
    public static void removeLanguageListeners ( final JComponent component )
    {
        componentLanguageListeners.clear ( component );
    }

    /**
     * Fires language changed event whenever current {@link Language} changes.
     *
     * @param oldLanguage old {@link Language}
     * @param newLanguage new {@link Language}
     */
    private static void fireLanguageChanged ( final Language oldLanguage, final Language newLanguage )
    {
        componentLanguageListeners.forEachData ( new BiConsumer ()
        {
            @Override
            public void accept ( final JComponent component, final LanguageListener languageListener )
            {
                languageListener.languageChanged ( oldLanguage, newLanguage );
            }
        } );
    }

    /**
     * Adds new {@link DictionaryListener} tied to the specified {@link JComponent}.
     *
     * Unlike {@link LanguageManager#addDictionaryListener(DictionaryListener)} using this method will not store hard references
     * to the {@link DictionaryListener} outside of the {@link JComponent} to avoid any mermory leaks. So if specified {@link JComponent}
     * will for instance be destroyed provided {@link DictionaryListener} will also be destroyed.
     *
     * @param component {@link JComponent} to tie {@link DictionaryListener} to
     * @param listener  {@link DictionaryListener} to add
     */
    public static void addDictionaryListener ( final JComponent component, final DictionaryListener listener )
    {
        componentDictionaryListeners.add ( component, listener );
    }

    /**
     * Removes {@link DictionaryListener} tied to the specified {@link JComponent}.
     *
     * @param component {@link JComponent} to remove tied {@link DictionaryListener} from
     * @param listener  {@link DictionaryListener} to remove
     */
    public static void removeDictionaryListener ( final JComponent component, final DictionaryListener listener )
    {
        componentDictionaryListeners.remove ( component, listener );
    }

    /**
     * Removes all {@link DictionaryListener}s tied to the specified {@link JComponent}.
     *
     * @param component {@link JComponent} to remove all tied {@link DictionaryListener}s from
     */
    public static void removeDictionaryListeners ( final JComponent component )
    {
        componentDictionaryListeners.clear ( component );
    }

    /**
     * Fires {@link Dictionary} added event whenever new {@link Dictionary} is added.
     *
     * @param dictionary new {@link Dictionary}
     */
    private static void fireDictionaryAdded ( final Dictionary dictionary )
    {
        componentDictionaryListeners.forEachData ( new BiConsumer ()
        {
            @Override
            public void accept ( final JComponent component, final DictionaryListener languageListener )
            {
                languageListener.dictionaryAdded ( dictionary );
            }
        } );
    }

    /**
     * Fires {@link Dictionary} removed event whenever {@link Dictionary} is removed.
     *
     * @param dictionary removed {@link Dictionary}
     */
    private static void fireDictionaryRemoved ( final Dictionary dictionary )
    {
        componentDictionaryListeners.forEachData ( new BiConsumer ()
        {
            @Override
            public void accept ( final JComponent component, final DictionaryListener languageListener )
            {
                languageListener.dictionaryRemoved ( dictionary );
            }
        } );
    }

    /**
     * Fires {@link Dictionary}s cleared event whenever all {@link Dictionary}s are removed.
     */
    private static void fireDictionariesCleared ()
    {
        componentDictionaryListeners.forEachData ( new BiConsumer ()
        {
            @Override
            public void accept ( final JComponent component, final DictionaryListener languageListener )
            {
                languageListener.dictionariesCleared ();
            }
        } );
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy