| /** |
| * Copyright (c) 2011 Google, Inc. |
| * |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Google, Inc. - initial API and implementation |
| * ***************************************************************************** |
| */ |
| package org.eclipse.emf.ecp.cdo.internal.ui; |
| |
| import java.io.FileInputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.graphics.Color; |
| import org.eclipse.swt.graphics.Cursor; |
| import org.eclipse.swt.graphics.Font; |
| import org.eclipse.swt.graphics.FontData; |
| import org.eclipse.swt.graphics.GC; |
| import org.eclipse.swt.graphics.Image; |
| import org.eclipse.swt.graphics.ImageData; |
| import org.eclipse.swt.graphics.RGB; |
| import org.eclipse.swt.graphics.Rectangle; |
| import org.eclipse.swt.widgets.Display; |
| |
| /** |
| * Utility class for managing OS resources associated with SWT controls such as colors, fonts, images, etc. |
| * <p> |
| * !!! IMPORTANT !!! Application code must explicitly invoke the <code>dispose()</code> method to release the operating |
| * system resources managed by cached objects when those objects and OS resources are no longer needed (e.g. on |
| * application shutdown) |
| * <p> |
| * This class may be freely distributed as part of any application or plugin. |
| * <p> |
| * |
| * @author scheglov_ke |
| * @author Dan Rubel |
| * @generated |
| */ |
| public class SWTResourceManager { |
| |
| // ////////////////////////////////////////////////////////////////////////// |
| // |
| // Color |
| // |
| // ////////////////////////////////////////////////////////////////////////// |
| private static Map<RGB, Color> m_colorMap = new HashMap<RGB, Color>(); |
| |
| /** |
| * Returns the system {@link Color} matching the specific ID. |
| * |
| * @param systemColorID |
| * the ID value for the color |
| * @return the system {@link Color} matching the specific ID |
| */ |
| public static Color getColor(int systemColorID) { |
| final Display display = Display.getCurrent(); |
| return display.getSystemColor(systemColorID); |
| } |
| |
| /** |
| * Returns a {@link Color} given its red, green and blue component values. |
| * |
| * @param r |
| * the red component of the color |
| * @param g |
| * the green component of the color |
| * @param b |
| * the blue component of the color |
| * @return the {@link Color} matching the given red, green and blue component values |
| */ |
| public static Color getColor(int r, int g, int b) { |
| return getColor(new RGB(r, g, b)); |
| } |
| |
| /** |
| * Returns a {@link Color} given its RGB value. |
| * |
| * @param rgb |
| * the {@link RGB} value of the color |
| * @return the {@link Color} matching the RGB value |
| */ |
| public static Color getColor(RGB rgb) { |
| Color color = m_colorMap.get(rgb); |
| if (color == null) { |
| final Display display = Display.getCurrent(); |
| color = new Color(display, rgb); |
| m_colorMap.put(rgb, color); |
| } |
| return color; |
| } |
| |
| /** |
| * Dispose of all the cached {@link Color}'s. |
| */ |
| public static void disposeColors() { |
| for (final Color color : m_colorMap.values()) { |
| color.dispose(); |
| } |
| m_colorMap.clear(); |
| } |
| |
| // ////////////////////////////////////////////////////////////////////////// |
| // |
| // Image |
| // |
| // ////////////////////////////////////////////////////////////////////////// |
| /** |
| * Maps image paths to images. |
| */ |
| private static Map<String, Image> m_imageMap = new HashMap<String, Image>(); |
| |
| /** |
| * Returns an {@link Image} encoded by the specified {@link InputStream}. |
| * |
| * @param stream |
| * the {@link InputStream} encoding the image data |
| * @return the {@link Image} encoded by the specified input stream |
| */ |
| protected static Image getImage(InputStream stream) throws IOException { |
| try { |
| final Display display = Display.getCurrent(); |
| final ImageData data = new ImageData(stream); |
| if (data.transparentPixel > 0) { |
| return new Image(display, data, data.getTransparencyMask()); |
| } |
| return new Image(display, data); |
| } finally { |
| stream.close(); |
| } |
| } |
| |
| /** |
| * Returns an {@link Image} stored in the file at the specified path. |
| * |
| * @param path |
| * the path to the image file |
| * @return the {@link Image} stored in the file at the specified path |
| */ |
| public static Image getImage(String path) { |
| Image image = m_imageMap.get(path); |
| if (image == null) { |
| try { |
| image = getImage(new FileInputStream(path)); |
| m_imageMap.put(path, image); |
| } catch (final Exception e) { |
| image = getMissingImage(); |
| m_imageMap.put(path, image); |
| } |
| } |
| return image; |
| } |
| |
| /** |
| * Returns an {@link Image} stored in the file at the specified path relative to the specified class. |
| * |
| * @param clazz |
| * the {@link Class} relative to which to find the image |
| * @param path |
| * the path to the image file, if starts with <code>'/'</code> |
| * @return the {@link Image} stored in the file at the specified path |
| */ |
| public static Image getImage(Class<?> clazz, String path) { |
| final String key = clazz.getName() + '|' + path; |
| Image image = m_imageMap.get(key); |
| if (image == null) { |
| try { |
| image = getImage(clazz.getResourceAsStream(path)); |
| m_imageMap.put(key, image); |
| } catch (final Exception e) { |
| image = getMissingImage(); |
| m_imageMap.put(key, image); |
| } |
| } |
| return image; |
| } |
| |
| private static final int MISSING_IMAGE_SIZE = 10; |
| |
| /** |
| * @return the small {@link Image} that can be used as placeholder for missing image. |
| */ |
| private static Image getMissingImage() { |
| final Image image = new Image(Display.getCurrent(), MISSING_IMAGE_SIZE, MISSING_IMAGE_SIZE); |
| // |
| final GC gc = new GC(image); |
| gc.setBackground(getColor(SWT.COLOR_RED)); |
| gc.fillRectangle(0, 0, MISSING_IMAGE_SIZE, MISSING_IMAGE_SIZE); |
| gc.dispose(); |
| // |
| return image; |
| } |
| |
| /** |
| * Style constant for placing decorator image in top left corner of base image. |
| */ |
| public static final int TOP_LEFT = 1; |
| |
| /** |
| * Style constant for placing decorator image in top right corner of base image. |
| */ |
| public static final int TOP_RIGHT = 2; |
| |
| /** |
| * Style constant for placing decorator image in bottom left corner of base image. |
| */ |
| public static final int BOTTOM_LEFT = 3; |
| |
| /** |
| * Style constant for placing decorator image in bottom right corner of base image. |
| */ |
| public static final int BOTTOM_RIGHT = 4; |
| |
| /** |
| * Internal value. |
| */ |
| protected static final int LAST_CORNER_KEY = 5; |
| |
| /** |
| * Maps images to decorated images. |
| */ |
| @SuppressWarnings("unchecked") |
| private static Map<Image, Map<Image, Image>>[] m_decoratedImageMap = new Map[LAST_CORNER_KEY]; |
| |
| /** |
| * Returns an {@link Image} composed of a base image decorated by another image. |
| * |
| * @param baseImage |
| * the base {@link Image} that should be decorated |
| * @param decorator |
| * the {@link Image} to decorate the base image |
| * @return {@link Image} The resulting decorated image |
| */ |
| public static Image decorateImage(Image baseImage, Image decorator) { |
| return decorateImage(baseImage, decorator, BOTTOM_RIGHT); |
| } |
| |
| /** |
| * Returns an {@link Image} composed of a base image decorated by another image. |
| * |
| * @param baseImage |
| * the base {@link Image} that should be decorated |
| * @param decorator |
| * the {@link Image} to decorate the base image |
| * @param corner |
| * the corner to place decorator image |
| * @return the resulting decorated {@link Image} |
| */ |
| public static Image decorateImage(final Image baseImage, final Image decorator, final int corner) { |
| if (corner <= 0 || corner >= LAST_CORNER_KEY) { |
| throw new IllegalArgumentException("Wrong decorate corner"); //$NON-NLS-1$ |
| } |
| Map<Image, Map<Image, Image>> cornerDecoratedImageMap = m_decoratedImageMap[corner]; |
| if (cornerDecoratedImageMap == null) { |
| cornerDecoratedImageMap = new HashMap<Image, Map<Image, Image>>(); |
| m_decoratedImageMap[corner] = cornerDecoratedImageMap; |
| } |
| Map<Image, Image> decoratedMap = cornerDecoratedImageMap.get(baseImage); |
| if (decoratedMap == null) { |
| decoratedMap = new HashMap<Image, Image>(); |
| cornerDecoratedImageMap.put(baseImage, decoratedMap); |
| } |
| // |
| Image result = decoratedMap.get(decorator); |
| if (result == null) { |
| final Rectangle bib = baseImage.getBounds(); |
| final Rectangle dib = decorator.getBounds(); |
| // |
| result = new Image(Display.getCurrent(), bib.width, bib.height); |
| // |
| final GC gc = new GC(result); |
| gc.drawImage(baseImage, 0, 0); |
| if (corner == TOP_LEFT) { |
| gc.drawImage(decorator, 0, 0); |
| } else if (corner == TOP_RIGHT) { |
| gc.drawImage(decorator, bib.width - dib.width, 0); |
| } else if (corner == BOTTOM_LEFT) { |
| gc.drawImage(decorator, 0, bib.height - dib.height); |
| } else if (corner == BOTTOM_RIGHT) { |
| gc.drawImage(decorator, bib.width - dib.width, bib.height - dib.height); |
| } |
| gc.dispose(); |
| // |
| decoratedMap.put(decorator, result); |
| } |
| return result; |
| } |
| |
| /** |
| * Dispose all of the cached {@link Image}'s. |
| */ |
| public static void disposeImages() { |
| // dispose loaded images |
| { |
| for (final Image image : m_imageMap.values()) { |
| image.dispose(); |
| } |
| m_imageMap.clear(); |
| } |
| // dispose decorated images |
| for (int i = 0; i < m_decoratedImageMap.length; i++) { |
| final Map<Image, Map<Image, Image>> cornerDecoratedImageMap = m_decoratedImageMap[i]; |
| if (cornerDecoratedImageMap != null) { |
| for (final Map<Image, Image> decoratedMap : cornerDecoratedImageMap.values()) { |
| for (final Image image : decoratedMap.values()) { |
| image.dispose(); |
| } |
| decoratedMap.clear(); |
| } |
| cornerDecoratedImageMap.clear(); |
| } |
| } |
| } |
| |
| // ////////////////////////////////////////////////////////////////////////// |
| // |
| // Font |
| // |
| // ////////////////////////////////////////////////////////////////////////// |
| /** |
| * Maps font names to fonts. |
| */ |
| private static Map<String, Font> m_fontMap = new HashMap<String, Font>(); |
| |
| /** |
| * Maps fonts to their bold versions. |
| */ |
| private static Map<Font, Font> m_fontToBoldFontMap = new HashMap<Font, Font>(); |
| |
| /** |
| * Returns a {@link Font} based on its name, height and style. |
| * |
| * @param name |
| * the name of the font |
| * @param height |
| * the height of the font |
| * @param style |
| * the style of the font |
| * @return {@link Font} The font matching the name, height and style |
| */ |
| public static Font getFont(String name, int height, int style) { |
| return getFont(name, height, style, false, false); |
| } |
| |
| /** |
| * Returns a {@link Font} based on its name, height and style. Windows-specific strikeout and underline flags are |
| * also |
| * supported. |
| * |
| * @param name |
| * the name of the font |
| * @param size |
| * the size of the font |
| * @param style |
| * the style of the font |
| * @param strikeout |
| * the strikeout flag (warning: Windows only) |
| * @param underline |
| * the underline flag (warning: Windows only) |
| * @return {@link Font} The font matching the name, height, style, strikeout and underline |
| */ |
| public static Font getFont(String name, int size, int style, boolean strikeout, boolean underline) { |
| final String fontName = name + '|' + size + '|' + style + '|' + strikeout + '|' + underline; |
| Font font = m_fontMap.get(fontName); |
| if (font == null) { |
| final FontData fontData = new FontData(name, size, style); |
| if (strikeout || underline) { |
| try { |
| final Class<?> logFontClass = Class.forName("org.eclipse.swt.internal.win32.LOGFONT"); //$NON-NLS-1$ |
| final Object logFont = FontData.class.getField("data").get(fontData); //$NON-NLS-1$ |
| if (logFont != null && logFontClass != null) { |
| if (strikeout) { |
| logFontClass.getField("lfStrikeOut").set(logFont, Byte.valueOf((byte) 1)); //$NON-NLS-1$ |
| } |
| if (underline) { |
| logFontClass.getField("lfUnderline").set(logFont, Byte.valueOf((byte) 1)); //$NON-NLS-1$ |
| } |
| } |
| } catch (final Throwable e) { |
| System.err |
| .println( |
| "Unable to set underline or strikeout" + " (probably on a non-Windows platform). " + e); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| } |
| font = new Font(Display.getCurrent(), fontData); |
| m_fontMap.put(fontName, font); |
| } |
| return font; |
| } |
| |
| /** |
| * Returns a bold version of the given {@link Font}. |
| * |
| * @param baseFont |
| * the {@link Font} for which a bold version is desired |
| * @return the bold version of the given {@link Font} |
| */ |
| public static Font getBoldFont(Font baseFont) { |
| Font font = m_fontToBoldFontMap.get(baseFont); |
| if (font == null) { |
| final FontData[] fontDatas = baseFont.getFontData(); |
| final FontData data = fontDatas[0]; |
| font = new Font(Display.getCurrent(), data.getName(), data.getHeight(), SWT.BOLD); |
| m_fontToBoldFontMap.put(baseFont, font); |
| } |
| return font; |
| } |
| |
| /** |
| * Dispose all of the cached {@link Font}'s. |
| */ |
| public static void disposeFonts() { |
| // clear fonts |
| for (final Font font : m_fontMap.values()) { |
| font.dispose(); |
| } |
| m_fontMap.clear(); |
| // clear bold fonts |
| for (final Font font : m_fontToBoldFontMap.values()) { |
| font.dispose(); |
| } |
| m_fontToBoldFontMap.clear(); |
| } |
| |
| // ////////////////////////////////////////////////////////////////////////// |
| // |
| // Cursor |
| // |
| // ////////////////////////////////////////////////////////////////////////// |
| /** |
| * Maps IDs to cursors. |
| */ |
| private static Map<Integer, Cursor> m_idToCursorMap = new HashMap<Integer, Cursor>(); |
| |
| /** |
| * Returns the system cursor matching the specific ID. |
| * |
| * @param id |
| * int The ID value for the cursor |
| * @return Cursor The system cursor matching the specific ID |
| */ |
| public static Cursor getCursor(int id) { |
| final Integer key = Integer.valueOf(id); |
| Cursor cursor = m_idToCursorMap.get(key); |
| if (cursor == null) { |
| cursor = new Cursor(Display.getDefault(), id); |
| m_idToCursorMap.put(key, cursor); |
| } |
| return cursor; |
| } |
| |
| /** |
| * Dispose all of the cached cursors. |
| */ |
| public static void disposeCursors() { |
| for (final Cursor cursor : m_idToCursorMap.values()) { |
| cursor.dispose(); |
| } |
| m_idToCursorMap.clear(); |
| } |
| |
| // ////////////////////////////////////////////////////////////////////////// |
| // |
| // General |
| // |
| // ////////////////////////////////////////////////////////////////////////// |
| /** |
| * Dispose of cached objects and their underlying OS resources. This should only be called when the cached objects |
| * are |
| * no longer needed (e.g. on application shutdown). |
| */ |
| public static void dispose() { |
| disposeColors(); |
| disposeImages(); |
| disposeFonts(); |
| disposeCursors(); |
| } |
| } |