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
9 * Google, Inc. - initial API and implementation
10 *******************************************************************************/
11 package org
.eclipse
.wb
.swt
;
14 import java
.io
.InputStream
;
15 import java
.lang
.reflect
.Constructor
;
16 import java
.lang
.reflect
.Method
;
17 import java
.net
.MalformedURLException
;
19 import java
.util
.HashMap
;
20 import java
.util
.Iterator
;
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
;
32 * Utility class for managing OS resources associated with SWT/JFace controls such as colors, fonts, images,
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)
39 * This class may be freely distributed as part of any application or plugin.
45 public class ResourceManager
extends SWTResourceManager
{
46 ////////////////////////////////////////////////////////////////////////////
50 ////////////////////////////////////////////////////////////////////////////
51 private static Map
<ImageDescriptor
, Image
> m_descriptorImageMap
= new HashMap
<ImageDescriptor
, Image
>();
53 * Returns an {@link ImageDescriptor} stored in the file at the specified path relative to the specified
57 * the {@link Class} relative to which to find the image descriptor.
59 * the path to the image file.
60 * @return the {@link ImageDescriptor} stored in the file at the specified path.
62 public static ImageDescriptor
getImageDescriptor(Class
<?
> clazz
, String path
) {
63 return ImageDescriptor
.createFromFile(clazz
, path
);
66 * Returns an {@link ImageDescriptor} stored in the file at the specified path.
69 * the path to the image file.
70 * @return the {@link ImageDescriptor} stored in the file at the specified path.
72 public static ImageDescriptor
getImageDescriptor(String path
) {
74 return ImageDescriptor
.createFromURL(new File(path
).toURI().toURL());
75 } catch (MalformedURLException e
) {
80 * Returns an {@link Image} based on the specified {@link ImageDescriptor}.
83 * the {@link ImageDescriptor} for the {@link Image}.
84 * @return the {@link Image} based on the specified {@link ImageDescriptor}.
86 public static Image
getImage(ImageDescriptor descriptor
) {
87 if (descriptor
== null) {
90 Image image
= m_descriptorImageMap
.get(descriptor
);
92 image
= descriptor
.createImage();
93 m_descriptorImageMap
.put(descriptor
, image
);
98 * Maps images to decorated images.
100 @SuppressWarnings("unchecked")
101 private static Map
<Image
, Map
<Image
, Image
>>[] m_decoratedImageMap
= new Map
[LAST_CORNER_KEY
];
103 * Returns an {@link Image} composed of a base image decorated by another image.
106 * the base {@link Image} that should be decorated.
108 * the {@link Image} to decorate the base image.
109 * @return {@link Image} The resulting decorated image.
111 public static Image
decorateImage(Image baseImage
, Image decorator
) {
112 return decorateImage(baseImage
, decorator
, BOTTOM_RIGHT
);
115 * Returns an {@link Image} composed of a base image decorated by another image.
118 * the base {@link Image} that should be decorated.
120 * the {@link Image} to decorate the base image.
122 * the corner to place decorator image.
123 * @return the resulting decorated {@link Image}.
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");
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
;
134 Map
<Image
, Image
> decoratedMap
= cornerDecoratedImageMap
.get(baseImage
);
135 if (decoratedMap
== null) {
136 decoratedMap
= new HashMap
<Image
, Image
>();
137 cornerDecoratedImageMap
.put(baseImage
, decoratedMap
);
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() {
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
);
160 protected Point
getSize() {
161 return baseImageSize
;
165 result
= compositImageDesc
.createImage();
166 decoratedMap
.put(decorator
, result
);
171 * Dispose all of the cached images.
173 public static void disposeImages() {
174 SWTResourceManager
.disposeImages();
175 // dispose ImageDescriptor images
177 for (Iterator
<Image
> I
= m_descriptorImageMap
.values().iterator(); I
.hasNext();) {
180 m_descriptorImageMap
.clear();
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()) {
190 decoratedMap
.clear();
192 cornerDecoratedImageMap
.clear();
195 // dispose plugin images
197 for (Iterator
<Image
> I
= m_URLImageMap
.values().iterator(); I
.hasNext();) {
200 m_URLImageMap
.clear();
203 ////////////////////////////////////////////////////////////////////////////
205 // Plugin images support
207 ////////////////////////////////////////////////////////////////////////////
209 * Maps URL to images.
211 private static Map
<String
, Image
> m_URLImageMap
= new HashMap
<String
, Image
>();
213 * Provider for plugin resources, used by WindowBuilder at design time.
215 public interface PluginResourceProvider
{
216 URL
getEntry(String symbolicName
, String path
);
219 * Instance of {@link PluginResourceProvider}, used by WindowBuilder at design time.
221 private static PluginResourceProvider m_designTimePluginResourceProvider
= null;
223 * Returns an {@link Image} based on a plugin and file path.
226 * the plugin {@link Object} containing the image
228 * the path to the image within the plugin
229 * @return the {@link Image} stored in the file at the specified path
231 * @deprecated Use {@link #getPluginImage(String, String)} instead.
234 public static Image
getPluginImage(Object plugin
, String name
) {
236 URL url
= getPluginImageURL(plugin
, name
);
238 return getPluginImageFromUrl(url
);
240 } catch (Throwable e
) {
241 // Ignore any exceptions
246 * Returns an {@link Image} based on a {@link Bundle} and resource entry path.
248 * @param symbolicName
249 * the symbolic name of the {@link Bundle}.
251 * the path of the resource entry.
252 * @return the {@link Image} stored in the file at the specified path.
254 public static Image
getPluginImage(String symbolicName
, String path
) {
256 URL url
= getPluginImageURL(symbolicName
, path
);
258 return getPluginImageFromUrl(url
);
260 } catch (Throwable e
) {
261 // Ignore any exceptions
266 * Returns an {@link Image} based on given {@link URL}.
268 private static Image
getPluginImageFromUrl(URL url
) {
271 String key
= url
.toExternalForm();
272 Image image
= m_URLImageMap
.get(key
);
274 InputStream stream
= url
.openStream();
276 image
= getImage(stream
);
277 m_URLImageMap
.put(key
, image
);
283 } catch (Throwable e
) {
284 // Ignore any exceptions
286 } catch (Throwable e
) {
287 // Ignore any exceptions
292 * Returns an {@link ImageDescriptor} based on a plugin and file path.
295 * the plugin {@link Object} containing the image.
297 * the path to th eimage within the plugin.
298 * @return the {@link ImageDescriptor} stored in the file at the specified path.
300 * @deprecated Use {@link #getPluginImageDescriptor(String, String)} instead.
303 public static ImageDescriptor
getPluginImageDescriptor(Object plugin
, String name
) {
306 URL url
= getPluginImageURL(plugin
, name
);
307 return ImageDescriptor
.createFromURL(url
);
308 } catch (Throwable e
) {
309 // Ignore any exceptions
311 } catch (Throwable e
) {
312 // Ignore any exceptions
317 * Returns an {@link ImageDescriptor} based on a {@link Bundle} and resource entry path.
319 * @param symbolicName
320 * the symbolic name of the {@link Bundle}.
322 * the path of the resource entry.
323 * @return the {@link ImageDescriptor} based on a {@link Bundle} and resource entry path.
325 public static ImageDescriptor
getPluginImageDescriptor(String symbolicName
, String path
) {
327 URL url
= getPluginImageURL(symbolicName
, path
);
329 return ImageDescriptor
.createFromURL(url
);
331 } catch (Throwable e
) {
332 // Ignore any exceptions
337 * Returns an {@link URL} based on a {@link Bundle} and resource entry path.
339 private static URL
getPluginImageURL(String symbolicName
, String path
) {
340 // try runtime plugins
342 Bundle bundle
= Platform
.getBundle(symbolicName
);
343 if (bundle
!= null) {
344 return bundle
.getEntry(path
);
347 // try design time provider
348 if (m_designTimePluginResourceProvider
!= null) {
349 return m_designTimePluginResourceProvider
.getEntry(symbolicName
, path
);
355 * Returns an {@link URL} based on a plugin and file path.
358 * the plugin {@link Object} containing the file path.
361 * @return the {@link URL} representing the file at the specified path.
364 private static URL
getPluginImageURL(Object plugin
, String name
) throws Exception
{
365 // try to work with 'plugin' as with OSGI BundleContext
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]);
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
});
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
});
382 } catch (Throwable e
) {
383 // Ignore any exceptions
385 // else work with 'plugin' as with usual Eclipse plugin
387 Class
<?
> PluginClass
= Class
.forName("org.eclipse.core.runtime.Plugin"); //$NON-NLS-1$
388 if (PluginClass
.isAssignableFrom(plugin
.getClass())) {
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
});
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
});
401 ////////////////////////////////////////////////////////////////////////////
405 ////////////////////////////////////////////////////////////////////////////
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).
410 public static void dispose() {