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