/** * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved. * Licensed under the terms of the Eclipse Public License (EPL). * Please see the license.txt included with this distribution for details. * Any modifications to this file must keep this entire header intact. */ /* * Author: atotic * Created: Jul 29, 2003 */ package org.python.pydev.core.bundle; import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.eclipse.jface.resource.CompositeImageDescriptor; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Color; 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.Point; import org.eclipse.swt.widgets.Display; import org.python.pydev.core.FontUtils; import org.python.pydev.core.IFontUsage; import org.python.pydev.core.Tuple3; import org.python.pydev.core.Tuple4; import org.python.pydev.core.log.Log; /** * Caches images, releases all on dispose */ public class ImageCache { /** * Helper to decorate an image. * * The only method that should be used is: drawDecoration */ private static final class ImageDecorator extends CompositeImageDescriptor { private Point size; private ImageData base; private ImageData decoration; private int ox; private int oy; protected Point getSize() { return size; } protected void drawCompositeImage(int width, int height) { this.drawImage(base, 0, 0); this.drawImage(decoration, ox, oy); } public final ImageData drawDecoration(ImageData base, ImageData decoration, int ox, int oy) { this.size = new Point(base.width, base.height); this.base = base; this.decoration = decoration; this.ox = ox; this.oy = oy; return getImageData(); } } private final Map<Object, Image> imageHash = new HashMap<Object, Image>(10); private final Map<Object, ImageDescriptor> descriptorHash = new HashMap<Object, ImageDescriptor>(10); private final ImageDecorator imageDecorator = new ImageDecorator(); private final URL baseURL; private Image missing = null; private final Object lock = new Object(); private final Object descriptorLock = new Object(); public ImageCache(URL baseURL) { this.baseURL = baseURL; } protected ImageCache() { this(null); } public void dispose() { synchronized (lock) { Iterator e = imageHash.values().iterator(); while (e.hasNext()) ((Image) e.next()).dispose(); if (missing != null) { missing.dispose(); } } } /** * @param key - relative path to the plugin directory * @return the image */ public Image get(String key) { synchronized (lock) { Image image = (Image) imageHash.get(key); if (image == null) { ImageDescriptor desc; try { desc = getDescriptor(key); image = desc.createImage(); imageHash.put(key, image); } catch (NoClassDefFoundError e) { //we're in tests... return null; } catch (UnsatisfiedLinkError e) { //we're in tests... return null; } catch (Exception e) { // If image is missing, create a default missing one Log.log("ERROR: Missing image: " + key); if (missing == null) { desc = ImageDescriptor.getMissingImageDescriptor(); missing = desc.createImage(); } image = missing; } } return image; } } public Image getImageDecorated(String key, String decoration) { return getImageDecorated(key, decoration, DECORATION_LOCATION_TOP_RIGHT); } public final static int DECORATION_LOCATION_TOP_RIGHT = 0; public final static int DECORATION_LOCATION_BOTTOM_RIGHT = 1; public Image getImageDecorated(String key, String decoration, int decorationLocation) { return getImageDecorated(key, decoration, decorationLocation, null, -1); } /** * @param key the key of the image that should be decorated (relative path to the plugin directory) * @param decoration the key of the image that should be decorated (relative path to the plugin directory) */ @SuppressWarnings({ "rawtypes", "unchecked" }) public Image getImageDecorated(String key, String decoration, int decorationLocation, String secondDecoration, int secondDecorationLocation) { synchronized (lock) { Object cacheKey = new Tuple4(key, decoration, decorationLocation, "imageDecoration"); if (secondDecoration != null) { //Also add the second decoration to the cache key. cacheKey = new Tuple3(cacheKey, secondDecoration, secondDecorationLocation); } Image image = imageHash.get(cacheKey); if (image == null) { Display display = Display.getCurrent(); //Note that changing the image data gotten here won't affect the original image. ImageData baseImageData = get(key).getImageData(); image = decorateImage(decoration, decorationLocation, display, baseImageData); if (secondDecoration != null) { image = decorateImage(secondDecoration, secondDecorationLocation, display, image.getImageData()); } imageHash.put(cacheKey, image); } return image; } } private Image decorateImage(String decoration, int decorationLocation, Display display, ImageData baseImageData) throws AssertionError { Image image; ImageData decorationImageData = get(decoration).getImageData(); ImageData imageData; switch (decorationLocation) { case DECORATION_LOCATION_TOP_RIGHT: imageData = imageDecorator.drawDecoration(baseImageData, decorationImageData, baseImageData.width - decorationImageData.width, 0); break; case DECORATION_LOCATION_BOTTOM_RIGHT: imageData = imageDecorator.drawDecoration(baseImageData, decorationImageData, baseImageData.width - decorationImageData.width, baseImageData.height - decorationImageData.height); break; default: throw new AssertionError("Decoration location not recognized: " + decorationLocation); } image = new Image(display, imageData); return image; } /** * @param key the key of the image that should be decorated (relative path to the plugin directory) * @param stringToAddToDecoration the string that should be drawn over the image */ public Image getStringDecorated(String key, String stringToAddToDecoration) { synchronized (lock) { Tuple3<String, String, String> cacheKey = new Tuple3<String, String, String>(key, stringToAddToDecoration, "stringDecoration"); Image image = imageHash.get(cacheKey); if (image == null) { Display display = Display.getCurrent(); image = new Image(display, get(key), SWT.IMAGE_COPY); imageHash.put(cacheKey, image); //put it there (even though it'll still be changed). GC gc = new GC(image); // Color color = new Color(display, 0, 0, 0); // Color color2 = new Color(display, 255, 255, 255); // gc.setForeground(color2); // gc.setBackground(color2); // gc.setFillRule(SWT.FILL_WINDING); // gc.fillRoundRectangle(2, 1, base-1, base, 2, 2); // gc.setForeground(color); // gc.drawRoundRectangle(6, 0, base, base+1, 2, 2); // color2.dispose(); // color.dispose(); Color colorBackground = new Color(display, 255, 255, 255); Color colorForeground = new Color(display, 0, 83, 41); // get TextFont from preferences FontData fontData = FontUtils.getFontData(IFontUsage.IMAGECACHE, true); fontData.setStyle(SWT.BOLD); Font font = new Font(display, fontData); try { gc.setForeground(colorForeground); gc.setBackground(colorBackground); gc.setTextAntialias(SWT.ON); gc.setFont(font); gc.drawText(stringToAddToDecoration, 5, 0, true); } catch (Exception e) { Log.log(e); } finally { colorBackground.dispose(); colorForeground.dispose(); font.dispose(); gc.dispose(); } } return image; } } /** * like get, but returns ImageDescription instead of image */ public ImageDescriptor getDescriptor(String key) { synchronized (descriptorLock) { if (!descriptorHash.containsKey(key)) { URL url; ImageDescriptor desc; try { url = new URL(baseURL, key); desc = ImageDescriptor.createFromURL(url); } catch (MalformedURLException e) { Log.log("ERROR: Missing image: " + key); desc = ImageDescriptor.getMissingImageDescriptor(); } descriptorHash.put(key, desc); return desc; } return descriptorHash.get(key); } } }