Home | History | Annotate | Download | only in ddmuilib
      1 /*
      2  * Copyright (C) 2007 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.ddmuilib;
     18 
     19 import com.android.ddmlib.Log;
     20 
     21 import org.eclipse.jface.resource.ImageDescriptor;
     22 import org.eclipse.swt.SWT;
     23 import org.eclipse.swt.graphics.Color;
     24 import org.eclipse.swt.graphics.GC;
     25 import org.eclipse.swt.graphics.Image;
     26 import org.eclipse.swt.widgets.Display;
     27 
     28 import java.io.InputStream;
     29 import java.net.URL;
     30 import java.util.HashMap;
     31 
     32 /**
     33  * Class to load images stored in a jar file.
     34  * All images are loaded from /images/<var>filename</var>
     35  *
     36  * Because Java requires to know the jar file in which to load the image from, a class is required
     37  * when getting the instance. Instances are cached and associated to the class passed to
     38  * {@link #getLoader(Class)}.
     39  *
     40  * {@link #getDdmUiLibLoader()} use {@link ImageLoader#getClass()} as the class. This is to be used
     41  * to load images from ddmuilib.
     42  *
     43  * Loaded images are stored so that 2 calls with the same filename will return the same object.
     44  * This also means that {@link Image} object returned by the loader should never be disposed.
     45  *
     46  */
     47 public class ImageLoader {
     48 
     49     private static final String PATH = "/images/"; //$NON-NLS-1$
     50 
     51     private final HashMap<String, Image> mLoadedImages = new HashMap<String, Image>();
     52     private static final HashMap<Class<?>, ImageLoader> mInstances =
     53             new HashMap<Class<?>, ImageLoader>();
     54     private final Class<?> mClass;
     55 
     56     /**
     57      * Private constructor, creating an instance associated with a class.
     58      * The class is used to identify which jar file the images are loaded from.
     59      */
     60     private ImageLoader(Class<?> theClass) {
     61         if (theClass == null) {
     62             theClass = ImageLoader.class;
     63         }
     64         mClass = theClass;
     65     }
     66 
     67     /**
     68      * Returns the {@link ImageLoader} instance to load images from ddmuilib.jar
     69      */
     70     public static ImageLoader getDdmUiLibLoader() {
     71         return getLoader(null);
     72     }
     73 
     74     /**
     75      * Returns an {@link ImageLoader} to load images based on a given class.
     76      *
     77      * The loader will load images from the jar from which the class was loaded. using
     78      * {@link Class#getResource(String)} and {@link Class#getResourceAsStream(String)}.
     79      *
     80      * Since all images are loaded using the path /images/<var>filename</var>, any class from the
     81      * jar will work. However since the loader is cached and reused when the query provides the same
     82      * class instance, and since the loader will also cache the loaded images, it is recommended
     83      * to always use the same class for a given Jar file.
     84      *
     85      */
     86     public static ImageLoader getLoader(Class<?> theClass) {
     87         ImageLoader instance = mInstances.get(theClass);
     88         if (instance == null) {
     89             instance = new ImageLoader(theClass);
     90             mInstances.put(theClass, instance);
     91         }
     92 
     93         return instance;
     94     }
     95 
     96     /**
     97      * Disposes all images for all instances.
     98      * This should only be called when the program exits.
     99      */
    100     public static void dispose() {
    101         for (ImageLoader loader : mInstances.values()) {
    102             loader.doDispose();
    103         }
    104     }
    105 
    106     private synchronized void doDispose() {
    107         for (Image image : mLoadedImages.values()) {
    108             image.dispose();
    109         }
    110 
    111         mLoadedImages.clear();
    112     }
    113 
    114     /**
    115      * Returns an {@link ImageDescriptor} for a given filename.
    116      *
    117      * This searches for an image located at /images/<var>filename</var>.
    118      *
    119      * @param filename the filename of the image to load.
    120      */
    121     public ImageDescriptor loadDescriptor(String filename) {
    122         URL url = mClass.getResource(PATH + filename);
    123         // TODO cache in a map
    124         return ImageDescriptor.createFromURL(url);
    125     }
    126 
    127     /**
    128      * Returns an {@link Image} for a given filename.
    129      *
    130      * This searches for an image located at /images/<var>filename</var>.
    131      *
    132      * @param filename the filename of the image to load.
    133      * @param display the Display object
    134      */
    135     public synchronized Image loadImage(String filename, Display display) {
    136         Image img = mLoadedImages.get(filename);
    137         if (img == null) {
    138             String tmp = PATH + filename;
    139             InputStream imageStream = mClass.getResourceAsStream(tmp);
    140 
    141             if (imageStream != null) {
    142                 img = new Image(display, imageStream);
    143                 mLoadedImages.put(filename, img);
    144             }
    145 
    146             if (img == null) {
    147                 throw new RuntimeException("Failed to load " + tmp);
    148             }
    149         }
    150 
    151         return img;
    152     }
    153 
    154     /**
    155      * Loads an image from a resource. This method used a class to locate the
    156      * resources, and then load the filename from /images inside the resources.<br>
    157      * Extra parameters allows for creation of a replacement image of the
    158      * loading failed.
    159      *
    160      * @param display the Display object
    161      * @param fileName the file name
    162      * @param width optional width to create replacement Image. If -1, null be
    163      *            be returned if the loading fails.
    164      * @param height optional height to create replacement Image. If -1, null be
    165      *            be returned if the loading fails.
    166      * @param phColor optional color to create replacement Image. If null, Blue
    167      *            color will be used.
    168      * @return a new Image or null if the loading failed and the optional
    169      *         replacement size was -1
    170      */
    171     public Image loadImage(Display display, String fileName, int width, int height,
    172             Color phColor) {
    173 
    174         Image img = loadImage(fileName, display);
    175 
    176         if (img == null) {
    177             Log.w("ddms", "Couldn't load " + fileName);
    178             // if we had the extra parameter to create replacement image then we
    179             // create and return it.
    180             if (width != -1 && height != -1) {
    181                 return createPlaceHolderArt(display, width, height,
    182                         phColor != null ? phColor : display
    183                                 .getSystemColor(SWT.COLOR_BLUE));
    184             }
    185 
    186             // otherwise, just return null
    187             return null;
    188         }
    189 
    190         return img;
    191     }
    192 
    193     /**
    194      * Create place-holder art with the specified color.
    195      */
    196     public static Image createPlaceHolderArt(Display display, int width,
    197             int height, Color color) {
    198         Image img = new Image(display, width, height);
    199         GC gc = new GC(img);
    200         gc.setForeground(color);
    201         gc.drawLine(0, 0, width, height);
    202         gc.drawLine(0, height - 1, width, -1);
    203         gc.dispose();
    204         return img;
    205     }
    206 }
    207