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