/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.ddmuilib; import com.android.ddmlib.Log; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Display; import java.io.InputStream; import java.net.URL; import java.util.HashMap; /** * Class to load images stored in a jar file. * All images are loaded from /images/<var>filename</var> * * Because Java requires to know the jar file in which to load the image from, a class is required * when getting the instance. Instances are cached and associated to the class passed to * {@link #getLoader(Class)}. * * {@link #getDdmUiLibLoader()} use {@link ImageLoader#getClass()} as the class. This is to be used * to load images from ddmuilib. * * Loaded images are stored so that 2 calls with the same filename will return the same object. * This also means that {@link Image} object returned by the loader should never be disposed. * */ public class ImageLoader { private static final String PATH = "/images/"; //$NON-NLS-1$ private final HashMap<String, Image> mLoadedImages = new HashMap<String, Image>(); private static final HashMap<Class<?>, ImageLoader> mInstances = new HashMap<Class<?>, ImageLoader>(); private final Class<?> mClass; /** * Private constructor, creating an instance associated with a class. * The class is used to identify which jar file the images are loaded from. */ private ImageLoader(Class<?> theClass) { if (theClass == null) { theClass = ImageLoader.class; } mClass = theClass; } /** * Returns the {@link ImageLoader} instance to load images from ddmuilib.jar */ public static ImageLoader getDdmUiLibLoader() { return getLoader(null); } /** * Returns an {@link ImageLoader} to load images based on a given class. * * The loader will load images from the jar from which the class was loaded. using * {@link Class#getResource(String)} and {@link Class#getResourceAsStream(String)}. * * Since all images are loaded using the path /images/<var>filename</var>, any class from the * jar will work. However since the loader is cached and reused when the query provides the same * class instance, and since the loader will also cache the loaded images, it is recommended * to always use the same class for a given Jar file. * */ public static ImageLoader getLoader(Class<?> theClass) { ImageLoader instance = mInstances.get(theClass); if (instance == null) { instance = new ImageLoader(theClass); mInstances.put(theClass, instance); } return instance; } /** * Disposes all images for all instances. * This should only be called when the program exits. */ public static void dispose() { for (ImageLoader loader : mInstances.values()) { loader.doDispose(); } } private synchronized void doDispose() { for (Image image : mLoadedImages.values()) { image.dispose(); } mLoadedImages.clear(); } /** * Returns an {@link ImageDescriptor} for a given filename. * * This searches for an image located at /images/<var>filename</var>. * * @param filename the filename of the image to load. */ public ImageDescriptor loadDescriptor(String filename) { URL url = mClass.getResource(PATH + filename); // TODO cache in a map return ImageDescriptor.createFromURL(url); } /** * Returns an {@link Image} for a given filename. * * This searches for an image located at /images/<var>filename</var>. * * @param filename the filename of the image to load. * @param display the Display object */ public synchronized Image loadImage(String filename, Display display) { Image img = mLoadedImages.get(filename); if (img == null) { String tmp = PATH + filename; InputStream imageStream = mClass.getResourceAsStream(tmp); if (imageStream != null) { img = new Image(display, imageStream); if (img == null) { throw new NullPointerException("couldn't load " + tmp); } mLoadedImages.put(filename, img); return img; } } return img; } /** * Loads an image from a resource. This method used a class to locate the * resources, and then load the filename from /images inside the resources.<br> * Extra parameters allows for creation of a replacement image of the * loading failed. * * @param loader the image loader used. * @param display the Display object * @param fileName the file name * @param width optional width to create replacement Image. If -1, null be * be returned if the loading fails. * @param height optional height to create replacement Image. If -1, null be * be returned if the loading fails. * @param phColor optional color to create replacement Image. If null, Blue * color will be used. * @return a new Image or null if the loading failed and the optional * replacement size was -1 */ public Image loadImage(Display display, String fileName, int width, int height, Color phColor) { Image img = loadImage(fileName, display); if (img == null) { Log.w("ddms", "Couldn't load " + fileName); // if we had the extra parameter to create replacement image then we // create and return it. if (width != -1 && height != -1) { return createPlaceHolderArt(display, width, height, phColor != null ? phColor : display .getSystemColor(SWT.COLOR_BLUE)); } // otherwise, just return null return null; } return img; } /** * Create place-holder art with the specified color. */ public static Image createPlaceHolderArt(Display display, int width, int height, Color color) { Image img = new Image(display, width, height); GC gc = new GC(img); gc.setForeground(color); gc.drawLine(0, 0, width, height); gc.drawLine(0, height - 1, width, -1); gc.dispose(); return img; } }