Home | History | Annotate | Download | only in editors
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 
     18 package com.android.ide.eclipse.adt.internal.editors;
     19 
     20 import com.android.ide.eclipse.adt.AdtPlugin;
     21 import com.android.sdklib.SdkConstants;
     22 
     23 import org.eclipse.jface.resource.ImageDescriptor;
     24 import org.eclipse.swt.SWT;
     25 import org.eclipse.swt.graphics.Font;
     26 import org.eclipse.swt.graphics.FontData;
     27 import org.eclipse.swt.graphics.GC;
     28 import org.eclipse.swt.graphics.Image;
     29 import org.eclipse.swt.graphics.ImageData;
     30 import org.eclipse.swt.graphics.Point;
     31 import org.eclipse.swt.widgets.Display;
     32 
     33 import java.util.HashMap;
     34 
     35 /**
     36  * Factory to generate icons for Android Editors.
     37  * <p/>
     38  * Icons are kept here and reused.
     39  */
     40 public class IconFactory {
     41 
     42     public static final int COLOR_RED     = SWT.COLOR_DARK_RED;
     43     public static final int COLOR_GREEN   = SWT.COLOR_DARK_GREEN;
     44     public static final int COLOR_BLUE    = SWT.COLOR_DARK_BLUE;
     45     public static final int COLOR_DEFAULT = SWT.COLOR_BLACK;
     46 
     47     public static final int SHAPE_CIRCLE  = 'C';
     48     public static final int SHAPE_RECT    = 'R';
     49     public static final int SHAPE_DEFAULT = SHAPE_CIRCLE;
     50 
     51     private static IconFactory sInstance;
     52 
     53     private HashMap<String, Image> mIconMap = new HashMap<String, Image>();
     54     private HashMap<String, ImageDescriptor> mImageDescMap = new HashMap<String, ImageDescriptor>();
     55 
     56     private IconFactory() {
     57     }
     58 
     59     public static synchronized IconFactory getInstance() {
     60         if (sInstance == null) {
     61             sInstance = new IconFactory();
     62         }
     63         return sInstance;
     64     }
     65 
     66     public void Dispose() {
     67         // Dispose icons
     68         for (Image icon : mIconMap.values()) {
     69             // The map can contain null values
     70             if (icon != null) {
     71                 icon.dispose();
     72             }
     73         }
     74         mIconMap.clear();
     75     }
     76 
     77     /**
     78      * Returns an Image for a given icon name.
     79      * <p/>
     80      * Callers should not dispose it.
     81      *
     82      * @param osName The leaf name, without the extension, of an existing icon in the
     83      *        editor's "icons" directory. If it doesn't exists, a default icon will be
     84      *        generated automatically based on the name.
     85      */
     86     public Image getIcon(String osName) {
     87         return getIcon(osName, COLOR_DEFAULT, SHAPE_DEFAULT);
     88     }
     89 
     90     /**
     91      * Returns an Image for a given icon name.
     92      * <p/>
     93      * Callers should not dispose it.
     94      *
     95      * @param osName The leaf name, without the extension, of an existing icon in the
     96      *        editor's "icons" directory. If it doesn't exists, a default icon will be
     97      *        generated automatically based on the name.
     98      * @param color The color of the text in the automatically generated icons,
     99      *        one of COLOR_DEFAULT, COLOR_RED, COLOR_BLUE or COLOR_RED.
    100      * @param shape The shape of the icon in the automatically generated icons,
    101      *        one of SHAPE_DEFAULT, SHAPE_CIRCLE or SHAPE_RECT.
    102      */
    103     public Image getIcon(String osName, int color, int shape) {
    104         String key = Character.toString((char) shape) + Integer.toString(color) + osName;
    105         Image icon = mIconMap.get(key);
    106         if (icon == null && !mIconMap.containsKey(key)) {
    107             ImageDescriptor id = getImageDescriptor(osName, color, shape);
    108             if (id != null) {
    109                 icon = id.createImage();
    110             }
    111             // Note that we store null references in the icon map, to avoid looking them
    112             // up every time. If it didn't exist once, it will not exist later.
    113             mIconMap.put(key, icon);
    114         }
    115         return icon;
    116     }
    117 
    118     /**
    119      * Returns an ImageDescriptor for a given icon name.
    120      * <p/>
    121      * Callers should not dispose it.
    122      *
    123      * @param osName The leaf name, without the extension, of an existing icon in the
    124      *        editor's "icons" directory. If it doesn't exists, a default icon will be
    125      *        generated automatically based on the name.
    126      */
    127     public ImageDescriptor getImageDescriptor(String osName) {
    128         return getImageDescriptor(osName, COLOR_DEFAULT, SHAPE_DEFAULT);
    129     }
    130 
    131     /**
    132      * Returns an ImageDescriptor for a given icon name.
    133      * <p/>
    134      * Callers should not dispose it.
    135      *
    136      * @param osName The leaf name, without the extension, of an existing icon in the
    137      *        editor's "icons" directory. If it doesn't exists, a default icon will be
    138      *        generated automatically based on the name.
    139      * @param color The color of the text in the automatically generated icons.
    140      *        one of COLOR_DEFAULT, COLOR_RED, COLOR_BLUE or COLOR_RED.
    141      * @param shape The shape of the icon in the automatically generated icons,
    142      *        one of SHAPE_DEFAULT, SHAPE_CIRCLE or SHAPE_RECT.
    143      */
    144     public ImageDescriptor getImageDescriptor(String osName, int color, int shape) {
    145         String key = Character.toString((char) shape) + Integer.toString(color) + osName;
    146         ImageDescriptor id = mImageDescMap.get(key);
    147         if (id == null && !mImageDescMap.containsKey(key)) {
    148             id = AdtPlugin.imageDescriptorFromPlugin(
    149                     AdtPlugin.PLUGIN_ID,
    150                     String.format("/icons/%1$s.png", osName)); //$NON-NLS-1$
    151 
    152             if (id == null) {
    153                 id = new LetterImageDescriptor(osName.charAt(0), color, shape);
    154             }
    155 
    156             // Note that we store null references in the icon map, to avoid looking them
    157             // up every time. If it didn't exist once, it will not exist later.
    158             mImageDescMap.put(key, id);
    159         }
    160         return id;
    161     }
    162 
    163     /**
    164      * A simple image description that generates a 16x16 image which consists
    165      * of a colored letter inside a black & white circle.
    166      */
    167     private static class LetterImageDescriptor extends ImageDescriptor {
    168 
    169         private final char mLetter;
    170         private final int mColor;
    171         private final int mShape;
    172 
    173         public LetterImageDescriptor(char letter, int color, int shape) {
    174             mLetter = letter;
    175             mColor = color;
    176             mShape = shape;
    177         }
    178 
    179         @Override
    180         public ImageData getImageData() {
    181 
    182             final int SX = 15;
    183             final int SY = 15;
    184             final int RX = 4;
    185             final int RY = 4;
    186 
    187             Display display = Display.getCurrent();
    188             if (display == null) {
    189                 return null;
    190             }
    191 
    192             Image image = new Image(display, SX, SY);
    193 
    194             image.setBackground(display.getSystemColor(SWT.COLOR_WHITE));
    195 
    196             GC gc = new GC(image);
    197             gc.setAdvanced(true);
    198             gc.setAntialias(SWT.ON);
    199             gc.setTextAntialias(SWT.ON);
    200 
    201             gc.setBackground(display.getSystemColor(SWT.COLOR_WHITE));
    202             if (mShape == SHAPE_CIRCLE) {
    203                 gc.fillOval(0, 0, SX - 1, SY - 1);
    204             } else if (mShape == SHAPE_RECT) {
    205                 gc.fillRoundRectangle(0, 0, SX - 1, SY - 1, RX, RY);
    206             }
    207 
    208             gc.setForeground(display.getSystemColor(SWT.COLOR_BLACK));
    209             gc.setLineWidth(1);
    210             if (mShape == SHAPE_CIRCLE) {
    211                 gc.drawOval(0, 0, SX - 1, SY - 1);
    212             } else if (mShape == SHAPE_RECT) {
    213                 gc.drawRoundRectangle(0, 0, SX - 1, SY - 1, RX, RY);
    214             }
    215 
    216             // Get a bold version of the default system font, if possible.
    217             Font font = display.getSystemFont();
    218             FontData[] fds = font.getFontData();
    219             fds[0].setStyle(SWT.BOLD);
    220             // use 3/4th of the circle diameter for the font size (in pixels)
    221             // and convert it to "font points" (font points in SWT are hardcoded in an
    222             // arbitrary 72 dpi and then converted in real pixels using whatever is
    223             // indicated by getDPI -- at least that's how it works under Win32).
    224             fds[0].setHeight((int) ((SY + 1) * 3./4. * 72./display.getDPI().y));
    225             // Note: win32 implementation always uses fds[0] so we change just that one.
    226             // getFontData indicates that the array of fd is really an unusual thing for X11.
    227             font = new Font(display, fds);
    228             gc.setFont(font);
    229             gc.setForeground(display.getSystemColor(mColor));
    230 
    231             // Text measurement varies so slightly depending on the platform
    232             int ofx = 0;
    233             int ofy = 0;
    234             if (SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_WINDOWS) {
    235                 ofx = +1;
    236                 ofy = -1;
    237             }
    238 
    239             String s = Character.toString(mLetter).toUpperCase();
    240             Point p = gc.textExtent(s);
    241             int tx = (SX + ofx - p.x) / 2;
    242             int ty = (SY + ofy - p.y) / 2;
    243             gc.drawText(s, tx, ty, true /* isTransparent */);
    244 
    245             font.dispose();
    246             gc.dispose();
    247 
    248             ImageData data = image.getImageData();
    249             image.dispose();
    250             return data;
    251         }
    252 
    253     }
    254 
    255 }
    256