package org.archstudio.utils.resources.swt; import java.net.URL; import java.util.Map; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtensionRegistry; import org.eclipse.core.runtime.Platform; import org.eclipse.jface.action.IAction; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Display; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import com.google.common.cache.RemovalListener; import com.google.common.cache.RemovalNotification; import com.google.common.collect.Maps; /** * General utilities for working with images. * * @author sahendrickson@gmail.com (Scott A. Hendrickson) */ public class ImageUtils { /** Mapping from class to icon. */ private static final Map<Class<?>, URL> typeToIcon16Url = Maps.newHashMap(); static { // Read plug-in extensions and populate typeToIcon16Url. IExtensionRegistry reg = Platform.getExtensionRegistry(); if (reg != null) { for (IConfigurationElement configurationElement : reg .getConfigurationElementsFor("org.archstudio.utils.resources")) { if ("Icon".equals(configurationElement.getName())) { String bundleName = configurationElement.getDeclaringExtension().getContributor().getName(); String icon16Path = configurationElement.getAttribute("icon16"); for (IConfigurationElement type : configurationElement.getChildren("Type")) { String className = type.getAttribute("class"); try { Class<?> typeClass = Platform.getBundle(bundleName).loadClass(className); URL imageURL = Platform.getBundle(bundleName).getEntry(icon16Path); typeToIcon16Url.put(typeClass, imageURL); } catch (ClassNotFoundException cnfe) { } } } } } } // A dynamically created map from Display to URL to cached Image. private static final LoadingCache<Display, LoadingCache<URL, Image>> imageCache = CacheBuilder .newBuilder().removalListener(new RemovalListener<Display, LoadingCache<URL, Image>>() { @Override public void onRemoval(RemovalNotification<Display, LoadingCache<URL, Image>> notification) { notification.getValue().invalidateAll(); } }).build(new CacheLoader<Display, LoadingCache<URL, Image>>() { @Override public LoadingCache<URL, Image> load(final Display display) throws Exception { display.disposeExec(new Runnable() { @Override public void run() { imageCache.invalidate(display); } }); return CacheBuilder.newBuilder().removalListener(new RemovalListener<URL, Image>() { @Override public void onRemoval(RemovalNotification<URL, Image> notification) { notification.getValue().dispose(); } }).build(new CacheLoader<URL, Image>() { @Override public Image load(URL key) throws Exception { try { if (key != null) { return new Image(display, key.openStream()); } } catch (Exception ignored) { } return null; } }); } }); /** * Returns a (cached) image loaded from the specified URL, or <code>null</code> if the URL does * not resolve to an image. * * @param display The Display to use to create the image. * @param url The url to the image file. * @return The Image for the given URL, or <code>null</code> if the Image cannot be created from * the URL. */ public static final Image getImage(Display display, URL url) { if (url != null) { return imageCache.getUnchecked(display).getUnchecked(url); } return null; } /** * Returns a 16x16 icon image for the specified type, or <code>null</code> if the type is not * registered. The registered types are read from the org.archstudio.utils.resources extension. * * @param display The Display to use to create the image. * @param forClass The class for which the icon is being requested. * @return The Image for the given class, or <code>null</code> if the Image cannot be created from * the URL. */ public static final Image getIcon16ForType(Display display, Class<?> forClass) { URL url = typeToIcon16Url.get(forClass); if (url != null) { return imageCache.getUnchecked(display).getUnchecked(url); } return null; } /** * Like {@link ImageDescriptor#createFromImage(Image)}, except returns <code>null</code> if the * image is <code>null</code>. Useful, for example, for returning {@link ImageDescriptor}s from * {@link IAction#getImageDescriptor()}. * * @param image The image from which to get the image descriptor. * @return an {@link ImageDescriptor} for the provided image, or <code>null</code> if the image * was <code>null</code>. */ public static final ImageDescriptor toImageDescriptor(Image image) { return image != null ? ImageDescriptor.createFromImage(image) : null; } }