001    /* JAPI - (Yet another (hopefully) useful) Java API
002     *
003     * Copyright (C) 2004-2006 Christian Hujer
004     *
005     * This program is free software; you can redistribute it and/or
006     * modify it under the terms of the GNU General Public License as
007     * published by the Free Software Foundation; either version 2 of the
008     * License, or (at your option) any later version.
009     *
010     * This program is distributed in the hope that it will be useful, but
011     * WITHOUT ANY WARRANTY; without even the implied warranty of
012     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013     * General Public License for more details.
014     *
015     * You should have received a copy of the GNU General Public License
016     * along with this program; if not, write to the Free Software
017     * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
018     * 02111-1307, USA.
019     */
020    
021    package net.sf.japi.swing;
022    
023    import java.net.URL;
024    import java.util.Map;
025    import java.util.WeakHashMap;
026    import java.util.List;
027    import java.util.ArrayList;
028    import java.util.Iterator;
029    import java.security.AccessController;
030    import java.security.PrivilegedAction;
031    import javax.swing.Icon;
032    import javax.swing.ImageIcon;
033    import org.jetbrains.annotations.Nullable;
034    
035    /** Class to handle icons.
036     * Default size is 16.
037     * Instances must have an associated ClassLoader, otherwise several methods will not work properly but throw a NullPointerException instead.
038     * So if you do not provide a ClassLoader, be sure the class you provide has one, or if you use the no-arg constructor resp. the default instance, be
039     * sure the IconManager class itself was loaded with some ClassLoader other than <code>null</code>.
040     * @author <a href="mailto:chris@riedquat.de">Christian Hujer</a>
041     * @todo this class should be refactored into a more generic version and accessible through ActionFactory?
042     * @todo it should be possible to initialize the paths through properties
043     */
044    public final class IconManager {
045    
046        /** The default IconManager. */
047        private static final IconManager DEFAULT_ICON_MANAGER = createDefaultIconManager();
048    
049        /** Create the default IconManager.
050         * @return default IconManager
051         */
052        private static IconManager createDefaultIconManager() {
053            final IconManager defaultIconManager = new IconManager();
054            defaultIconManager.iconPaths.add("icons/");
055            defaultIconManager.iconPaths.add("toolbarButtonGraphics/");
056            return defaultIconManager;
057        }
058    
059        /** ClassLoader to get icons from, must not be null. */
060        private final ClassLoader classLoader;
061    
062        /** The available sizes provided by this IconManager. */
063        private final int[] availableSizes = { 16, 24 };
064    
065        /** The icon cache.
066         * Key: short name for icon, which is likely to be used as a relative file name.
067         * Value: Icon
068         */
069        private final Map<String,Icon> smallCache = new WeakHashMap<String,Icon>();
070    
071        /** The paths to search icons in. */
072        private final List<String> iconPaths = new ArrayList<String>();
073    
074        /** Get the default IconManager.
075         * The ClassLoader in use is the classloader IconManager was loaded with, whatever classloader that was.
076         * @return default IconManaager
077         */
078        public static IconManager getDefaultIconManager() {
079            return DEFAULT_ICON_MANAGER;
080        }
081    
082        /** Create a IconManager.
083         * Uses the IconManager's class loader.
084         * Only use this if you want to be independent of the global icon size settings.
085         * The recommended way to get a default IconManager instance is {#getDefaultIconManager()}.
086         */
087        public IconManager() {
088            this(getContextClassLoader());
089            //this(IconManager.class.getClassLoader());
090        }
091    
092        private static ClassLoader getContextClassLoader() {
093            return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
094                public ClassLoader run() {
095                    try {
096                        return Thread.currentThread().getContextClassLoader();
097                    } catch (final SecurityException e) {
098                        return getClass().getClassLoader();
099                    }
100                }
101            });
102        }
103    
104        /** Create an IconManager.
105         * @param clazz Class to get ClassLoader for IconManager
106         */
107        public IconManager(final Class<?> clazz) {
108            classLoader = clazz.getClassLoader();
109        }
110    
111        /** Create an IconManager.
112         * @param cl ClassLoader to create IconManager for
113         */
114        public IconManager(final ClassLoader cl) {
115            classLoader = cl;
116        }
117    
118        /** Return the available sizes for icons.
119         * @return available icon sizes
120         */
121        public int[] getAvailableSizes() {
122            return availableSizes.clone();
123        }
124    
125        /** Load an icon.
126         * @param s icon name, like "general/About" or "navigation/Forward"
127         * @return Icon for <var>s</var>
128         */
129        @Nullable public Icon getIcon(final String s) {
130            Icon icon = smallCache.get(s);
131            if (icon == null) {
132                URL url = null;
133                // Search the configured class loader
134                for (final Iterator<String> it = iconPaths.iterator(); url == null && it.hasNext();) {
135                    final String path = it.next();
136                    final String iconPath = path + (path.endsWith("/") ? "" : "/") + s + ".gif";
137                    url = classLoader.getResource(iconPath);
138                }
139                if (url == null) {
140                    // if searching the configured class loader failed, search the system class loader
141                    for (final Iterator<String> it = iconPaths.iterator(); url == null && it.hasNext();) {
142                        final String path = it.next();
143                        final String iconPath = path + (path.endsWith("/") ? "" : "/") + s + ".gif";
144                        url = ClassLoader.getSystemResource(iconPath);
145                    }
146                }
147                if (url == null) {
148                    return null;
149                }
150                icon = new ImageIcon(url);
151                smallCache.put(s, icon);
152            }
153            return icon;
154        }
155    
156    } // class IconManager