Home | History | Annotate | Download | only in descriptors
      1 /*
      2  * Copyright (C) 2008 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 
     17 package com.android.ide.eclipse.adt.internal.editors.menu.descriptors;
     18 
     19 import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor;
     20 import com.android.ide.eclipse.adt.internal.editors.descriptors.DescriptorsUtils;
     21 import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor;
     22 import com.android.ide.eclipse.adt.internal.editors.descriptors.IDescriptorProvider;
     23 import com.android.ide.eclipse.adt.internal.editors.descriptors.XmlnsAttributeDescriptor;
     24 import com.android.ide.eclipse.adt.internal.resources.DeclareStyleableInfo;
     25 import com.android.sdklib.SdkConstants;
     26 
     27 import java.util.ArrayList;
     28 import java.util.Map;
     29 
     30 
     31 /**
     32  * Complete description of the menu structure.
     33  */
     34 public final class MenuDescriptors implements IDescriptorProvider {
     35 
     36     public static final String MENU_ROOT_ELEMENT = "menu"; //$NON-NLS-1$
     37 
     38     /** The root element descriptor. */
     39     private ElementDescriptor mDescriptor = null;
     40 
     41     /** @return the root descriptor. */
     42     public ElementDescriptor getDescriptor() {
     43         return mDescriptor;
     44     }
     45 
     46     public ElementDescriptor[] getRootElementDescriptors() {
     47         return mDescriptor.getChildren();
     48     }
     49 
     50     /**
     51      * Updates the document descriptor.
     52      * <p/>
     53      * It first computes the new children of the descriptor and then updates them
     54      * all at once.
     55      *
     56      * @param styleMap The map style => attributes from the attrs.xml file
     57      */
     58     public synchronized void updateDescriptors(Map<String, DeclareStyleableInfo> styleMap) {
     59 
     60         // There are 3 elements: menu, item and group.
     61         // The root element MUST be a menu.
     62         // A top menu can contain items or group:
     63         //  - top groups can contain top items
     64         //  - top items can contain sub-menus
     65         // A sub menu can contains sub items or sub groups:
     66         //  - sub groups can contain sub items
     67         //  - sub items cannot contain anything
     68 
     69         if (mDescriptor == null) {
     70             mDescriptor = createElement(styleMap,
     71                 MENU_ROOT_ELEMENT, // xmlName
     72                 "Menu", // uiName,
     73                 null, // TODO SDK URL
     74                 null, // extraAttribute
     75                 null, // childrenElements,
     76                 true /* mandatory */);
     77         }
     78 
     79         // -- sub menu can have sub_items, sub_groups but not sub_menus
     80 
     81         ElementDescriptor sub_item = createElement(styleMap,
     82                 "item", // xmlName //$NON-NLS-1$
     83                 "Item", // uiName,
     84                 null, // TODO SDK URL
     85                 null, // extraAttribute
     86                 null, // childrenElements,
     87                 false /* mandatory */);
     88 
     89         ElementDescriptor sub_group = createElement(styleMap,
     90                 "group", // xmlName //$NON-NLS-1$
     91                 "Group", // uiName,
     92                 null, // TODO SDK URL
     93                 null, // extraAttribute
     94                 new ElementDescriptor[] { sub_item }, // childrenElements,
     95                 false /* mandatory */);
     96 
     97         ElementDescriptor sub_menu = createElement(styleMap,
     98                 MENU_ROOT_ELEMENT, // xmlName //$NON-NLS-1$
     99                 "Sub-Menu", // uiName,
    100                 null, // TODO SDK URL
    101                 null, // extraAttribute
    102                 new ElementDescriptor[] { sub_item, sub_group }, // childrenElements,
    103                 true /* mandatory */);
    104 
    105         // -- top menu can have all top groups and top items (which can have sub menus)
    106 
    107         ElementDescriptor top_item = createElement(styleMap,
    108                 "item", // xmlName //$NON-NLS-1$
    109                 "Item", // uiName,
    110                 null, // TODO SDK URL
    111                 null, // extraAttribute
    112                 new ElementDescriptor[] { sub_menu }, // childrenElements,
    113                 false /* mandatory */);
    114 
    115         ElementDescriptor top_group = createElement(styleMap,
    116                 "group", // xmlName //$NON-NLS-1$
    117                 "Group", // uiName,
    118                 null, // TODO SDK URL
    119                 null, // extraAttribute
    120                 new ElementDescriptor[] { top_item }, // childrenElements,
    121                 false /* mandatory */);
    122 
    123         XmlnsAttributeDescriptor xmlns = new XmlnsAttributeDescriptor("android", //$NON-NLS-1$
    124                 SdkConstants.NS_RESOURCES);
    125 
    126         updateElement(mDescriptor, styleMap, "Menu", xmlns); //$NON-NLS-1$
    127         mDescriptor.setChildren(new ElementDescriptor[] { top_item, top_group });
    128     }
    129 
    130     /**
    131      * Returns a new ElementDescriptor constructed from the information given here
    132      * and the javadoc & attributes extracted from the style map if any.
    133      */
    134     private ElementDescriptor createElement(
    135             Map<String, DeclareStyleableInfo> styleMap,
    136             String xmlName, String uiName, String sdkUrl,
    137             AttributeDescriptor extraAttribute,
    138             ElementDescriptor[] childrenElements, boolean mandatory) {
    139 
    140         ElementDescriptor element = new ElementDescriptor(xmlName, uiName, null, sdkUrl,
    141                 null, childrenElements, mandatory);
    142 
    143         return updateElement(element, styleMap,
    144                 getStyleName(xmlName),
    145                 extraAttribute);
    146     }
    147 
    148     /**
    149      * Updates an ElementDescriptor with the javadoc & attributes extracted from the style
    150      * map if any.
    151      */
    152     private ElementDescriptor updateElement(ElementDescriptor element,
    153             Map<String, DeclareStyleableInfo> styleMap,
    154             String styleName,
    155             AttributeDescriptor extraAttribute) {
    156         ArrayList<AttributeDescriptor> descs = new ArrayList<AttributeDescriptor>();
    157 
    158         DeclareStyleableInfo style = styleMap != null ? styleMap.get(styleName) : null;
    159         if (style != null) {
    160             DescriptorsUtils.appendAttributes(descs,
    161                     null,   // elementName
    162                     SdkConstants.NS_RESOURCES,
    163                     style.getAttributes(),
    164                     null,   // requiredAttributes
    165                     null);  // overrides
    166             element.setTooltip(style.getJavaDoc());
    167         }
    168 
    169         if (extraAttribute != null) {
    170             descs.add(extraAttribute);
    171         }
    172 
    173         element.setAttributes(descs.toArray(new AttributeDescriptor[descs.size()]));
    174         return element;
    175     }
    176 
    177     /**
    178      * Returns the style name (i.e. the <declare-styleable> name found in attrs.xml)
    179      * for a given XML element name.
    180      * <p/>
    181      * The rule is that all elements have for style name:
    182      * - their xml name capitalized
    183      * - a "Menu" prefix, except for <menu> itself which is just "Menu".
    184      */
    185     private String getStyleName(String xmlName) {
    186         String styleName = DescriptorsUtils.capitalize(xmlName);
    187 
    188         // This is NOT the UI Name but the expected internal style name
    189         final String MENU_STYLE_BASE_NAME = "Menu"; //$NON-NLS-1$
    190 
    191         if (!styleName.equals(MENU_STYLE_BASE_NAME)) {
    192             styleName = MENU_STYLE_BASE_NAME + styleName;
    193         }
    194         return styleName;
    195     }
    196 }
    197