/*
* This file is part of muCommander, http://www.mucommander.com
* Copyright (C) 2002-2016 Maxence Bernard
*
* muCommander 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.
*
* muCommander 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.mucommander.ui.icon;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Insets;
import java.awt.image.BufferedImage;
import java.net.URL;
import java.util.Hashtable;
import java.util.Map;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.mucommander.commons.file.util.ResourceLoader;
/**
* IconManager takes care of loading, caching, rescaling the icons contained inside the application's JAR file.
*
* @author Maxence Bernard
*/
public class IconManager {
private static final Logger LOGGER = LoggerFactory.getLogger(IconManager.class);
/** Caches for the different icon sets */
private final static Map<String, ImageIcon> caches[];
/** Designates the file icon set */
public final static int FILE_ICON_SET = 0;
/** Designates the action icon set */
public final static int ACTION_ICON_SET = 1;
/** Designates the toolbar icon set */
public final static int STATUS_BAR_ICON_SET = 2;
/** Designates the table icon set */
public final static int COMMON_ICON_SET = 3;
/** Designates the preferences icon set */
public final static int PREFERENCES_ICON_SET = 4;
/** Designates the progress icon set */
public final static int PROGRESS_ICON_SET = 5;
/** Designates the language icon set */
public final static int LANGUAGE_ICON_SET = 6;
/** Designates the mucommander icon set */
public final static int MUCOMMANDER_ICON_SET = 7;
/** Base folder of all images */
private final static String BASE_IMAGE_FOLDER = "/images";
/** Icon sets folders within the application's JAR file */
private final static String ICON_SET_FOLDERS[] = {
BASE_IMAGE_FOLDER +"/file/",
BASE_IMAGE_FOLDER +"/action/",
BASE_IMAGE_FOLDER +"/status_bar/",
BASE_IMAGE_FOLDER +"/common/",
BASE_IMAGE_FOLDER +"/preferences/",
BASE_IMAGE_FOLDER +"/progress/",
BASE_IMAGE_FOLDER +"/language/",
BASE_IMAGE_FOLDER +"/mucommander/"
};
static {
// Initialize caches for icon sets that need it.
// Icons which are displayed once in a while like preferences icons don't need to be cached
caches = new Hashtable[ICON_SET_FOLDERS.length];
caches[FILE_ICON_SET] = new Hashtable<String, ImageIcon>();
caches[ACTION_ICON_SET] = new Hashtable<String, ImageIcon>();
caches[STATUS_BAR_ICON_SET] = new Hashtable<String, ImageIcon>();
caches[COMMON_ICON_SET] = new Hashtable<String, ImageIcon>();
caches[PROGRESS_ICON_SET] = new Hashtable<String, ImageIcon>();
}
/**
* Creates a new instance of IconManager.
*/
private IconManager() {}
/**
* Creates and returns an ImageIcon instance using the specified icon path and scale factor. No caching.
*
* @param iconPath path of the icon resource inside the application's JAR file
* @param scaleFactor the icon scale factor, <code>1.0f</code> to have the icon in its original size (no rescaling)
*/
public static ImageIcon getIcon(String iconPath, float scaleFactor) {
URL resourceURL = ResourceLoader.getResourceAsURL(iconPath);
if(resourceURL==null) {
LOGGER.debug("Warning: attempt to load non-existing icon: "+iconPath+" , icon missing ?");
return null;
}
ImageIcon icon = new ImageIcon(resourceURL);
return scaleFactor==1.0f?icon:getScaledIcon(icon, scaleFactor);
}
/**
* Convenience method, calls and returns the result of {@link #getIcon(String, float) getIcon(iconPath, scaleFactor)}
* with a scale factor of 1.0f (no rescaling).
*/
public static ImageIcon getIcon(String iconPath) {
return getIcon(iconPath, 1.0f);
}
/**
* Returns a scaled version of the given ImageIcon instance, using the specified scale factor.
*
* @param icon the icon to scale.
* @param scaleFactor the icon scale factor, <code>1.0f</code> to have the icon in its original size (no rescaling)
*/
public static ImageIcon getScaledIcon(ImageIcon icon, float scaleFactor) {
if(scaleFactor==1.0f || icon==null)
return icon;
Image image = icon.getImage();
return new ImageIcon(image.getScaledInstance((int)(scaleFactor*image.getWidth(null)), (int)(scaleFactor*image.getHeight(null)), Image.SCALE_AREA_AVERAGING));
}
/**
* Returns a 'composite' icon made by composing the two given icons: the <code>backgroundIcon</code> is painted
* first, and the <code>foregroundIcon</code> is superposed, letting its non-transparent pixels reveal the
* background icon.
* For this method to provide a meaningful result, the two icons should have the same dimensions and the
* <code>foreground</code> should have some transparent pixels.
*
* @param backgroundIcon the icon that is painted first
* @param foregroundIcon the icon that is superposed above backgroundIcon, should use transparency
* @return a 'composite' icon made by composing the two given icons
*/
public static ImageIcon getCompositeIcon(Icon backgroundIcon, Icon foregroundIcon) {
BufferedImage bi = new BufferedImage(backgroundIcon.getIconWidth(), backgroundIcon.getIconHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics g = bi.getGraphics();
backgroundIcon.paintIcon(null, g, 0, 0);
foregroundIcon.paintIcon(null, g, 0, 0);
return new ImageIcon(bi);
}
/**
* Returns an icon in the specified icon set and with the given name. If a scale factor other than 1.0f is passed,
* the return icon will be scaled accordingly.
*
* <p>If the icon set has a cache, first looks for an existing instance in the cache, and if it couldn't be found,
* create an instance and store it in the cache for future access. Note that the cached icon is unscaled, i.e.
* the scaled icon is not cached.</p>
*
* @param iconSet an icon set (see public constants for possible values)
* @param iconName filename of the icon to retrieve
* @param scaleFactor the icon scale factor, <code>1.0f</code> to have the icon in its original size (no rescaling)
* @return an ImageIcon instance corresponding to the specified icon set, name and scale factor,
* <code>null</code> if the image wasn't found or couldn't be loaded
*/
public static ImageIcon getIcon(int iconSet, String iconName, float scaleFactor) {
Map<String, ImageIcon> cache = caches[iconSet];
ImageIcon icon;
if(cache==null) {
// No caching, simply create the icon
icon = getIcon(ICON_SET_FOLDERS[iconSet]+iconName);
}
else {
// Look for the icon in the cache
icon = cache.get(iconName);
if(icon==null) {
// Icon is not in the cache, let's create it
icon = getIcon(ICON_SET_FOLDERS[iconSet]+iconName);
// and add it to the cache if icon exists
if(icon!=null)
cache.put(iconName, icon);
}
}
if(icon==null)
return null;
return scaleFactor==1.0f?icon:getScaledIcon(icon, scaleFactor);
}
/**
* Convenience method, calls and returns the result of {@link #getIcon(int, String, float) getIcon(iconSet, iconName, scaleFactor)}
* with a scale factor of 1.0f (no rescaling).
*/
public static ImageIcon getIcon(int iconSet, String iconName) {
return getIcon(iconSet, iconName, 1.0f);
}
/**
* Returns an icon made of the specified icon and some transparent space around it.
*
* @param icon the original icon, will be painted at the center of the new icon
* @param insets specifies the dimensions of the transparent space around the returned icon
* @return an icon made of the specified icon and some transparent space around it
*/
public static ImageIcon getPaddedIcon(ImageIcon icon, Insets insets) {
BufferedImage bi = new BufferedImage(
icon.getIconWidth()+insets.left+insets.right,
icon.getIconHeight()+insets.top+insets.bottom,
BufferedImage.TYPE_INT_ARGB);
Graphics g = bi.getGraphics();
g.drawImage(icon.getImage(), insets.left, insets.top, null);
return new ImageIcon(bi);
}
/**
* Creates and returns an ImageIcon with the same content and dimensions. This method is useful when an ImageIcon
* is needed and only an Icon is available.
*
* <p>If the given Icon is already an ImageIcon, the same instance is returned. If it is not, a new ImageIcon is
* created and returned.
*/
public static ImageIcon getImageIcon(Icon icon) {
if(icon instanceof ImageIcon)
return (ImageIcon)icon;
BufferedImage bi = new BufferedImage(icon.getIconWidth(), icon.getIconHeight(), BufferedImage.TYPE_INT_ARGB);
icon.paintIcon(null, bi.getGraphics(), 0, 0);
return new ImageIcon(bi);
}
/**
* Returns the path to the folder that contains the image resource files of the given icon set.
* The returned path is relative to the application JAR file's root and contains a trailing slash.
*
* @param iconSet an icon set (see public constants for possible values)
*/
public static String getIconSetFolder(int iconSet) {
return ICON_SET_FOLDERS[iconSet];
}
}