Project

General

Profile

Download (14 KB) Statistics
| Branch: | Tag: | Revision:
1
/*******************************************************************************
2
 * Copyright (c) 2011 Google, Inc.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *    Google, Inc. - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.wb.swt;
12

    
13
import java.io.File;
14
import java.io.InputStream;
15
import java.lang.reflect.Constructor;
16
import java.lang.reflect.Method;
17
import java.net.MalformedURLException;
18
import java.net.URL;
19
import java.util.HashMap;
20
import java.util.Iterator;
21
import java.util.Map;
22

    
23
import org.eclipse.core.runtime.Platform;
24
import org.eclipse.jface.resource.CompositeImageDescriptor;
25
import org.eclipse.jface.resource.ImageDescriptor;
26
import org.eclipse.swt.graphics.Image;
27
import org.eclipse.swt.graphics.Point;
28
import org.eclipse.swt.graphics.Rectangle;
29
import org.osgi.framework.Bundle;
30

    
31
/**
32
 * Utility class for managing OS resources associated with SWT/JFace controls such as colors, fonts, images,
33
 * etc.
34
 * 
35
 * !!! IMPORTANT !!! Application code must explicitly invoke the <code>dispose()</code> method to release the
36
 * operating system resources managed by cached objects when those objects and OS resources are no longer
37
 * needed (e.g. on application shutdown)
38
 * 
39
 * This class may be freely distributed as part of any application or plugin.
40
 * <p>
41
 * 
42
 * @author scheglov_ke
43
 * @author Dan Rubel
44
 */
