• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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      */
ImageLoader(Class<?> theClass)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      */
getDdmUiLibLoader()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      */
getLoader(Class<?> theClass)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      */
dispose()100     public static void dispose() {
101         for (ImageLoader loader : mInstances.values()) {
102             loader.doDispose();
103         }
104     }
105 
doDispose()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      */
loadDescriptor(String filename)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      */
loadImage(String filename, Display display)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      */
loadImage(Display display, String fileName, int width, int height, Color phColor)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      */
createPlaceHolderArt(Display display, int width, int height, Color color)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