Java tutorial
package org.mailster.gui; import java.io.BufferedInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; 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.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.graphics.Resource; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.ToolBar; import org.eclipse.swt.widgets.ToolItem; import org.eclipse.swt.widgets.Tree; import org.eclipse.swt.widgets.TreeItem; import org.mailster.MailsterSWT; import org.mailster.util.MailUtilities; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * ---<br> * Mailster (C) 2007-2009 De Oliveira Edouard * <p> * This program is free software; you can redistribute it and/or modify it under the terms of the * GNU General Public License as published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * <p> * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * <p> * You should have received a copy of the GNU General Public License along with this program; if * not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * <p> * See <a href="http://tedorg.free.fr/en/projects.php" target="_parent">Mailster Web Site</a> * <br> * --- * <p> * SWTHelper.java - A helper class that handles all the OS associated resources. Resources are * cached and the helper provides a <code>disposeAll()</code> method that allows to free all system * resources acquired till there. The class also register a JVM shutdown hook to ensure it won't be * forgotten. * * @author <a href="mailto:doe_wanted@yahoo.fr">Edouard De Oliveira</a> * @version $Revision: 1.11 $, $Date: 2009/02/07 19:45:52 $ */ public class SWTHelper { private static final Logger LOG = LoggerFactory.getLogger(SWTHelper.class); static { // Automatic disposal of OS resources Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { public void run() { LOG.debug("Disposing system resources ..."); disposeAll(); } })); } /** * The directory in which images and icons are stored. */ public final static String DESC_IMAGES_DIRECTORY = "org/mailster/gui/resources/images/"; //$NON-NLS-1$ public final static String IMAGES_DIRECTORY = "/" + DESC_IMAGES_DIRECTORY; //$NON-NLS-1$ /** * The suffix added to the key name of the gray version of a image. */ public final static String GRAY_IMAGE_SUFFIX = "_SWT_GRAY_IMAGE"; /** * The temporary directory path. */ private final static String tempDir = MailUtilities.tempDirectory.replace(File.separatorChar, '/') + "/"; /** * The resource tracker. */ private static Map<String, Resource> resourceTracker = new HashMap<String, Resource>(20); /** * The system font. * * Note: This font should not be freed because it's allocated by the system itself. */ public final static Font SYSTEM_FONT = Display.getDefault().getSystemFont(); /** * The system font in bold style. */ public final static Font SYSTEM_FONT_BOLD = makeBoldFont(SYSTEM_FONT); /** * Images decorator map. */ private static Map<Image, HashMap<Image, Image>> imageToDecoratorMap = new HashMap<Image, HashMap<Image, Image>>(); /** * Turns the specified <code>Font</code> bold. * * @param sourceFont * the source <code>Font</code> object * @return Font the <code>Font</code> in Bold */ public static Font makeBoldFont(Font sourceFont) { FontData[] fontData = sourceFont.getFontData(); for (int i = 0; i < fontData.length; i++) fontData[i].setStyle(SWT.BOLD); Font f = new Font(getDisplay(), fontData); resourceTracker.put(f.toString(), f); return createFont(fontData); } /** * Creates a font that is registered in the resource tracker. * * @param data * the <code>FontData</code> to create the font * @return Font the new font */ public static Font createFont(FontData data) { Font f = new Font(getDisplay(), data); resourceTracker.put(f.toString(), f); return f; } /** * Creates a font that is registered in the resource tracker. * * @param data * the <code>FontData</code> to create the font * @return Font the new font */ public static Font createFont(FontData[] data) { Font f = new Font(getDisplay(), data); resourceTracker.put(f.toString(), f); return f; } /** * Returns an <code>ImageDescriptor</code> from the application's image directory but DOES NOT * register it with the resource tracker. * * @param fileName * the image file name * @return the image object */ public static ImageDescriptor getImageDescriptor(String fileName) { URL url = Thread.currentThread().getContextClassLoader().getResource(DESC_IMAGES_DIRECTORY + fileName); if (url == null) return ImageDescriptor.getMissingImageDescriptor(); else return (ImageDescriptor.createFromURL(url)); } /** * Loads an image from the application's image directory and register it with a resource tracker * for later disposal by the <code>disposeAll()</code> function. * * @param fileName * the image file name * @return the image object */ public static Image loadImage(String fileName) { return loadImage(fileName, true); } /** * Loads an image from the application's image directory and register it with a resource tracker * for later disposal by the <code>disposeAll()</code> function. * * @param fileName * the image file name * @return the image as an {@link InputStream} */ public static InputStream getResourceAsStream(String fileName) { return MailsterSWT.class.getResourceAsStream(IMAGES_DIRECTORY + fileName); } /** * Loads an image from the application's image directory and register it with a resource tracker * for later disposal by the <code>disposeAll()</code> function if the <code>register</code> * parameter is set to <code>true</code>. * * @param fileName * the image file name * @param register * if true image is registered in the resource tracker * @return the image object */ protected static Image loadImage(String fileName, boolean register) { Object o = resourceTracker.get(fileName); if (o == null) { Image i = new Image(getDisplay(), MailsterSWT.class.getResourceAsStream(IMAGES_DIRECTORY + fileName)); resourceTracker.put(fileName, i); return i; } if (o == null || !(o instanceof Image)) { LOG.info("Image {} did not load", fileName); return null; } else return (Image) o; } /** * Loads an image from the application's image directory, then computes the corresponding gray * image and finally register the grayed image with a resource tracker for later disposal by the * <code>disposeAll()</code> function. * * @param fileName * the image file name * @return the image object */ public static Image loadGrayImage(String fileName) { String key = fileName + GRAY_IMAGE_SUFFIX; Object o = resourceTracker.get(key); if (o == null) { Image i = loadImage(fileName); if (i != null) { Image gray = new Image(getDisplay(), i, SWT.IMAGE_GRAY); resourceTracker.put(fileName + GRAY_IMAGE_SUFFIX, gray); return gray; } } if (o == null || !(o instanceof Image)) return null; else return (Image) o; } /** * Dispose all registered OS resources. */ public static void disposeAll() { if (imageToDecoratorMap != null) { Iterator<HashMap<Image, Image>> baseImages = imageToDecoratorMap.values().iterator(); while (baseImages.hasNext()) { Iterator<Image> decorators = baseImages.next().values().iterator(); while (decorators.hasNext()) decorators.next().dispose(); } } Iterator<Resource> it = resourceTracker.values().iterator(); while (it.hasNext()) it.next().dispose(); } /** * Helper function to create a tool item. The behaviour of the toolitem is set to use a grayed * image when not hovered and to use the normal image when mouse is over the toolitem. Image * objects are registered in the resource tracker. * * @return ToolItem */ public static ToolItem createToolItem(ToolBar parent, int type, String text, String toolTipText, String imageName, boolean createHotImage) { ToolItem item = new ToolItem(parent, type); item.setText(text); Image image = loadImage(imageName); item.setToolTipText(toolTipText); if (createHotImage) { item.setImage(loadGrayImage(imageName)); item.setHotImage(image); } else item.setImage(image); return item; } /** * Computes the gradient between two colors. Color objects are registered in the resource * tracker. * * @param steps * the number of steps for the color transition in the gradient * @param start * the color at the start of the gradient * @param end * the color at the end of the gradient * @return an array of the colors for the gradient */ public static Color[] getGradientColors(int steps, Color start, Color end) { Color[] colors = new Color[steps]; int rStep = Math.abs(start.getRed() - end.getRed()) / steps; int gStep = Math.abs(start.getGreen() - end.getGreen()) / steps; int bStep = Math.abs(start.getBlue() - end.getBlue()) / steps; colors[0] = start; colors[steps - 1] = end; Display display = getDisplay(); resourceTracker.put(start.getRGB().toString(), start); resourceTracker.put(end.getRGB().toString(), end); for (int i = 1, max = steps - 1; i < max; i++) { colors[i] = new Color(display, end.getRed() >= start.getRed() ? colors[i - 1].getRed() + rStep : colors[i - 1].getRed() - rStep, end.getGreen() >= start.getGreen() ? colors[i - 1].getGreen() + gStep : colors[i - 1].getGreen() - gStep, end.getBlue() >= start.getBlue() ? colors[i - 1].getBlue() + bStep : colors[i - 1].getBlue() - bStep); resourceTracker.put(colors[i].getRGB().toString(), colors[i]); } return colors; } /** * Creates a Color object and register in the resource tracker for later disposal. * * @param r * the red composant of the color * @param g * the green composant of the color * @param b * the blue composant of the color * @return the generated color object */ public static Color createColor(int r, int g, int b) { Color c = new Color(getDisplay(), r, g, b); String key = c.getRGB().toString(); Object obj = resourceTracker.get(key); if (obj != null) { c.dispose(); return (Color) obj; } resourceTracker.put(key, c); return c; } public static Color getColor(int id) { return getDisplay().getSystemColor(id); } /** * Returns the file URL of the image on the local temporary directory. If image isn't already * created it creates it before. * * @param fileName * the image file name * @return the url if file exists or "file:///" if file couldn't be written to temporary * directory */ public static String getImageURL(String fileName) { // Generate files in temporary directory if needed boolean exists = (new File(tempDir + fileName)).exists(); if (!exists) exists = writeImageToTempDirectory(fileName); if (!exists) return "file:///"; else return "file:///" + tempDir + fileName; } /** * Writes the resource image to the temporary directory. * * @param fileName * the image file name * @return true if write succeeded */ private static boolean writeImageToTempDirectory(String fileName) { try { BufferedInputStream bin = new BufferedInputStream( SWTHelper.class.getResourceAsStream(IMAGES_DIRECTORY + fileName)); MailUtilities.outputStreamToFile(tempDir, fileName, bin); bin.close(); } catch (IOException e) { e.printStackTrace(); return false; } return true; } /** * Try to return the current display. If no display is tied to current thread then it returns * the default Display a.k.a the first created as described in Display.getDefault(). * * @return the current or default display */ public static Display getDisplay() { Display display = Display.getCurrent(); // may be null if outside the UI thread if (display == null) display = Display.getDefault(); return display; } /** * Returns an image composed of a base image decorated by another image. * * @param baseImage * The filename of the base image that should be decorated * @param decorator * The filename of the image used to decorate the base image * @param corner * The corner to place decorator image * @return Image The resulting decorated image */ public static Image decorateImage(String baseImage, String decorator, final int corner) { return decorateImage(loadImage(baseImage, true), loadImage(decorator, false), corner); } /** * Returns an image composed of a base image decorated by another image. * * @param baseImage * Image The base image that should be decorated * @param decorator * Image The image used to decorate the base image * @param corner * The corner to place decorator image * @return Image The resulting decorated image */ public static Image decorateImage(final Image baseImage, final Image decorator, final int corner) { HashMap<Image, Image> decoratedMap = imageToDecoratorMap.get(baseImage); if (decoratedMap == null) { decoratedMap = new HashMap<Image, Image>(); imageToDecoratorMap.put(baseImage, decoratedMap); } Image result = (Image) decoratedMap.get(decorator); if (result == null) { final Rectangle bid = baseImage.getBounds(); final Rectangle did = decorator.getBounds(); final Point baseImageSize = new Point(bid.width, bid.height); CompositeImageDescriptor compositImageDesc = new CompositeImageDescriptor() { protected void drawCompositeImage(int width, int height) { drawImage(baseImage.getImageData(), 0, 0); if (corner == (SWT.TOP | SWT.LEFT)) drawImage(decorator.getImageData(), 0, 0); else if (corner == (SWT.TOP | SWT.RIGHT)) drawImage(decorator.getImageData(), bid.width - did.width - 1, 0); else if (corner == (SWT.BOTTOM | SWT.LEFT)) drawImage(decorator.getImageData(), 0, bid.height - did.height - 1); else if (corner == (SWT.BOTTOM | SWT.RIGHT)) drawImage(decorator.getImageData(), bid.width - did.width - 1, bid.height - did.height - 1); } protected Point getSize() { return baseImageSize; } }; result = compositImageDesc.createImage(); decoratedMap.put(decorator, result); } return result; } public static void expandAll(Tree tree) { TreeItem root = tree.getItem(0); if (root == null) return; root.setExpanded(true); setNodesExpandedState(root, true); } public static void collapseAll(Tree tree) { TreeItem root = tree.getItem(0); if (root == null) return; root.setExpanded(false); setNodesExpandedState(root, false); } private static void setNodesExpandedState(TreeItem current, boolean expand) { if (current == null || current.getItemCount() == 0) return; for (TreeItem item : current.getItems()) { item.setExpanded(expand); setNodesExpandedState(item, expand); } } }