/*
* Copyright 2004 - 2008 Christian Sprajc. All rights reserved.
*
* This file is part of PowerFolder.
*
* PowerFolder 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.
*
* PowerFolder 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 PowerFolder. If not, see <http://www.gnu.org/licenses/>.
*
* $Id$
*/
package de.dal33t.powerfolder.ui.util;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.HeadlessException;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.Transparency;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.awt.image.ColorModel;
import java.awt.image.PixelGrabber;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.filechooser.FileSystemView;
import javax.swing.plaf.IconUIResource;
import de.dal33t.powerfolder.Controller;
import de.dal33t.powerfolder.Member;
import de.dal33t.powerfolder.light.FileInfo;
import de.dal33t.powerfolder.net.ConnectionHandler;
import de.dal33t.powerfolder.net.ConnectionQuality;
import de.dal33t.powerfolder.skin.Origin;
import de.dal33t.powerfolder.transfer.DownloadManager;
import de.dal33t.powerfolder.ui.TrayIconManager;
import de.dal33t.powerfolder.util.Reject;
/**
* Contains all icons for the powerfolder application. Icons should be got by
* calling <code>Icons.getIconById(Icon.EXAMPLE)</code>. This will dereference
* the icon via properties file and will return the Icon as well as caching it,
* so that subsequent calls will return the same object. The advantage of this
* approach is that Icons are only get as required, saving time and memory.
* Similarly, Images should be got by calling something like
* <code>Icons.getImageById(Icon.EXAMPLE)</code>.
*
* @author <a href="mailto:totmacher@powerfolder.com">Christian Sprajc </a>
* @version $Revision: 1.74 $
*/
public class Icons {
// General stuff
public static final String FILTER_TEXT_FIELD_CLEAR_BUTTON_NORMAL = "filter_text_field_clear_button_normal.icon";
public static final String FILTER_TEXT_FIELD_CLEAR_BUTTON_HOVER = "filter_text_field_clear_button_hover.icon";
public static final String FILTER_TEXT_FIELD_CLEAR_BUTTON_PUSH = "filter_text_field_clear_button_push.icon";
public static final String FILTER_TEXT_FIELD_GLASS = "filter_text_field_glass.icon";
public static final String FILTER_TEXT_FIELD_GLASS_ARROW = "filter_text_field_glass_arrow.icon";
public static final String WINDOW_MAXIMIZE_NORMAL = "window_maximize_normal.icon";
public static final String WINDOW_MAXIMIZE_HOVER = "window_maximize_hover.icon";
public static final String WINDOW_MAXIMIZE_PUSH = "window_maximize_push.icon";
public static final String WINDOW_PLUS_NORMAL = "window_plus_normal.icon";
public static final String WINDOW_PLUS_HOVER = "window_plus_hover.icon";
public static final String WINDOW_PLUS_PUSH = "window_plus_push.icon";
public static final String WINDOW_MINUS_NORMAL = "window_minus_normal.icon";
public static final String WINDOW_MINUS_HOVER = "window_minus_hover.icon";
public static final String WINDOW_MINUS_PUSH = "window_minus_push.icon";
public static final String ACTION_ARROW = "action_arrow.icon";
public static final String BLANK = "blank.icon";
public static final String WARNING = "warning.icon";
public static final String DEBUG = "bug.icon";
public static final String SYSTEM_MONITOR = "system_monitor.icon";
public static final String STOP = "stop.icon";
public static final String RUN = "run.icon";
public static final String PAUSE = "pause.icon";
public static final String STATUS = "status.icon";
public static final String ADD = "add.icon";
public static final String EDIT = "edit.icon";
public static final String DELETE = "delete.icon";
public static final String UNKNOWN_FILE = "unknown.icon";
public static final String UNKNOWN_FILE_GRAY = "unknown_file_gray";
public static final String UNKNOWN_FILE_RED = "unknown_file_red";
public static final String SETTINGS = "settings.icon";
public static final String PROBLEMS = "problems.icon";
public static final String INFORMATION = "information.icon";
// Wizard Arrows
public static final String ARROW_LEFT = "arrow_left.icon";
public static final String ARROW_RIGHT = "arrow_right.icon";
public static final String EXPAND = "expand.icon";
public static final String COLLAPSE = "collapse.icon";
public static final String QUESTION = "question.icon";
public static final String SORT_UP = "sort_up.icon";
public static final String SORT_DOWN = "sort_down.icon";
public static final String SORT_BLANK = "sort_blank.icon";
// Directories in navigation tree
public static final String DIRECTORY = "directory.icon";
public static final String DIRECTORY_OPEN = "directory_open.icon";
// Node icons
public static final String NODE_MYSELF = "node_myself.icon";
public static final String NODE_CONNECTED = "node_friend_connected.icon";
public static final String NODE_DISCONNECTED = "node_friend_disconnected.icon";
public static final String NODE_CONNECTING = NODE_DISCONNECTED;
public static final String NODE_POOR = "node_friend_poor.icon";
public static final String NODE_MEDIUM = "node_friend_medium.icon";
public static final String NODE_LAN = "node_friend_lan.icon";
public static final String NODE_GROUP = "node_group.icon";
public static final String FOLDER = "folder.icon";
public static final String FILES = "files.icon";
public static final String ONLINE_FOLDER = "online_folder.icon";
public static final String ONLINE_FOLDER_SMALL = "online_folder_small.icon";
public static final String PREVIEW_FOLDER = "preview_folder.icon";
public static final String TYPICAL_FOLDER = "typical_folder.icon";
public static final String BLACK_LIST = "black_list.icon";
public static final String WHITE_LIST = "white_list.icon";
public static final String DOWNLOAD = "download.icon";
public static final String DOWNLOAD_ACTIVE = "download_active.icon";
public static final String UPLOAD = "upload.icon";
public static final String INACTIVE = "inactive.icon";
public static final String TRANSFERS = "transfers.icon";
public static final String EXPECTED = "expected.icon";
public static final String CHECKED = "checked.icon";
public static final String STATS = "stats.icon";
public static final String STATUS_TAB_TELL_A_FRIEND = "status_tab_tell_friend_icon";
public static final String TWITTER_BUTTON = "twitter.icon";
public static final String FACEBOOK_BUTTON = "facebook.icon";
public static final String LINKEDIN_BUTTON = "linkedin.icon";
public static final String EMAIL_BUTTON = "email.icon";
// Sync icons
public static final String SYNC_COMPLETE = "sync_complete.icon";
public static final String SYNC_INCOMPLETE = "sync_incomplete.icon";
public static final String[] SYNC_ANIMATION = {"sync00.icon",
"sync01.icon", "sync02.icon", "sync03.icon", "sync04.icon",
"sync05.icon", "sync06.icon", "sync07.icon", "sync08.icon",
"sync09.icon", "sync10.icon", "sync11.icon"};
// Systray icons
public static final String[] SYSTRAY_SYNC_ANIMATION;
private static final String[] SYSTRAY_SYNC_ANIMATION_LOW_RES = {
"systray_sync00_lowres.icon", "systray_sync01_lowres.icon", "systray_sync02_lowres.icon",
"systray_sync03_lowres.icon", "systray_sync04_lowres.icon", "systray_sync05_lowres.icon",
"systray_sync06_lowres.icon", "systray_sync07_lowres.icon", "systray_sync08_lowres.icon",
"systray_sync09_lowres.icon", "systray_sync10_lowres.icon", "systray_sync11_lowres.icon"};
private static final String[] SYSTRAY_SYNC_ANIMATION_HI_RES = {
"systray_sync00_hires.icon", "systray_sync01_hires.icon", "systray_sync02_hires.icon",
"systray_sync03_hires.icon", "systray_sync04_hires.icon", "systray_sync05_hires.icon",
"systray_sync06_hires.icon", "systray_sync07_hires.icon", "systray_sync08_hires.icon",
"systray_sync09_hires.icon", "systray_sync10_hires.icon", "systray_sync11_hires.icon"};
public static final String SYSTRAY_SYNC_COMPLETE;
private static final String SYSTRAY_SYNC_COMPLETE_LOW_RES = "systray_sync_complete_lowres.icon";
private static final String SYSTRAY_SYNC_COMPLETE_HIGH_RES = "systray_sync_complete_hires.icon";
public static final String SYSTRAY_SYNC_INCOMPLETE;
private static final String SYSTRAY_SYNC_INCOMPLETE_LOW_RES = "systray_sync_incomplete_lowres.icon";
private static final String SYSTRAY_SYNC_INCOMPLETE_HIGH_RES = "systray_sync_incomplete_hires.icon";
public static final String SYSTRAY_WARNING;
private static final String SYSTRAY_WARNING_LOW_RES = "systray_warning_lowres.icon";
private static final String SYSTRAY_WARNING_HIGH_RES = "systray_warning_hires.icon";
public static final String SYSTRAY_PAUSE;
private static final String SYSTRAY_PAUSE_LOW_RES = "systray_pause_lowres.icon";
private static final String SYSTRAY_PAUSE_HIGH_RES = "systray_pause_hires.icon";
static {
if (!TrayIconManager.isHiRes()) {
SYSTRAY_SYNC_ANIMATION = SYSTRAY_SYNC_ANIMATION_LOW_RES;
SYSTRAY_SYNC_COMPLETE = SYSTRAY_SYNC_COMPLETE_LOW_RES;
SYSTRAY_SYNC_INCOMPLETE = SYSTRAY_SYNC_INCOMPLETE_LOW_RES;
SYSTRAY_WARNING = SYSTRAY_WARNING_LOW_RES;
SYSTRAY_PAUSE = SYSTRAY_PAUSE_LOW_RES;
} else {
SYSTRAY_SYNC_ANIMATION = SYSTRAY_SYNC_ANIMATION_HI_RES;
SYSTRAY_SYNC_COMPLETE = SYSTRAY_SYNC_COMPLETE_HIGH_RES;
SYSTRAY_SYNC_INCOMPLETE = SYSTRAY_SYNC_INCOMPLETE_HIGH_RES;
SYSTRAY_WARNING = SYSTRAY_WARNING_HIGH_RES;
SYSTRAY_PAUSE = SYSTRAY_PAUSE_HIGH_RES;
}
}
// Wizard pictos from the quick info panels
public static final String LOGO128X128 = "picto_logo_128.icon";
public static final String LOGO400UI = "power_folder_logo_400_ui.icon";
public static final String SMALL_LOGO = "powerfolder_32.icon";
public static final String SPLASH = "splash.icon";
private static final Logger log = Logger.getLogger(Icons.class.getName());
private static final String DISABLED_EXTENSION_ADDITION = "_disabled";
private static final Object FILE_LOCK = new Object();
/** Map of ID - Icon */
private static final Map<String, Icon> ID_ICON_MAP = new ConcurrentHashMap<String, Icon>();
/** Map of ID - Image */
private static final Map<String, Image> ID_IMAGE_MAP = new ConcurrentHashMap<String, Image>();
/** Map of Extension - Icon */
private static final Map<String, Icon> EXTENSION_ICON_MAP = new HashMap<String, Icon>();
// BlueGlobe is our default.
private static final String DEFAULT_PROPERTIES_FILENAME = Origin.ICON_PROPERTIES_FILENAME;
private static Properties iconProperties;
private static final List<String> UNKNOWN_ICONS = new ArrayList<String>();
/**
* Constructor - no instances.
*/
protected Icons() {
// No instances - everything is static.
}
/**
* Configure the properties file / icons. PowerFolder will takes the icons
* from this properties.
*
* @param icoProps
*/
public static void setIconProperties(Properties icoProps) {
Reject.ifNull(icoProps, "iconProperties");
Reject.ifTrue(icoProps.isEmpty(), "iconProperties are empty");
iconProperties = icoProps;
ID_ICON_MAP.clear();
ID_IMAGE_MAP.clear();
}
/**
* @return the icon properties. Loads the default icon properties if
* null/not set/not loaded.
*/
public static synchronized Properties getIconProperties() {
if (iconProperties == null) {
iconProperties = loadProperties(DEFAULT_PROPERTIES_FILENAME);
}
// Don't hand out internal instance to prevent side effects.
return new Properties(iconProperties);
}
/**
* Returns the icons for the specified id.
*
* @param id
* the icon id
* @return the icon
*/
public static Icon getIconById(String id) {
if (id == null) {
log.severe("Icon id null ???");
return null;
}
if (UNKNOWN_ICONS.contains(id)) {
// Already discovered that we do not know this one.
return null;
}
Icon icon = ID_ICON_MAP.get(id);
if (icon != null) {
return icon;
}
// Special cases for unknown file icons.
if (id.equals(UNKNOWN_FILE_GRAY)) {
icon = getGrayIcon(getIconById(UNKNOWN_FILE));
if (icon != null) {
if (log.isLoggable(Level.FINER)) {
log.finer("Cached icon " + id);
}
ID_ICON_MAP.put(id, icon);
}
return icon;
} else if (id.equals(UNKNOWN_FILE_RED)) {
icon = convertToRed(getGrayIcon(getIconById(UNKNOWN_FILE)));
if (icon != null) {
if (log.isLoggable(Level.FINER)) {
log.finer("Cached icon " + id);
}
ID_ICON_MAP.put(id, icon);
}
return icon;
}
String iconId = getIconId(id);
if (iconId == null) {
// Log it.
if (log.isLoggable(Level.FINE)) {
log.fine("Icon not found ID: '" + id + '\'');
}
UNKNOWN_ICONS.add(id);
return null;
}
URL iconURL = Thread.currentThread().getContextClassLoader()
.getResource(iconId);
if (iconURL == null) {
if (log.isLoggable(Level.FINE)) {
log.fine("Icon not found '" + id + '\'');
}
return null;
}
icon = new ImageIcon(iconURL);
if (log.isLoggable(Level.FINER)) {
log.finer("Cached icon " + id);
}
ID_ICON_MAP.put(id, icon);
return icon;
}
/**
* Returns the image for the specified id
*
* @param id
* the image id
* @return the image
*/
public static Image getImageById(String id) {
Image image = ID_IMAGE_MAP.get(id);
if (image != null) {
return image;
}
String iconId = getIconId(id);
if (iconId == null) {
log.severe("Image not found ID: '" + id + '\'');
return null;
}
URL imageURL = Thread.currentThread().getContextClassLoader()
.getResource(iconId);
if (imageURL == null) {
return null;
}
image = Toolkit.getDefaultToolkit().getImage(imageURL);
if (log.isLoggable(Level.FINER)) {
log.finer("Cached image " + id);
}
ID_IMAGE_MAP.put(id, image);
return image;
}
/**
* Get the icon id from the properties for an id. So if there is a line
*
* <pre>
* stop.icon = icons / Abort.png
* </pre>
*
* then id of 'stop.icon' would return 'icons/Abort.png'. Tries override
* properties first, then the normal PowerFolder ones.
*
* @param id
* @return
*/
private static String getIconId(String id) {
return getIconProperties().getProperty(id);
}
/**
* @param node
* @return a simplified version of the node icon. Does not reflect the
* online- and supernode-state
*/
public static Icon getSimpleIconFor(Member node) {
if (node == null) {
// Unknown
return getIconById(NODE_CONNECTED);
}
Icon icon;
// Render friendship things
if (node.isFriend()) {
icon = getIconById(NODE_CONNECTED);
} else {
// Orange head for non-friends
icon = getIconById(NODE_CONNECTED);
}
if (!node.isOnSameNetwork()) {
icon = new OverlayedIcon(icon, getIconById(DELETE), 0, 0);
}
return icon;
}
/**
* Returns the icon for that node
*
* @param node
* @return the icon
*/
public static Icon getIconFor(Member node) {
if (node == null) {
// Unknown
return getIconById(NODE_CONNECTED);
}
String iconID;
if (node.isMySelf()) {
iconID = NODE_MYSELF;
} else if (node.isCompletelyConnected()) {
ConnectionHandler peer = node.getPeer();
iconID = NODE_CONNECTED;
if (node.isOnLAN()) {
iconID = NODE_LAN;
} else if (peer != null) {
ConnectionQuality quality = peer.getConnectionQuality();
if (quality != null) {
switch (quality) {
case GOOD :
iconID = NODE_CONNECTED;
break;
case MEDIUM :
iconID = NODE_MEDIUM;
break;
case POOR :
iconID = NODE_POOR;
break;
}
}
}
} else {
iconID = NODE_DISCONNECTED;
}
Icon icon = getIconById(iconID);
if (!node.isOnSameNetwork()) {
icon = new OverlayedIcon(icon, getIconById(DELETE), 0, 0);
}
return icon;
}
/**
* returns a icon based on the state of the fileinfo this maybe a normal
* gray or red icon
*
* @param fileInfo
* the fileinfo to return a icon for
* @param controller
* @return the icon
*/
public static Icon getIconFor(FileInfo fileInfo, Controller controller) {
String extension = fileInfo.getExtension();
if (extension == null) { // no file extension
return getUnknownIcon(fileInfo, controller);
}
File file = fileInfo.getDiskFile(controller.getFolderRepository());
boolean exists = file != null && file.exists();
Icon icon = getCachedIcon(extension, exists);
if (icon == null) {// no icon found in cache
if (exists) { // create one if local file is there
icon = FileSystemView.getFileSystemView().getSystemIcon(file);
if (icon == null) {
return getIconById(UNKNOWN_FILE);
}
if (!hasUniqueIcon(extension)) {// do not cache executables
EXTENSION_ICON_MAP.put(extension, icon);// put in cache
Icon disabled = getGrayIcon(icon);
// put in cache
EXTENSION_ICON_MAP.put(extension
+ DISABLED_EXTENSION_ADDITION, disabled);
}
} else { // local file doesnot exists
if (hasUniqueIcon(extension)) {// if *.exe or *.ico we don't
// know the icon
// fixes speed with lots of *.ico or *.exe files
icon = getIconById(UNKNOWN_FILE_GRAY);
} else {
icon = getIconExtension(extension);
if (icon == null) {
icon = getIconById(UNKNOWN_FILE_GRAY);
} else {
Icon disabled = getGrayIcon(icon);
if (!hasUniqueIcon(extension)) {// do not cache *.exe
// and *.ico etc
// put in cache
EXTENSION_ICON_MAP.put(extension, icon);
EXTENSION_ICON_MAP.put(extension
+ DISABLED_EXTENSION_ADDITION, disabled);
}
icon = disabled;
}
}
}
}
if (fileInfo.isDeleted()) {
icon = convertToRed(icon); // it's already gray because local file
// does not exists
}
return icon;
}
/**
* returns a icon (never gray or red)
* <p>
* TODO THIS IS A MESS
*
* @param fileInfo
* the fileinfo to return a icon for
* @param controller
* @return the icon
*/
public static Icon getEnabledIconFor(FileInfo fileInfo,
Controller controller)
{
String extension = fileInfo.getExtension();
if (extension == null) { // no file extension
return getIconById(UNKNOWN_FILE);
}
if (EXTENSION_ICON_MAP.containsKey(extension)) { // getIcon from cache
return EXTENSION_ICON_MAP.get(extension);
}
File file = fileInfo.getDiskFile(controller.getFolderRepository());
boolean exists = file != null && file.exists();
Icon icon;
if (exists) {
icon = FileSystemView.getFileSystemView().getSystemIcon(file);
if (!hasUniqueIcon(extension)) { // do not cache executables
EXTENSION_ICON_MAP.put(extension, icon);// put in cache
Icon disabled = getGrayIcon(icon); // think ahead we may need
// the disabled version somewhere later
// put in cache
EXTENSION_ICON_MAP.put(extension + DISABLED_EXTENSION_ADDITION,
disabled);
}
return icon;
}
// local file doesnot exists
icon = getIconExtension(extension);
EXTENSION_ICON_MAP.put(extension, icon);// put in cache
Icon disabled = getGrayIcon(icon); // think ahead we may need
// the disabled version somewhere later
// put in cache
EXTENSION_ICON_MAP.put(extension + DISABLED_EXTENSION_ADDITION,
disabled);
return icon;
}
/**
* @param controller
* @param fInfo
* the file
* @return the icon for a file
*/
public static Icon getIconFor(Controller controller, FileInfo fInfo) {
Icon icon;
if (fInfo.isDownloading(controller)) {
DownloadManager dl = controller.getTransferManager()
.getActiveDownload(fInfo);
if (dl != null && dl.isStarted()) {
icon = getIconById(DOWNLOAD_ACTIVE);
} else {
icon = getIconById(DOWNLOAD);
}
} else if (fInfo.isDeleted()) {
icon = getIconById(DELETE);
} else if (fInfo.isExpected(controller.getFolderRepository())) {
icon = getIconById(EXPECTED);
} else if (fInfo.getFolder(controller.getFolderRepository()) == null) {
icon = getIconById(EXPECTED);
} else {
icon = null;
}
return icon;
}
/**
* we don't want to cache icons, executables and screensavers because they
* have unique icons
*
* @param extension
* @return true if extension is one of "EXE", "SCR", "ICO" else false
*/
private static boolean hasUniqueIcon(String extension) {
return extension.equals("EXE") || extension.equals("SCR")
|| extension.equals("ICO");
}
/**
* @param extension
* @param disabled
* @return a icon from cache.
*/
private static Icon getCachedIcon(String extension, boolean disabled) {
if (disabled) {
if (EXTENSION_ICON_MAP.containsKey(extension)) { // getIcon from
// cache
return EXTENSION_ICON_MAP.get(extension);
}
} else {// file does not exist try to get Disabled icon
if (EXTENSION_ICON_MAP.containsKey(extension
+ DISABLED_EXTENSION_ADDITION))
{
// get disabled Icon from cache
return EXTENSION_ICON_MAP.get(extension
+ DISABLED_EXTENSION_ADDITION);
}
}
return null;
}
/**
* @param fileInfo
* @param controller
* @return the unknown icon, normal grey or red based on state of fileinfo
*/
private static Icon getUnknownIcon(FileInfo fileInfo, Controller controller)
{
if (fileInfo.diskFileExists(controller)) {
return getIconById(UNKNOWN_FILE);
}
if (fileInfo.isDeleted()) {
return getIconById(UNKNOWN_FILE_RED);
}
return getIconById(UNKNOWN_FILE_GRAY);
}
/**
* Creates a tmp file and get image.
* FileSystemView.getFileSystemView().getSystemIcon(file) needs a existing
* file to get a image for.
*
* @param extension
* the extension to get a Image for
* @return the Image
*/
public static Image getImageExtension(String extension) {
Icon icon = getIconExtension(extension);
if (icon == null) {
log.severe("Image Icon not found for extension '" + extension
+ '\'');
return null;
}
return getImageFromIcon(icon);
}
/**
* Creates a tmp file and get icon.
* FileSystemView.getFileSystemView().getSystemIcon(file) needs a existing
* file to get a icon for.
*
* @param extension
* the extension to get a Icon for
* @return the icon
*/
private static Icon getIconExtension(String extension) {
File tempFile = new File(Controller.getTempFilesLocation(), "temp."
+ extension);
try {
synchronized (FILE_LOCK) { // synchronized otherwise we may try
// to create the same file twice at once
if (tempFile.createNewFile()) {
Icon icon = FileSystemView.getFileSystemView()
.getSystemIcon(tempFile);
if (!tempFile.delete()) {
log.warning("Failed to delete temporary file.");
tempFile.deleteOnExit();
}
return icon;
}
log.severe("Couldn't create temporary file for icon retrieval for extension:'"
+ extension + '\'');
}
} catch (IOException e) {
log.log(Level.SEVERE, "Exception", e);
}
return null;
}
/**
* converts Icon to red, note: first convert to gray *
*
* @param icon
* @return the red icon
*/
private static ImageIcon convertToRed(Icon icon) {
Image image = getImageFromIcon(icon);
BufferedImage src = toBufferedImage(image);
int targetColor = 0x00FF0000; // Red; format: 0x00RRGGBB in hex
int width = src.getWidth();
int height = src.getHeight();
BufferedImage dst = new BufferedImage(width, height,
BufferedImage.TYPE_INT_ARGB);
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
int rgb = src.getRGB(x, y);
int istrans = rgb & 0xFF000000;
if (istrans == 0xFF000000) { // map to alpha
int alpha = 255 - (src.getRGB(x, y) & 0x000000FF);
dst.setRGB(x, y, alpha << 24 | targetColor);
} else {// set original if transparent
dst.setRGB(x, y, rgb);
}
}
}
return new ImageIcon(dst);
}
/**
* create a disabled (Gray) version of the Icon much better way than
* GrayFilter, because GrayFilter does not handle the transparancy well.
*
* @param icon
* the icon to convert to gray icon
* @return icon grayed out for use as disabled icon
*/
private static Icon getGrayIcon(Icon icon) {
ColorSpace colorSpace = ColorSpace.getInstance(ColorSpace.CS_GRAY);
ColorConvertOp colorConvertOp = new ColorConvertOp(colorSpace, null);
Image image = getImageFromIcon(icon);
// on failure, a colored icon is better than nothing
if (image == null) {
return icon;
}
return new ImageIcon(
colorConvertOp.filter(toBufferedImage(image), null));
}
/**
* Extracts the image from an Icon. If the icon is not an ImageIcon but
* wrapped into an IconUIResource, this method tries to get the image via
* reflection.
*
* @param icon
* The icon to get the image from.
* @return The image or null on failure
*/
private static Image getImageFromIcon(Icon icon) {
if (icon == null) {
log.log(Level.SEVERE, "Icon is null", new RuntimeException(
"Icon is null"));
return null;
}
// simple case: we have an ImageIcon to get the image from
if (icon instanceof ImageIcon) {
ImageIcon imageIcon = (ImageIcon) icon;
return imageIcon.getImage();
}
// if the icon is wrapped in an IconUIResource, try to unwrap
if (icon instanceof IconUIResource) {
// try to get the image from the icon via Reflection
try {
IconUIResource iconUIResource = (IconUIResource) icon;
Field delegateField = iconUIResource.getClass()
.getDeclaredField("delegate");
delegateField.setAccessible(true);
Icon inner = (Icon) delegateField.get(iconUIResource);
return getImageFromIcon(inner);
} catch (Exception e) {
log.log(Level.SEVERE, "Could not get icon from IconUIResource",
e);
}
}
// Fallback
int w = icon.getIconWidth();
int h = icon.getIconHeight();
GraphicsEnvironment ge = GraphicsEnvironment
.getLocalGraphicsEnvironment();
GraphicsDevice gd = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = gd.getDefaultConfiguration();
BufferedImage image = gc.createCompatibleImage(w, h);
Graphics2D g = image.createGraphics();
icon.paintIcon(null, g, 0, 0);
g.dispose();
return image;
}
/**
* This method returns a buffered image with the contents of an image.
* "Converting" by drawing on image, but there seems to be no other way.
* <P>
* ATTENTION: Needs to be public. Used by PowerFolder Pro code.
*
* @param image
* @return the buffered image.
*/
public static BufferedImage toBufferedImage(Image image) {
if (image instanceof BufferedImage) {
return (BufferedImage) image;
}
// This code ensures that all the pixels in the image are loaded
image = new ImageIcon(image).getImage();
// Determine if the image has transparent pixels; for this method's
// implementation, see e661 Determining If an Image Has Transparent
// Pixels
boolean hasAlpha = hasAlpha(image);
// Create a buffered image with a format that's compatible with the
// screen
BufferedImage bimage = null;
GraphicsEnvironment ge = GraphicsEnvironment
.getLocalGraphicsEnvironment();
try {
// Determine the type of transparency of the new buffered image
int transparency = Transparency.OPAQUE;
if (hasAlpha) {
transparency = Transparency.BITMASK;
}
// Create the buffered image
GraphicsDevice gs = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = gs.getDefaultConfiguration();
bimage = gc.createCompatibleImage(image.getWidth(null),
image.getHeight(null), transparency);
} catch (HeadlessException e) {
log.log(Level.FINER, "HeadlessException", e);
}
if (bimage == null) {
// Create a buffered image using the default color model
int type = BufferedImage.TYPE_INT_RGB;
if (hasAlpha) {
type = BufferedImage.TYPE_INT_ARGB;
}
bimage = new BufferedImage(image.getWidth(null),
image.getHeight(null), type);
}
// Copy image to buffered image
Graphics g = bimage.createGraphics();
// Paint the image onto the buffered image
g.drawImage(image, 0, 0, null);
g.dispose();
return bimage;
}
// This method returns true if the specified image has transparent pixels
private static boolean hasAlpha(Image image) {
// If buffered image, the color model is readily available
if (image instanceof BufferedImage) {
BufferedImage bimage = (BufferedImage) image;
return bimage.getColorModel().hasAlpha();
}
// Use a pixel grabber to retrieve the image's color model;
// grabbing a single pixel is usually sufficient
PixelGrabber pg = new PixelGrabber(image, 0, 0, 1, 1, false);
try {
pg.grabPixels();
} catch (InterruptedException e) {
log.log(Level.INFO, "InterruptedException", e);
}
// Get the image's color model
ColorModel cm = pg.getColorModel();
return cm.hasAlpha();
}
/**
* Loads a properties file from classpath.
*
* @param filename
* the filename to load
* @return the properties that have been loaded. Or <code>null</code> if not
* found.
*/
public static Properties loadProperties(String filename) {
Reject.ifBlank(filename, "Properties blank");
BufferedInputStream buf = null;
try {
Properties props = new Properties();
InputStream inputStream = Thread.currentThread()
.getContextClassLoader().getResourceAsStream(filename);
if (inputStream == null) {
throw new FileNotFoundException("File not found");
}
buf = new BufferedInputStream(inputStream);
props.load(buf);
return props;
} catch (IOException ioe) {
log.log(Level.INFO, "Cannot read properties file: " + filename
+ ". " + ioe, ioe);
return null;
} finally {
if (buf != null) {
try {
buf.close();
} catch (Exception e) {
// Ignore
}
}
}
}
}