001/*
002 * Copyright (c) 2002-2007 JGoodies Karsten Lentzsch. All Rights Reserved.
003 *
004 * Redistribution and use in source and binary forms, with or without
005 * modification, are permitted provided that the following conditions are met:
006 *
007 *  o Redistributions of source code must retain the above copyright notice,
008 *    this list of conditions and the following disclaimer.
009 *
010 *  o Redistributions in binary form must reproduce the above copyright notice,
011 *    this list of conditions and the following disclaimer in the documentation
012 *    and/or other materials provided with the distribution.
013 *
014 *  o Neither the name of JGoodies Karsten Lentzsch nor the names of
015 *    its contributors may be used to endorse or promote products derived
016 *    from this software without specific prior written permission.
017 *
018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
020 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
021 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
022 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
023 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
024 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
025 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
026 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
027 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
028 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029 */
030
031package com.jgoodies.forms.util;
032
033import java.beans.PropertyChangeEvent;
034import java.beans.PropertyChangeListener;
035
036import javax.swing.LookAndFeel;
037import javax.swing.UIManager;
038
039/**
040 * Consists only of static utility methods.
041 *
042 * This class may be merged with the FormLayoutUtils extra - or not. *
043 *
044 * @author Karsten Lentzsch
045 * @version $Revision$
046 */
047public final class Utilities {
048
049    // Instance *************************************************************
050
051    private Utilities() {
052        // Suppresses default constructor, ensuring non-instantiability.
053    }
054
055    /**
056     * Lazily checks and answers whether the Aqua look&feel is active.
057     *
058     * @return true if the current look&feel is Aqua
059     */
060    public static boolean isLafAqua() {
061        if (cachedIsLafAqua == null) {
062            cachedIsLafAqua = Boolean.valueOf(computeIsLafAqua());
063            ensureLookAndFeelChangeHandlerRegistered();
064        }
065        return cachedIsLafAqua.booleanValue();
066    }
067
068    // Caching and Lazily Computing the Laf State *****************************
069
070    /**
071     * Holds the cached result of the Aqua l&f check.
072     * Is invalidated by the <code>LookAndFeelChangeHandler</code>
073     * if the look&amp;feel changes.
074     */
075    private static Boolean cachedIsLafAqua;
076
077    /**
078     * Describes whether the <code>LookAndFeelChangeHandler</code>
079     * has been registered with the <code>UIManager</code> or not.
080     * It is registered lazily when the first cached l&amp;f state is computed.
081     */
082    private static boolean lafChangeHandlerRegistered = false;
083
084    private static synchronized void ensureLookAndFeelChangeHandlerRegistered() {
085        if (!lafChangeHandlerRegistered) {
086            UIManager.addPropertyChangeListener(new LookAndFeelChangeHandler());
087            lafChangeHandlerRegistered = true;
088        }
089    }
090
091    /**
092     * Computes and answers whether the Aqua look&amp;feel is active.
093     *
094     * @return true if the current look&amp;feel is Aqua
095     */
096    private static boolean computeIsLafAqua() {
097        LookAndFeel laf = UIManager.getLookAndFeel();
098        return laf.getName().startsWith("Mac OS X Aqua");
099    }
100
101    /**
102     * Listens to changes of the Look and Feel and invalidates the cache.
103     */
104    private static final class LookAndFeelChangeHandler
105            implements PropertyChangeListener {
106
107        /**
108         * Invalidates the cached laf states, if the UIManager has fired
109         * any property change event. Since we need to handle look&amp;feel
110         * changes only, we check the event's property name to be
111         * "lookAndFeel" or <code>null</code>. The check for null is necessary
112         * to handle the special event where property name, old and new value
113         * are all <code>null</code> to indicate that multiple properties
114         * have changed.
115         *
116         * @param evt  describes the property change
117         */
118        @Override
119        public void propertyChange(PropertyChangeEvent evt) {
120            String propertyName = evt.getPropertyName();
121            if (propertyName == null || propertyName.equals("lookAndFeel")) {
122                cachedIsLafAqua = null;
123            }
124        }
125    }
126
127}