Home | History | Annotate | Download | only in templates
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
      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 package com.android.ide.eclipse.adt.internal.wizards.templates;
     17 
     18 import static com.android.ide.eclipse.adt.internal.wizards.templates.NewProjectWizard.ATTR_MIN_API;
     19 import static com.android.ide.eclipse.adt.internal.wizards.templates.NewProjectWizard.ATTR_MIN_BUILD_API;
     20 import static com.android.ide.eclipse.adt.internal.wizards.templates.NewProjectWizard.ATTR_REVISION;
     21 import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_BACKGROUND;
     22 import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_CLIPART_NAME;
     23 import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_DESCRIPTION;
     24 import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_FOREGROUND;
     25 import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_FORMAT;
     26 import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_NAME;
     27 import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_PADDING;
     28 import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_SHAPE;
     29 import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_SOURCE_TYPE;
     30 import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_TEXT;
     31 import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_TRIM;
     32 import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_TYPE;
     33 import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_VALUE;
     34 import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.CURRENT_FORMAT;
     35 import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.TAG_DEPENDENCY;
     36 import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.TAG_ICONS;
     37 import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.TAG_PARAMETER;
     38 import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.TAG_THUMB;
     39 import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.TAG_FORMFACTOR;
     40 import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.TAG_CATEGORY;
     41 
     42 import com.android.annotations.NonNull;
     43 import com.android.annotations.Nullable;
     44 import com.android.assetstudiolib.GraphicGenerator;
     45 import com.android.ide.eclipse.adt.AdtPlugin;
     46 import com.android.ide.eclipse.adt.internal.assetstudio.AssetType;
     47 import com.android.ide.eclipse.adt.internal.assetstudio.CreateAssetSetWizardState;
     48 import com.android.ide.eclipse.adt.internal.assetstudio.CreateAssetSetWizardState.SourceType;
     49 import com.android.ide.eclipse.adt.internal.editors.IconFactory;
     50 import com.android.ide.eclipse.adt.internal.editors.layout.gle2.ImageUtils;
     51 import com.android.utils.Pair;
     52 import com.google.common.collect.Lists;
     53 
     54 import org.eclipse.core.resources.IProject;
     55 import org.eclipse.swt.graphics.Image;
     56 import org.eclipse.swt.graphics.RGB;
     57 import org.w3c.dom.Attr;
     58 import org.w3c.dom.Document;
     59 import org.w3c.dom.Element;
     60 import org.w3c.dom.NamedNodeMap;
     61 import org.w3c.dom.Node;
     62 import org.w3c.dom.NodeList;
     63 
     64 import java.util.ArrayList;
     65 import java.util.Collections;
     66 import java.util.HashMap;
     67 import java.util.List;
     68 import java.util.Locale;
     69 import java.util.Map;
     70 
     71 /** An ADT template along with metadata */
     72 class TemplateMetadata {
     73     private final Document mDocument;
     74     private final List<Parameter> mParameters;
     75     private final Map<String, Parameter> mParameterMap;
     76     private List<Pair<String, Integer>> mDependencies;
     77     private Integer mMinApi;
     78     private Integer mMinBuildApi;
     79     private Integer mRevision;
     80     private boolean mNoIcons;
     81     private CreateAssetSetWizardState mIconState;
     82 	private String mFormFactor;
     83 	private String mCategory;
     84 
     85     TemplateMetadata(@NonNull Document document) {
     86         mDocument = document;
     87 
     88         NodeList parameters = mDocument.getElementsByTagName(TAG_PARAMETER);
     89         mParameters = new ArrayList<Parameter>(parameters.getLength());
     90         mParameterMap = new HashMap<String, Parameter>(parameters.getLength());
     91         for (int index = 0, max = parameters.getLength(); index < max; index++) {
     92             Element element = (Element) parameters.item(index);
     93             Parameter parameter = new Parameter(this, element);
     94             mParameters.add(parameter);
     95             if (parameter.id != null) {
     96                 mParameterMap.put(parameter.id, parameter);
     97             }
     98         }
     99     }
    100 
    101     boolean isSupported() {
    102         String versionString = mDocument.getDocumentElement().getAttribute(ATTR_FORMAT);
    103         if (versionString != null && !versionString.isEmpty()) {
    104             try {
    105                 int version = Integer.parseInt(versionString);
    106                 return version <= CURRENT_FORMAT;
    107             } catch (NumberFormatException nufe) {
    108                 return false;
    109             }
    110         }
    111 
    112         // Older templates without version specified: supported
    113         return true;
    114     }
    115 
    116     @Nullable
    117     String getTitle() {
    118         String name = mDocument.getDocumentElement().getAttribute(ATTR_NAME);
    119         if (name != null && !name.isEmpty()) {
    120             return name;
    121         }
    122 
    123         return null;
    124     }
    125 
    126     @Nullable
    127     String getDescription() {
    128         String description = mDocument.getDocumentElement().getAttribute(ATTR_DESCRIPTION);
    129         if (description != null && !description.isEmpty()) {
    130             return description;
    131         }
    132 
    133         return null;
    134     }
    135 
    136     int getMinSdk() {
    137         if (mMinApi == null) {
    138             mMinApi = 1;
    139             String api = mDocument.getDocumentElement().getAttribute(ATTR_MIN_API);
    140             if (api != null && !api.isEmpty()) {
    141                 try {
    142                     mMinApi = Integer.parseInt(api);
    143                 } catch (NumberFormatException nufe) {
    144                     // Templates aren't allowed to contain codenames, should always be an integer
    145                     AdtPlugin.log(nufe, null);
    146                     mMinApi = 1;
    147                 }
    148             }
    149         }
    150 
    151         return mMinApi.intValue();
    152     }
    153 
    154     int getMinBuildApi() {
    155         if (mMinBuildApi == null) {
    156             mMinBuildApi = 1;
    157             String api = mDocument.getDocumentElement().getAttribute(ATTR_MIN_BUILD_API);
    158             if (api != null && !api.isEmpty()) {
    159                 try {
    160                     mMinBuildApi = Integer.parseInt(api);
    161                 } catch (NumberFormatException nufe) {
    162                     // Templates aren't allowed to contain codenames, should always be an integer
    163                     AdtPlugin.log(nufe, null);
    164                     mMinBuildApi = 1;
    165                 }
    166             }
    167         }
    168 
    169         return mMinBuildApi.intValue();
    170     }
    171 
    172     public int getRevision() {
    173         if (mRevision == null) {
    174             mRevision = 1;
    175             String revision = mDocument.getDocumentElement().getAttribute(ATTR_REVISION);
    176             if (revision != null && !revision.isEmpty()) {
    177                 try {
    178                     mRevision = Integer.parseInt(revision);
    179                 } catch (NumberFormatException nufe) {
    180                     AdtPlugin.log(nufe, null);
    181                     mRevision = 1;
    182                 }
    183             }
    184         }
    185 
    186         return mRevision.intValue();
    187     }
    188 
    189     public String getFormFactor() {
    190         if (mFormFactor == null) {
    191             mFormFactor = "Mobile";
    192 
    193             NodeList formfactorDeclarations = mDocument.getElementsByTagName(TAG_FORMFACTOR);
    194             if (formfactorDeclarations.getLength() > 0) {
    195             	Element element = (Element) formfactorDeclarations.item(0);
    196                 String formFactor = element.getAttribute(ATTR_VALUE);
    197                 if (formFactor != null && !formFactor.isEmpty()) {
    198                 	mFormFactor = formFactor;
    199                 }
    200             }
    201         }
    202         return mFormFactor;
    203     }
    204 
    205     public String getCategory() {
    206         if (mCategory == null) {
    207         	mCategory = "";
    208         	NodeList categories = mDocument.getElementsByTagName(TAG_CATEGORY);
    209             if (categories.getLength() > 0) {
    210             	Element element = (Element) categories.item(0);
    211             	String category = element.getAttribute(ATTR_VALUE);
    212                 if (category != null && !category.isEmpty()) {
    213                 	mCategory = category;
    214                 }
    215             }
    216         }
    217         return mCategory;
    218     }
    219 
    220     /**
    221      * Returns a suitable icon wizard state instance if this wizard requests
    222      * icons to be created, and null otherwise
    223      *
    224      * @return icon wizard state or null
    225      */
    226     @Nullable
    227     public CreateAssetSetWizardState getIconState(IProject project) {
    228         if (mIconState == null && !mNoIcons) {
    229             NodeList icons = mDocument.getElementsByTagName(TAG_ICONS);
    230             if (icons.getLength() < 1) {
    231                 mNoIcons = true;
    232                 return null;
    233             }
    234             Element icon = (Element) icons.item(0);
    235 
    236             mIconState = new CreateAssetSetWizardState();
    237             mIconState.project = project;
    238 
    239             String typeString = getAttributeOrNull(icon, ATTR_TYPE);
    240             if (typeString != null) {
    241                 typeString = typeString.toUpperCase(Locale.US);
    242                 boolean found = false;
    243                 for (AssetType type : AssetType.values()) {
    244                     if (typeString.equals(type.name())) {
    245                         mIconState.type = type;
    246                         found = true;
    247                         break;
    248                     }
    249                 }
    250                 if (!found) {
    251                     AdtPlugin.log(null, "Unknown asset type %1$s", typeString);
    252                 }
    253             }
    254 
    255             mIconState.outputName = getAttributeOrNull(icon, ATTR_NAME);
    256             if (mIconState.outputName != null) {
    257                 // Register parameter such that if it is referencing other values, it gets
    258                 // updated when other values are edited
    259                 Parameter outputParameter = new Parameter(this,
    260                         Parameter.Type.STRING, "_iconname", mIconState.outputName); //$NON-NLS-1$
    261                 getParameters().add(outputParameter);
    262             }
    263 
    264             RGB background = getRgb(icon, ATTR_BACKGROUND);
    265             if (background != null) {
    266                 mIconState.background = background;
    267             }
    268             RGB foreground = getRgb(icon, ATTR_FOREGROUND);
    269             if (foreground != null) {
    270                 mIconState.foreground = foreground;
    271             }
    272             String shapeString = getAttributeOrNull(icon, ATTR_SHAPE);
    273             if (shapeString != null) {
    274                 shapeString = shapeString.toUpperCase(Locale.US);
    275                 boolean found = false;
    276                 for (GraphicGenerator.Shape shape : GraphicGenerator.Shape.values()) {
    277                     if (shapeString.equals(shape.name())) {
    278                         mIconState.shape = shape;
    279                         found = true;
    280                         break;
    281                     }
    282                 }
    283                 if (!found) {
    284                     AdtPlugin.log(null, "Unknown shape %1$s", shapeString);
    285                 }
    286             }
    287             String trimString = getAttributeOrNull(icon, ATTR_TRIM);
    288             if (trimString != null) {
    289                 mIconState.trim = Boolean.valueOf(trimString);
    290             }
    291             String paddingString = getAttributeOrNull(icon, ATTR_PADDING);
    292             if (paddingString != null) {
    293                 mIconState.padding = Integer.parseInt(paddingString);
    294             }
    295             String sourceTypeString = getAttributeOrNull(icon, ATTR_SOURCE_TYPE);
    296             if (sourceTypeString != null) {
    297                 sourceTypeString = sourceTypeString.toUpperCase(Locale.US);
    298                 boolean found = false;
    299                 for (SourceType type : SourceType.values()) {
    300                     if (sourceTypeString.equals(type.name())) {
    301                         mIconState.sourceType = type;
    302                         found = true;
    303                         break;
    304                     }
    305                 }
    306                 if (!found) {
    307                     AdtPlugin.log(null, "Unknown source type %1$s", sourceTypeString);
    308                 }
    309             }
    310             mIconState.clipartName = getAttributeOrNull(icon, ATTR_CLIPART_NAME);
    311 
    312             String textString = getAttributeOrNull(icon, ATTR_TEXT);
    313             if (textString != null) {
    314                 mIconState.text = textString;
    315             }
    316         }
    317 
    318         return mIconState;
    319     }
    320 
    321     void updateIconName(List<Parameter> parameters, StringEvaluator evaluator) {
    322         if (mIconState != null) {
    323             NodeList icons = mDocument.getElementsByTagName(TAG_ICONS);
    324             if (icons.getLength() < 1) {
    325                 return;
    326             }
    327             Element icon = (Element) icons.item(0);
    328             String name = getAttributeOrNull(icon, ATTR_NAME);
    329             if (name != null) {
    330                 mIconState.outputName = evaluator.evaluate(name, parameters);
    331             }
    332         }
    333     }
    334 
    335     private static RGB getRgb(@NonNull Element element, @NonNull String name) {
    336         String colorString = getAttributeOrNull(element, name);
    337         if (colorString != null) {
    338             int rgb = ImageUtils.getColor(colorString.trim());
    339             return ImageUtils.intToRgb(rgb);
    340         }
    341 
    342         return null;
    343     }
    344 
    345     @Nullable
    346     private static String getAttributeOrNull(@NonNull Element element, @NonNull String name) {
    347         String value = element.getAttribute(name);
    348         if (value != null && value.isEmpty()) {
    349             return null;
    350         }
    351         return value;
    352     }
    353 
    354     @Nullable
    355     String getThumbnailPath() {
    356         // Apply selector logic. Pick the thumb first thumb that satisfies the largest number
    357         // of conditions.
    358         NodeList thumbs = mDocument.getElementsByTagName(TAG_THUMB);
    359         if (thumbs.getLength() == 0) {
    360             return null;
    361         }
    362 
    363 
    364         int bestMatchCount = 0;
    365         Element bestMatch = null;
    366 
    367         for (int i = 0, n = thumbs.getLength(); i < n; i++) {
    368             Element thumb = (Element) thumbs.item(i);
    369 
    370             NamedNodeMap attributes = thumb.getAttributes();
    371             if (bestMatch == null && attributes.getLength() == 0) {
    372                 bestMatch = thumb;
    373             } else if (attributes.getLength() <= bestMatchCount) {
    374                 // Already have a match with this number of attributes, no point checking
    375                 continue;
    376             } else {
    377                 boolean match = true;
    378                 for (int j = 0, max = attributes.getLength(); j < max; j++) {
    379                     Attr attribute = (Attr) attributes.item(j);
    380                     Parameter parameter = mParameterMap.get(attribute.getName());
    381                     if (parameter == null) {
    382                         AdtPlugin.log(null, "Unexpected parameter in template thumbnail: %1$s",
    383                                 attribute.getName());
    384                         continue;
    385                     }
    386                     String thumbNailValue = attribute.getValue();
    387                     String editedValue = parameter.value != null ? parameter.value.toString() : "";
    388                     if (!thumbNailValue.equals(editedValue)) {
    389                         match = false;
    390                         break;
    391                     }
    392                 }
    393                 if (match) {
    394                     bestMatch = thumb;
    395                     bestMatchCount = attributes.getLength();
    396                 }
    397             }
    398         }
    399 
    400         if (bestMatch != null) {
    401             NodeList children = bestMatch.getChildNodes();
    402             for (int i = 0, n = children.getLength(); i < n; i++) {
    403                 Node child = children.item(i);
    404                 if (child.getNodeType() == Node.TEXT_NODE) {
    405                     return child.getNodeValue().trim();
    406                 }
    407             }
    408         }
    409 
    410         return null;
    411     }
    412 
    413     /**
    414      * Returns the dependencies (as a list of pairs of names and revisions)
    415      * required by this template
    416      */
    417     List<Pair<String, Integer>> getDependencies() {
    418         if (mDependencies == null) {
    419             NodeList elements = mDocument.getElementsByTagName(TAG_DEPENDENCY);
    420             if (elements.getLength() == 0) {
    421                 return Collections.emptyList();
    422             }
    423 
    424             List<Pair<String, Integer>> dependencies = Lists.newArrayList();
    425             for (int i = 0, n = elements.getLength(); i < n; i++) {
    426                 Element element = (Element) elements.item(i);
    427                 String name = element.getAttribute(ATTR_NAME);
    428                 int revision = -1;
    429                 String revisionString = element.getAttribute(ATTR_REVISION);
    430                 if (!revisionString.isEmpty()) {
    431                     revision = Integer.parseInt(revisionString);
    432                 }
    433                 dependencies.add(Pair.of(name, revision));
    434             }
    435             mDependencies = dependencies;
    436         }
    437 
    438         return mDependencies;
    439     }
    440 
    441     /** Returns the list of available parameters */
    442     @NonNull
    443     List<Parameter> getParameters() {
    444         return mParameters;
    445     }
    446 
    447     /**
    448      * Returns the parameter of the given id, or null if not found
    449      *
    450      * @param id the id of the target parameter
    451      * @return the corresponding parameter, or null if not found
    452      */
    453     @Nullable
    454     public Parameter getParameter(@NonNull String id) {
    455         for (Parameter parameter : mParameters) {
    456             if (id.equals(parameter.id)) {
    457                 return parameter;
    458             }
    459         }
    460 
    461         return null;
    462     }
    463 
    464     /** Returns a default icon for templates */
    465     static Image getDefaultTemplateIcon() {
    466         return IconFactory.getInstance().getIcon("default_template"); //$NON-NLS-1$
    467     }
    468 }
    469