Project

General

Profile

Download (14.2 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.FileInputStream;
14
import java.io.IOException;
15
import java.io.InputStream;
16
import java.util.HashMap;
17
import java.util.Map;
18

    
19
import org.eclipse.swt.SWT;
20
import org.eclipse.swt.graphics.Color;
21
import org.eclipse.swt.graphics.Cursor;
22
import org.eclipse.swt.graphics.Font;
23
import org.eclipse.swt.graphics.FontData;
24
import org.eclipse.swt.graphics.GC;
25
import org.eclipse.swt.graphics.Image;
26
import org.eclipse.swt.graphics.ImageData;
27
import org.eclipse.swt.graphics.RGB;
28
import org.eclipse.swt.graphics.Rectangle;
29
import org.eclipse.swt.widgets.Display;
30

    
31
/**
32
 * Utility class for managing OS resources associated with SWT controls such as colors, fonts, images, etc.
33
 * <p>
34
 * !!! IMPORTANT !!! Application code must explicitly invoke the <code>dispose()</code> method to release the
35
 * operating system resources managed by cached objects when those objects and OS resources are no longer
36
 * needed (e.g. on application shutdown)
37
 * <p>
38
 * This class may be freely distributed as part of any application or plugin.
39
 * <p>
40
 * @author scheglov_ke
41
 * @author Dan Rubel
42
 */
43
public class SWTResourceManager {
44
	////////////////////////////////////////////////////////////////////////////
45
	//
46
	// Color
47
	//
48
	////////////////////////////////////////////////////////////////////////////
49
	private static Map<RGB, Color> m_colorMap = new HashMap<RGB, Color>();
50
	/**
51
	 * Returns the system {@link Color} matching the specific ID.
52
	 * 
53
	 * @param systemColorID
54
	 *            the ID value for the color
55
	 * @return the system {@link Color} matching the specific ID
56
	 */
57
	public static Color getColor(int systemColorID) {
58
		Display display = Display.getCurrent();
59
		return display.getSystemColor(systemColorID);
60
	}
61
	/**
62
	 * Returns a {@link Color} given its red, green and blue component values.
63
	 * 
64
	 * @param r
65
	 *            the red component of the color
66
	 * @param g
67
	 *            the green component of the color
68
	 * @param b
69
	 *            the blue component of the color
70
	 * @return the {@link Color} matching the given red, green and blue component values
71
	 */
72
	public static Color getColor(int r, int g, int b) {
73
		return getColor(new RGB(r, g, b));
74
	}
75
	/**
76
	 * Returns a {@link Color} given its RGB value.
77
	 * 
78
	 * @param rgb
79
	 *            the {@link RGB} value of the color
80
	 * @return the {@link Color} matching the RGB value
81
	 */
82
	public static Color getColor(RGB rgb) {
83
		Color color = m_colorMap.get(rgb);
84
		if (color == null) {
85
			Display display = Display.getCurrent();
86
			color = new Color(display, rgb);
87
			m_colorMap.put(rgb, color);
88
		}
89
		return color;
90
	}
91
	/**
92
	 * Dispose of all the cached {@link Color}'s.
93
	 */
94
	public static void disposeColors() {
95
		for (Color color : m_colorMap.values()) {
96
			color.dispose();
97
		}
98
		m_colorMap.clear();
99
	}
100
	////////////////////////////////////////////////////////////////////////////
101
	//
102
	// Image
103
	//
104
	////////////////////////////////////////////////////////////////////////////
105
	/**
106
	 * Maps image paths to images.
107
	 */
108
	private static Map<String, Image> m_imageMap = new HashMap<String, Image>();
109
	/**
110
	 * Returns an {@link Image} encoded by the specified {@link InputStream}.
111
	 * 
112
	 * @param stream
113
	 *            the {@link InputStream} encoding the image data
114
	 * @return the {@link Image} encoded by the specified input stream
115
	 */
116
	protected static Image getImage(InputStream stream) throws IOException {
117
		try {
118
			Display display = Display.getCurrent();
119
			ImageData data = new ImageData(stream);
120
			if (data.transparentPixel > 0) {
121
				return new Image(display, data, data.getTransparencyMask());
122
			}
123
			return new Image(display, data);
124
		} finally {
125
			stream.close();
126
		}
127
	}
128
	/**
129
	 * Returns an {@link Image} stored in the file at the specified path.
130
	 * 
131
	 * @param path
132
	 *            the path to the image file
133
	 * @return the {@link Image} stored in the file at the specified path
134
	 */
135
	public static Image getImage(String path) {
136
		Image image = m_imageMap.get(path);
137
		if (image == null) {
138
			try {
139
				image = getImage(new FileInputStream(path));
140
				m_imageMap.put(path, image);
141
			} catch (Exception e) {
142
				image = getMissingImage();
143
				m_imageMap.put(path, image);
144
			}
145
		}
146
		return image;
147
	}
148
	/**
149
	 * Returns an {@link Image} stored in the file at the specified path relative to the specified class.
150
	 * 
151
	 * @param clazz
152
	 *            the {@link Class} relative to which to find the image
153
	 * @param path
154
	 *            the path to the image file, if starts with <code>'/'</code>
155
	 * @return the {@link Image} stored in the file at the specified path
156
	 */
157
	public static Image getImage(Class<?> clazz, String path) {
158
		String key = clazz.getName() + '|' + path;
159
		Image image = m_imageMap.get(key);
160
		if (image == null) {
161
			try {
162
				image = getImage(clazz.getResourceAsStream(path));
163
				m_imageMap.put(key, image);
164
			} catch (Exception e) {
165
				image = getMissingImage();
166
				m_imageMap.put(key, image);
167
			}
168
		}
169
		return image;
170
	}
171
	private static final int MISSING_IMAGE_SIZE = 10;
172
	/**
173
	 * @return the small {@link Image} that can be used as placeholder for missing image.
174
	 */
175
	private static Image getMissingImage() {
176
		Image image = new Image(Display.getCurrent(), MISSING_IMAGE_SIZE, MISSING_IMAGE_SIZE);
177
		//
178
		GC gc = new GC(image);
179
		gc.setBackground(getColor(SWT.COLOR_RED));
180
		gc.fillRectangle(0, 0, MISSING_IMAGE_SIZE, MISSING_IMAGE_SIZE);
181
		gc.dispose();
182
		//
183
		return image;
184
	}
185
	/**
186
	 * Style constant for placing decorator image in top left corner of base image.
187
	 */
188
	public static final int TOP_LEFT = 1;
189
	/**
190
	 * Style constant for placing decorator image in top right corner of base image.
191
	 */
192
	public static final int TOP_RIGHT = 2;
193
	/**
194
	 * Style constant for placing decorator image in bottom left corner of base image.
195
	 */
196
	public static final int BOTTOM_LEFT = 3;
197
	/**
198
	 * Style constant for placing decorator image in bottom right corner of base image.
199
	 */
200
	public static final int BOTTOM_RIGHT = 4;
201
	/**
202
	 * Internal value.
203
	 */
204
	protected static final int LAST_CORNER_KEY = 5;
205
	/**
206
	 * Maps images to decorated images.
207
	 */
208
	@SuppressWarnings("unchecked")
209
	private static Map<Image, Map<Image, Image>>[] m_decoratedImageMap = new Map[LAST_CORNER_KEY];
210
	/**
211
	 * Returns an {@link Image} composed of a base image decorated by another image.
212
	 * 
213
	 * @param baseImage
214
	 *            the base {@link Image} that should be decorated
215
	 * @param decorator
216
	 *            the {@link Image} to decorate the base image
217
	 * @return {@link Image} The resulting decorated image
218
	 */
219
	public static Image decorateImage(Image baseImage, Image decorator) {
220
		return decorateImage(baseImage, decorator, BOTTOM_RIGHT);
221
	}
222
	/**
223
	 * Returns an {@link Image} composed of a base image decorated by another image.
224
	 * 
225
	 * @param baseImage
226
	 *            the base {@link Image} that should be decorated
227
	 * @param decorator
228
	 *            the {@link Image} to decorate the base image
229
	 * @param corner
230
	 *            the corner to place decorator image
231
	 * @return the resulting decorated {@link Image}
232
	 */
233
	public static Image decorateImage(final Image baseImage, final Image decorator, final int corner) {
234
		if (corner <= 0 || corner >= LAST_CORNER_KEY) {
235
			throw new IllegalArgumentException("Wrong decorate corner");
236
		}
237
		Map<Image, Map<Image, Image>> cornerDecoratedImageMap = m_decoratedImageMap[corner];
238
		if (cornerDecoratedImageMap == null) {
239
			cornerDecoratedImageMap = new HashMap<Image, Map<Image, Image>>();
240
			m_decoratedImageMap[corner] = cornerDecoratedImageMap;
241
		}
242
		Map<Image, Image> decoratedMap = cornerDecoratedImageMap.get(baseImage);
243
		if (decoratedMap == null) {
244
			decoratedMap = new HashMap<Image, Image>();
245
			cornerDecoratedImageMap.put(baseImage, decoratedMap);
246
		}
247
		//
248
		Image result = decoratedMap.get(decorator);
249
		if (result == null) {
250
			Rectangle bib = baseImage.getBounds();
251
			Rectangle dib = decorator.getBounds();
252
			//
253
			result = new Image(Display.getCurrent(), bib.width, bib.height);
254
			//
255
			GC gc = new GC(result);
256
			gc.drawImage(baseImage, 0, 0);
257
			if (corner == TOP_LEFT) {
258
				gc.drawImage(decorator, 0, 0);
259
			} else if (corner == TOP_RIGHT) {
260
				gc.drawImage(decorator, bib.width - dib.width, 0);
261
			} else if (corner == BOTTOM_LEFT) {
262
				gc.drawImage(decorator, 0, bib.height - dib.height);
263
			} else if (corner == BOTTOM_RIGHT) {
264
				gc.drawImage(decorator, bib.width - dib.width, bib.height - dib.height);
265
			}
266
			gc.dispose();
267
			//
268
			decoratedMap.put(decorator, result);
269
		}
270
		return result;
271
	}
272
	/**
273
	 * Dispose all of the cached {@link Image}'s.
274
	 */
275
	public static void disposeImages() {
276
		// dispose loaded images
277
		{
278
			for (Image image : m_imageMap.values()) {
279
				image.dispose();
280
			}
281
			m_imageMap.clear();
282
		}
283
		// dispose decorated images
284
		for (int i = 0; i < m_decoratedImageMap.length; i++) {
285
			Map<Image, Map<Image, Image>> cornerDecoratedImageMap = m_decoratedImageMap[i];
286
			if (cornerDecoratedImageMap != null) {
287
				for (Map<Image, Image> decoratedMap : cornerDecoratedImageMap.values()) {
288
					for (Image image : decoratedMap.values()) {
289
						image.dispose();
290
					}
291
					decoratedMap.clear();
292
				}
293
				cornerDecoratedImageMap.clear();
294
			}
295
		}
296
	}
297
	////////////////////////////////////////////////////////////////////////////
298
	//
299
	// Font
300
	//
301
	////////////////////////////////////////////////////////////////////////////
302
	/**
303
	 * Maps font names to fonts.
304
	 */
305
	private static Map<String, Font> m_fontMap = new HashMap<String, Font>();
306
	/**
307
	 * Maps fonts to their bold versions.
308
	 */
309
	private static Map<Font, Font> m_fontToBoldFontMap = new HashMap<Font, Font>();
310
	/**
311
	 * Returns a {@link Font} based on its name, height and style.
312
	 * 
313
	 * @param name
314
	 *            the name of the font
315
	 * @param height
316
	 *            the height of the font
317
	 * @param style
318
	 *            the style of the font
319
	 * @return {@link Font} The font matching the name, height and style
320
	 */
321
	public static Font getFont(String name, int height, int style) {
322
		return getFont(name, height, style, false, false);
323
	}
324
	/**
325
	 * Returns a {@link Font} based on its name, height and style. Windows-specific strikeout and underline
326
	 * flags are also supported.
327
	 * 
328
	 * @param name
329
	 *            the name of the font
330
	 * @param size
331
	 *            the size of the font
332
	 * @param style
333
	 *            the style of the font
334
	 * @param strikeout
335
	 *            the strikeout flag (warning: Windows only)
336
	 * @param underline
337
	 *            the underline flag (warning: Windows only)
338
	 * @return {@link Font} The font matching the name, height, style, strikeout and underline
339
	 */
340
	public static Font getFont(String name, int size, int style, boolean strikeout, boolean underline) {
341
		String fontName = name + '|' + size + '|' + style + '|' + strikeout + '|' + underline;
342
		Font font = m_fontMap.get(fontName);
343
		if (font == null) {
344
			FontData fontData = new FontData(name, size, style);
345
			if (strikeout || underline) {
346
				try {
347
					Class<?> logFontClass = Class.forName("org.eclipse.swt.internal.win32.LOGFONT"); //$NON-NLS-1$
348
					Object logFont = FontData.class.getField("data").get(fontData); //$NON-NLS-1$
349
					if (logFont != null && logFontClass != null) {
350
						if (strikeout) {
351
							logFontClass.getField("lfStrikeOut").set(logFont, Byte.valueOf((byte) 1)); //$NON-NLS-1$
352
						}
353
						if (underline) {
354
							logFontClass.getField("lfUnderline").set(logFont, Byte.valueOf((byte) 1)); //$NON-NLS-1$
355
						}
356
					}
357
				} catch (Throwable e) {
358
					System.err.println("Unable to set underline or strikeout" + " (probably on a non-Windows platform). " + e); //$NON-NLS-1$ //$NON-NLS-2$
359
				}
360
			}
361
			font = new Font(Display.getCurrent(), fontData);
362
			m_fontMap.put(fontName, font);
363
		}
364
		return font;
365
	}
366
	/**
367
	 * Returns a bold version of the given {@link Font}.
368
	 * 
369
	 * @param baseFont
370
	 *            the {@link Font} for which a bold version is desired
371
	 * @return the bold version of the given {@link Font}
372
	 */
373
	public static Font getBoldFont(Font baseFont) {
374
		Font font = m_fontToBoldFontMap.get(baseFont);
375
		if (font == null) {
376
			FontData fontDatas[] = baseFont.getFontData();
377
			FontData data = fontDatas[0];
378
			font = new Font(Display.getCurrent(), data.getName(), data.getHeight(), SWT.BOLD);
379
			m_fontToBoldFontMap.put(baseFont, font);
380
		}
381
		return font;
382
	}
383
	/**
384
	 * Dispose all of the cached {@link Font}'s.
385
	 */
386
	public static void disposeFonts() {
387
		// clear fonts
388
		for (Font font : m_fontMap.values()) {
389
			font.dispose();
390
		}
391
		m_fontMap.clear();
392
		// clear bold fonts
393
		for (Font font : m_fontToBoldFontMap.values()) {
394
			font.dispose();
395
		}
396
		m_fontToBoldFontMap.clear();
397
	}
398
	////////////////////////////////////////////////////////////////////////////
399
	//
400
	// Cursor
401
	//
402
	////////////////////////////////////////////////////////////////////////////
403
	/**
404
	 * Maps IDs to cursors.
405
	 */
406
	private static Map<Integer, Cursor> m_idToCursorMap = new HashMap<Integer, Cursor>();
407
	/**
408
	 * Returns the system cursor matching the specific ID.
409
	 * 
410
	 * @param id
411
	 *            int The ID value for the cursor
412
	 * @return Cursor The system cursor matching the specific ID
413
	 */
414
	public static Cursor getCursor(int id) {
415
		Integer key = Integer.valueOf(id);
416
		Cursor cursor = m_idToCursorMap.get(key);
417
		if (cursor == null) {
418
			cursor = new Cursor(Display.getDefault(), id);
419
			m_idToCursorMap.put(key, cursor);
420
		}
421
		return cursor;
422
	}
423
	/**
424
	 * Dispose all of the cached cursors.
425
	 */
426
	public static void disposeCursors() {
427
		for (Cursor cursor : m_idToCursorMap.values()) {
428
			cursor.dispose();
429
		}
430
		m_idToCursorMap.clear();
431
	}
432
	////////////////////////////////////////////////////////////////////////////
433
	//
434
	// General
435
	//
436
	////////////////////////////////////////////////////////////////////////////
437
	/**
438
	 * Dispose of cached objects and their underlying OS resources. This should only be called when the cached
439
	 * objects are no longer needed (e.g. on application shutdown).
440
	 */
441
	public static void dispose() {
442
		disposeColors();
443
		disposeImages();
444
		disposeFonts();
445
		disposeCursors();
446
	}
447
}
(2-2/2)