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