45
public class ResourceManager extends SWTResourceManager {
46
	////////////////////////////////////////////////////////////////////////////
47
	//
48
	// Image
49
	//
50
	////////////////////////////////////////////////////////////////////////////
51
	private static Map<ImageDescriptor, Image> m_descriptorImageMap = new HashMap<ImageDescriptor, Image>();
52
	/**
53
	 * Returns an {@link ImageDescriptor} stored in the file at the specified path relative to the specified
54
	 * class.
55
	 * 
56
	 * @param clazz
57
	 *            the {@link Class} relative to which to find the image descriptor.
58
	 * @param path
59
	 *            the path to the image file.
60
	 * @return the {@link ImageDescriptor} stored in the file at the specified path.
61
	 */
62
	public static ImageDescriptor getImageDescriptor(Class<?> clazz, String path) {
63
		return ImageDescriptor.createFromFile(clazz, path);
64
	}
65
	/**
66
	 * Returns an {@link ImageDescriptor} stored in the file at the specified path.
67
	 * 
68
	 * @param path
69
	 *            the path to the image file.
70
	 * @return the {@link ImageDescriptor} stored in the file at the specified path.
71
	 */
72
	public static ImageDescriptor getImageDescriptor(String path) {
73
		try {
74
			return ImageDescriptor.createFromURL(new File(path).toURI().toURL());
75
		} catch (MalformedURLException e) {
76
			return null;
77
		}
78
	}
79
	/**
80
	 * Returns an {@link Image} based on the specified {@link ImageDescriptor}.
81
	 * 
82
	 * @param descriptor
83
	 *            the {@link ImageDescriptor} for the {@link Image}.
84
	 * @return the {@link Image} based on the specified {@link ImageDescriptor}.
85
	 */
86
	public static Image getImage(ImageDescriptor descriptor) {
87
		if (descriptor == null) {
88
			return null;
89
		}
90
		Image image = m_descriptorImageMap.get(descriptor);
91
		if (image == null) {
92
			image = descriptor.createImage();
93
			m_descriptorImageMap.put(descriptor, image);
94
		}
95
		return image;
96
	}
97
	/**
98
	 * Maps images to decorated images.
99
	 */
100
	@SuppressWarnings("unchecked")
101
	private static Map<Image, Map<Image, Image>>[] m_decoratedImageMap = new Map[LAST_CORNER_KEY];
102
	/**
103
	 * Returns an {@link Image} composed of a base image decorated by another image.
104
	 * 
105
	 * @param baseImage
106
	 *            the base {@link Image} that should be decorated.
107
	 * @param decorator
108
	 *            the {@link Image} to decorate the base image.
109
	 * @return {@link Image} The resulting decorated image.
110
	 */
111
	public static Image decorateImage(Image baseImage, Image decorator) {
112
		return decorateImage(baseImage, decorator, BOTTOM_RIGHT);
113
	}
114
	/**
115
	 * Returns an {@link Image} composed of a base image decorated by another image.
116
	 * 
117
	 * @param baseImage
118
	 *            the base {@link Image} that should be decorated.
119
	 * @param decorator
120
	 *            the {@link Image} to decorate the base image.
121
	 * @param corner
122
	 *            the corner to place decorator image.
123
	 * @return the resulting decorated {@link Image}.
124
	 */
125
	public static Image decorateImage(final Image baseImage, final Image decorator, final int corner) {
126
		if (corner <= 0 || corner >= LAST_CORNER_KEY) {
127
			throw new IllegalArgumentException("Wrong decorate corner");
128
		}
129
		Map<Image, Map<Image, Image>> cornerDecoratedImageMap = m_decoratedImageMap[corner];
130
		if (cornerDecoratedImageMap == null) {
131
			cornerDecoratedImageMap = new HashMap<Image, Map<Image, Image>>();
132
			m_decoratedImageMap[corner] = cornerDecoratedImageMap;
133
		}
134
		Map<Image, Image> decoratedMap = cornerDecoratedImageMap.get(baseImage);
135
		if (decoratedMap == null) {
136
			decoratedMap = new HashMap<Image, Image>();
137
			cornerDecoratedImageMap.put(baseImage, decoratedMap);
138
		}
139
		//
140
		Image result = decoratedMap.get(decorator);
141
		if (result == null) {
142
			final Rectangle bib = baseImage.getBounds();
143
			final Rectangle dib = decorator.getBounds();
144
			final Point baseImageSize = new Point(bib.width, bib.height);
145
			CompositeImageDescriptor compositImageDesc = new CompositeImageDescriptor() {
146
				@Override
147
				protected void drawCompositeImage(int width, int height) {
148
					drawImage(baseImage.getImageData(), 0, 0);
149
					if (corner == TOP_LEFT) {
150
						drawImage(decorator.getImageData(), 0, 0);
151
					} else if (corner == TOP_RIGHT) {
152
						drawImage(decorator.getImageData(), bib.width - dib.width, 0);
153
					} else if (corner == BOTTOM_LEFT) {
154
						drawImage(decorator.getImageData(), 0, bib.height - dib.height);
155
					} else if (corner == BOTTOM_RIGHT) {
156
						drawImage(decorator.getImageData(), bib.width - dib.width, bib.height - dib.height);
157
					}
158
				}
159
				@Override
160
				protected Point getSize() {
161
					return baseImageSize;
162
				}
163
			};
164
			//
165
			result = compositImageDesc.createImage();
166
			decoratedMap.put(decorator, result);
167
		}
168
		return result;
169
	}
170
	/**
171
	 * Dispose all of the cached images.
172
	 */
173
	public static void disposeImages() {
174
		SWTResourceManager.disposeImages();
175
		// dispose ImageDescriptor images
176
		{
177
			for (Iterator<Image> I = m_descriptorImageMap.values().iterator(); I.hasNext();) {
178
				I.next().dispose();
179
			}
180
			m_descriptorImageMap.clear();
181
		}
182
		// dispose decorated images
183
		for (int i = 0; i < m_decoratedImageMap.length; i++) {
184
			Map<Image, Map<Image, Image>> cornerDecoratedImageMap = m_decoratedImageMap[i];
185
			if (cornerDecoratedImageMap != null) {
186
				for (Map<Image, Image> decoratedMap : cornerDecoratedImageMap.values()) {
187
					for (Image image : decoratedMap.values()) {
188
						image.dispose();
189
					}
190
					decoratedMap.clear();
191
				}
192
				cornerDecoratedImageMap.clear();
193
			}
194
		}
195
		// dispose plugin images
196
		{
197
			for (Iterator<Image> I = m_URLImageMap.values().iterator(); I.hasNext();) {
198
				I.next().dispose();
199
			}
200
			m_URLImageMap.clear();
201
		}
202
	}
203
	////////////////////////////////////////////////////////////////////////////
204
	//
205
	// Plugin images support
206
	//
207
	////////////////////////////////////////////////////////////////////////////
208
	/**
209
	 * Maps URL to images.
210
	 */
211
	private static Map<String, Image> m_URLImageMap = new HashMap<String, Image>();
212
	/**
213
	 * Provider for plugin resources, used by WindowBuilder at design time.
214
	 */
215
	public interface PluginResourceProvider {
216
		URL getEntry(String symbolicName, String path);
217
	}
218
	/**
219
	 * Instance of {@link PluginResourceProvider}, used by WindowBuilder at design time.
220
	 */
221
	private static PluginResourceProvider m_designTimePluginResourceProvider = null;
222
	/**
223
	 * Returns an {@link Image} based on a plugin and file path.
224
	 * 
225
	 * @param plugin
226
	 *            the plugin {@link Object} containing the image
227
	 * @param name
228
	 *            the path to the image within the plugin
229
	 * @return the {@link Image} stored in the file at the specified path
230
	 * 
231
	 * @deprecated Use {@link #getPluginImage(String, String)} instead.
232
	 */
233
	@Deprecated
234
	public static Image getPluginImage(Object plugin, String name) {
235
		try {
236
			URL url = getPluginImageURL(plugin, name);
237
			if (url != null) {
238
				return getPluginImageFromUrl(url);
239
			}
240
		} catch (Throwable e) {
241
			// Ignore any exceptions
242
		}
243
		return null;
244
	}
245
	/**
246
	 * Returns an {@link Image} based on a {@link Bundle} and resource entry path.
247
	 * 
248
	 * @param symbolicName
249
	 *            the symbolic name of the {@link Bundle}.
250
	 * @param path
251
	 *            the path of the resource entry.
252
	 * @return the {@link Image} stored in the file at the specified path.
253
	 */
254
	public static Image getPluginImage(String symbolicName, String path) {
255
		try {
256
			URL url = getPluginImageURL(symbolicName, path);
257
			if (url != null) {
258
				return getPluginImageFromUrl(url);
259
			}
260
		} catch (Throwable e) {
261
			// Ignore any exceptions
262
		}
263
		return null;
264
	}
265
	/**
266
	 * Returns an {@link Image} based on given {@link URL}.
267
	 */
268
	private static Image getPluginImageFromUrl(URL url) {
269
		try {
270
			try {
271
				String key = url.toExternalForm();
272
				Image image = m_URLImageMap.get(key);
273
				if (image == null) {
274
					InputStream stream = url.openStream();
275
					try {
276
						image = getImage(stream);
277
						m_URLImageMap.put(key, image);
278
					} finally {
279
						stream.close();
280
					}
281
				}
282
				return image;
283
			} catch (Throwable e) {
284
				// Ignore any exceptions
285
			}
286
		} catch (Throwable e) {
287
			// Ignore any exceptions
288
		}
289
		return null;
290
	}
291
	/**
292
	 * Returns an {@link ImageDescriptor} based on a plugin and file path.
293
	 * 
294
	 * @param plugin
295
	 *            the plugin {@link Object} containing the image.
296
	 * @param name
297
	 *            the path to th eimage within the plugin.
298
	 * @return the {@link ImageDescriptor} stored in the file at the specified path.
299
	 * 
300
	 * @deprecated Use {@link #getPluginImageDescriptor(String, String)} instead.
301
	 */
302
	@Deprecated
303
	public static ImageDescriptor getPluginImageDescriptor(Object plugin, String name) {
304
		try {
305
			try {
306
				URL url = getPluginImageURL(plugin, name);
307
				return ImageDescriptor.createFromURL(url);
308
			} catch (Throwable e) {
309
				// Ignore any exceptions
310
			}
311
		} catch (Throwable e) {
312
			// Ignore any exceptions
313
		}
314
		return null;
315
	}
316
	/**
317
	 * Returns an {@link ImageDescriptor} based on a {@link Bundle} and resource entry path.
318
	 * 
319
	 * @param symbolicName
320
	 *            the symbolic name of the {@link Bundle}.
321
	 * @param path
322
	 *            the path of the resource entry.
323
	 * @return the {@link ImageDescriptor} based on a {@link Bundle} and resource entry path.
324
	 */
325
	public static ImageDescriptor getPluginImageDescriptor(String symbolicName, String path) {
326
		try {
327
			URL url = getPluginImageURL(symbolicName, path);
328
			if (url != null) {
329
				return ImageDescriptor.createFromURL(url);
330
			}
331
		} catch (Throwable e) {
332
			// Ignore any exceptions
333
		}
334
		return null;
335
	}
336
	/**
337
	 * Returns an {@link URL} based on a {@link Bundle} and resource entry path.
338
	 */
339
	private static URL getPluginImageURL(String symbolicName, String path) {
340
		// try runtime plugins
341
		{
342
			Bundle bundle = Platform.getBundle(symbolicName);
343
			if (bundle != null) {
344
				return bundle.getEntry(path);
345
			}
346
		}
347
		// try design time provider
348
		if (m_designTimePluginResourceProvider != null) {
349
			return m_designTimePluginResourceProvider.getEntry(symbolicName, path);
350
		}
351
		// no such resource
352
		return null;
353
	}
354
	/**
355
	 * Returns an {@link URL} based on a plugin and file path.
356
	 * 
357
	 * @param plugin
358
	 *            the plugin {@link Object} containing the file path.
359
	 * @param name
360
	 *            the file path.
361
	 * @return the {@link URL} representing the file at the specified path.
362
	 * @throws Exception
363
	 */
364
	private static URL getPluginImageURL(Object plugin, String name) throws Exception {
365
		// try to work with 'plugin' as with OSGI BundleContext
366
		try {
367
			Class<?> BundleClass = Class.forName("org.osgi.framework.Bundle"); //$NON-NLS-1$
368
			Class<?> BundleContextClass = Class.forName("org.osgi.framework.BundleContext"); //$NON-NLS-1$
369
			if (BundleContextClass.isAssignableFrom(plugin.getClass())) {
370
				Method getBundleMethod = BundleContextClass.getMethod("getBundle", new Class[0]); //$NON-NLS-1$
371
				Object bundle = getBundleMethod.invoke(plugin, new Object[0]);
372
				//
373
				Class<?> PathClass = Class.forName("org.eclipse.core.runtime.Path"); //$NON-NLS-1$
374
				Constructor<?> pathConstructor = PathClass.getConstructor(new Class[]{String.class});
375
				Object path = pathConstructor.newInstance(new Object[]{name});
376
				//
377
				Class<?> IPathClass = Class.forName("org.eclipse.core.runtime.IPath"); //$NON-NLS-1$
378
				Class<?> PlatformClass = Class.forName("org.eclipse.core.runtime.Platform"); //$NON-NLS-1$
379
				Method findMethod = PlatformClass.getMethod("find", new Class[]{BundleClass, IPathClass}); //$NON-NLS-1$
380
				return (URL) findMethod.invoke(null, new Object[]{bundle, path});
381
			}
382
		} catch (Throwable e) {
383
			// Ignore any exceptions
384
		}
385
		// else work with 'plugin' as with usual Eclipse plugin
386
		{
387
			Class<?> PluginClass = Class.forName("org.eclipse.core.runtime.Plugin"); //$NON-NLS-1$
388
			if (PluginClass.isAssignableFrom(plugin.getClass())) {
389
				//
390
				Class<?> PathClass = Class.forName("org.eclipse.core.runtime.Path"); //$NON-NLS-1$
391
				Constructor<?> pathConstructor = PathClass.getConstructor(new Class[]{String.class});
392
				Object path = pathConstructor.newInstance(new Object[]{name});
393
				//
394
				Class<?> IPathClass = Class.forName("org.eclipse.core.runtime.IPath"); //$NON-NLS-1$
395
				Method findMethod = PluginClass.getMethod("find", new Class[]{IPathClass}); //$NON-NLS-1$
396
				return (URL) findMethod.invoke(plugin, new Object[]{path});
397
			}
398
		}
399
		return null;
400
	}
401
	////////////////////////////////////////////////////////////////////////////
402
	//
403
	// General
404
	//
405
	////////////////////////////////////////////////////////////////////////////
406
	/**
407
	 * Dispose of cached objects and their underlying OS resources. This should only be called when the cached
408
	 * objects are no longer needed (e.g. on application shutdown).
409
	 */
410
	public static void dispose() {
411
		disposeColors();
412
		disposeFonts();
413
		disposeImages();
414
	}
415
}
(1-1/2)