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.xml.descriptors;
     18 
     19 import static com.android.ide.common.layout.LayoutConstants.ANDROID_NS_NAME;
     20 
     21 import com.android.ide.common.resources.platform.AttributeInfo;
     22 import com.android.ide.common.resources.platform.DeclareStyleableInfo;
     23 import com.android.ide.common.resources.platform.ViewClassInfo;
     24 import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor;
     25 import com.android.ide.eclipse.adt.internal.editors.descriptors.DescriptorsUtils;
     26 import com.android.ide.eclipse.adt.internal.editors.descriptors.DocumentDescriptor;
     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.SeparatorAttributeDescriptor;
     30 import com.android.ide.eclipse.adt.internal.editors.descriptors.XmlnsAttributeDescriptor;
     31 import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.ViewElementDescriptor;
     32 import com.android.sdklib.SdkConstants;
     33 
     34 import java.util.ArrayList;
     35 import java.util.Map;
     36 
     37 
     38 /**
     39  * Description of the /res/xml structure.
     40  * Currently supports the <searchable> and <preferences> root nodes.
     41  */
     42 public final class XmlDescriptors implements IDescriptorProvider {
     43 
     44     // Public attributes names, attributes descriptors and elements descriptors referenced
     45     // elsewhere.
     46     public static final String PREF_KEY_ATTR = "key"; //$NON-NLS-1$
     47 
     48     /** The root document descriptor for both searchable and preferences. */
     49     private DocumentDescriptor mDescriptor = new DocumentDescriptor("xml_doc", null /* children */); //$NON-NLS-1$
     50 
     51     /** The root document descriptor for searchable. */
     52     private DocumentDescriptor mSearchDescriptor = new DocumentDescriptor("xml_doc", null /* children */); //$NON-NLS-1$
     53 
     54     /** The root document descriptor for preferences. */
     55     private DocumentDescriptor mPrefDescriptor = new DocumentDescriptor("xml_doc", null /* children */); //$NON-NLS-1$
     56 
     57     /** The root document descriptor for widget provider. */
     58     private DocumentDescriptor mAppWidgetDescriptor = new DocumentDescriptor("xml_doc", null /* children */); //$NON-NLS-1$
     59 
     60     /** @return the root descriptor for both searchable and preferences. */
     61     public DocumentDescriptor getDescriptor() {
     62         return mDescriptor;
     63     }
     64 
     65     public ElementDescriptor[] getRootElementDescriptors() {
     66         return mDescriptor.getChildren();
     67     }
     68 
     69     /** @return the root descriptor for searchable. */
     70     public DocumentDescriptor getSearchableDescriptor() {
     71         return mSearchDescriptor;
     72     }
     73 
     74     /** @return the root descriptor for preferences. */
     75     public DocumentDescriptor getPreferencesDescriptor() {
     76         return mPrefDescriptor;
     77     }
     78 
     79     /** @return the root descriptor for widget providers. */
     80     public DocumentDescriptor getAppWidgetDescriptor() {
     81         return mAppWidgetDescriptor;
     82     }
     83 
     84     public IDescriptorProvider getSearchableProvider() {
     85         return new IDescriptorProvider() {
     86             public ElementDescriptor getDescriptor() {
     87                 return mSearchDescriptor;
     88             }
     89 
     90             public ElementDescriptor[] getRootElementDescriptors() {
     91                 return mSearchDescriptor.getChildren();
     92             }
     93         };
     94     }
     95 
     96     public IDescriptorProvider getPreferencesProvider() {
     97         return new IDescriptorProvider() {
     98             public ElementDescriptor getDescriptor() {
     99                 return mPrefDescriptor;
    100             }
    101 
    102             public ElementDescriptor[] getRootElementDescriptors() {
    103                 return mPrefDescriptor.getChildren();
    104             }
    105         };
    106     }
    107 
    108     public IDescriptorProvider getAppWidgetProvider() {
    109         return new IDescriptorProvider() {
    110             public ElementDescriptor getDescriptor() {
    111                 return mAppWidgetDescriptor;
    112             }
    113 
    114             public ElementDescriptor[] getRootElementDescriptors() {
    115                 return mAppWidgetDescriptor.getChildren();
    116             }
    117         };
    118     }
    119 
    120     /**
    121      * Updates the document descriptor.
    122      * <p/>
    123      * It first computes the new children of the descriptor and then updates them
    124      * all at once.
    125      *
    126      * @param searchableStyleMap The map style=>attributes for <searchable> from the attrs.xml file
    127      * @param appWidgetStyleMap The map style=>attributes for <appwidget-provider> from the attrs.xml file
    128      * @param prefs The list of non-group preference descriptions
    129      * @param prefGroups The list of preference group descriptions
    130      */
    131     public synchronized void updateDescriptors(
    132             Map<String, DeclareStyleableInfo> searchableStyleMap,
    133             Map<String, DeclareStyleableInfo> appWidgetStyleMap,
    134             ViewClassInfo[] prefs, ViewClassInfo[] prefGroups) {
    135 
    136         XmlnsAttributeDescriptor xmlns = new XmlnsAttributeDescriptor(
    137                 ANDROID_NS_NAME,
    138                 SdkConstants.NS_RESOURCES);
    139 
    140         ElementDescriptor searchable = createSearchable(searchableStyleMap, xmlns);
    141         ElementDescriptor appWidget = createAppWidgetProviderInfo(appWidgetStyleMap, xmlns);
    142         ElementDescriptor preferences = createPreference(prefs, prefGroups, xmlns);
    143         ArrayList<ElementDescriptor> list =  new ArrayList<ElementDescriptor>();
    144         if (searchable != null) {
    145             list.add(searchable);
    146             mSearchDescriptor.setChildren(new ElementDescriptor[]{ searchable });
    147         }
    148         if (appWidget != null) {
    149             list.add(appWidget);
    150             mAppWidgetDescriptor.setChildren(new ElementDescriptor[]{ appWidget });
    151         }
    152         if (preferences != null) {
    153             list.add(preferences);
    154             mPrefDescriptor.setChildren(new ElementDescriptor[]{ preferences });
    155         }
    156 
    157         if (list.size() > 0) {
    158             mDescriptor.setChildren(list.toArray(new ElementDescriptor[list.size()]));
    159         }
    160     }
    161 
    162     //-------------------------
    163     // Creation of <searchable>
    164     //-------------------------
    165 
    166     /**
    167      * Returns the new ElementDescriptor for <searchable>
    168      */
    169     private ElementDescriptor createSearchable(
    170             Map<String, DeclareStyleableInfo> searchableStyleMap,
    171             XmlnsAttributeDescriptor xmlns) {
    172 
    173         ElementDescriptor action_key = createElement(searchableStyleMap,
    174                 "SearchableActionKey", //$NON-NLS-1$ styleName
    175                 "actionkey", //$NON-NLS-1$ xmlName
    176                 "Action Key", // uiName
    177                 null, // sdk url
    178                 null, // extraAttribute
    179                 null, // childrenElements
    180                 false /* mandatory */ );
    181 
    182         ElementDescriptor searchable = createElement(searchableStyleMap,
    183                 "Searchable", //$NON-NLS-1$ styleName
    184                 "searchable", //$NON-NLS-1$ xmlName
    185                 "Searchable", // uiName
    186                 null, // sdk url
    187                 xmlns, // extraAttribute
    188                 new ElementDescriptor[] { action_key }, // childrenElements
    189                 false /* mandatory */ );
    190         return searchable;
    191     }
    192 
    193     /**
    194      * Returns the new ElementDescriptor for <appwidget-provider>
    195      */
    196     private ElementDescriptor createAppWidgetProviderInfo(
    197             Map<String, DeclareStyleableInfo> appWidgetStyleMap,
    198             XmlnsAttributeDescriptor xmlns) {
    199 
    200         if (appWidgetStyleMap == null) {
    201             return null;
    202         }
    203 
    204         ElementDescriptor appWidget = createElement(appWidgetStyleMap,
    205                 "AppWidgetProviderInfo", //$NON-NLS-1$ styleName
    206                 "appwidget-provider", //$NON-NLS-1$ xmlName
    207                 "AppWidget Provider", // uiName
    208                 null, // sdk url
    209                 xmlns, // extraAttribute
    210                 null, // childrenElements
    211                 false /* mandatory */ );
    212         return appWidget;
    213     }
    214 
    215     /**
    216      * Returns a new ElementDescriptor constructed from the information given here
    217      * and the javadoc & attributes extracted from the style map if any.
    218      */
    219     private ElementDescriptor createElement(
    220             Map<String, DeclareStyleableInfo> styleMap, String styleName,
    221             String xmlName, String uiName, String sdkUrl,
    222             AttributeDescriptor extraAttribute,
    223             ElementDescriptor[] childrenElements, boolean mandatory) {
    224 
    225         ElementDescriptor element = new ElementDescriptor(xmlName, uiName, null, sdkUrl,
    226                 null, childrenElements, mandatory);
    227 
    228         return updateElement(element, styleMap, styleName, extraAttribute);
    229     }
    230 
    231     /**
    232      * Updates an ElementDescriptor with the javadoc & attributes extracted from the style
    233      * map if any.
    234      */
    235     private ElementDescriptor updateElement(ElementDescriptor element,
    236             Map<String, DeclareStyleableInfo> styleMap,
    237             String styleName,
    238             AttributeDescriptor extraAttribute) {
    239         ArrayList<AttributeDescriptor> descs = new ArrayList<AttributeDescriptor>();
    240 
    241         DeclareStyleableInfo style = styleMap != null ? styleMap.get(styleName) : null;
    242         if (style != null) {
    243             DescriptorsUtils.appendAttributes(descs,
    244                     null,   // elementName
    245                     SdkConstants.NS_RESOURCES,
    246                     style.getAttributes(),
    247                     null,   // requiredAttributes
    248                     null);  // overrides
    249             element.setTooltip(style.getJavaDoc());
    250         }
    251 
    252         if (extraAttribute != null) {
    253             descs.add(extraAttribute);
    254         }
    255 
    256         element.setAttributes(descs.toArray(new AttributeDescriptor[descs.size()]));
    257         return element;
    258     }
    259 
    260     //--------------------------
    261     // Creation of <Preferences>
    262     //--------------------------
    263 
    264     /**
    265      * Returns the new ElementDescriptor for <Preferences>
    266      */
    267     private ElementDescriptor createPreference(ViewClassInfo[] prefs,
    268             ViewClassInfo[] prefGroups, XmlnsAttributeDescriptor xmlns) {
    269 
    270         ArrayList<ElementDescriptor> newPrefs = new ArrayList<ElementDescriptor>();
    271         if (prefs != null) {
    272             for (ViewClassInfo info : prefs) {
    273                 ElementDescriptor desc = convertPref(info);
    274                 newPrefs.add(desc);
    275             }
    276         }
    277 
    278         ElementDescriptor topPreferences = null;
    279 
    280         ArrayList<ElementDescriptor> newGroups = new ArrayList<ElementDescriptor>();
    281         if (prefGroups != null) {
    282             for (ViewClassInfo info : prefGroups) {
    283                 ElementDescriptor desc = convertPref(info);
    284                 newGroups.add(desc);
    285 
    286                 if (info.getFullClassName() == SdkConstants.CLASS_PREFERENCES) {
    287                     topPreferences = desc;
    288                 }
    289             }
    290         }
    291 
    292         ArrayList<ElementDescriptor> everything = new ArrayList<ElementDescriptor>();
    293         everything.addAll(newGroups);
    294         everything.addAll(newPrefs);
    295         ElementDescriptor[] newArray = everything.toArray(new ElementDescriptor[everything.size()]);
    296 
    297         // Link all groups to everything else here.. recursively
    298         for (ElementDescriptor layoutDesc : newGroups) {
    299             layoutDesc.setChildren(newArray);
    300         }
    301 
    302         // The "top" element to be returned corresponds to the class "Preferences".
    303         // Its descriptor has already been created. However the root one also needs
    304         // the hidden xmlns:android definition..
    305         if (topPreferences != null) {
    306             AttributeDescriptor[] attrs = topPreferences.getAttributes();
    307             AttributeDescriptor[] newAttrs = new AttributeDescriptor[attrs.length + 1];
    308             System.arraycopy(attrs, 0, newAttrs, 0, attrs.length);
    309             newAttrs[attrs.length] = xmlns;
    310             return new ElementDescriptor(
    311                     topPreferences.getXmlName(),
    312                     topPreferences.getUiName(),
    313                     topPreferences.getTooltip(),
    314                     topPreferences.getSdkUrl(),
    315                     newAttrs,
    316                     topPreferences.getChildren(),
    317                     false /* mandatory */);
    318         } else {
    319             return null;
    320         }
    321     }
    322 
    323     /**
    324      * Creates an element descriptor from a given {@link ViewClassInfo}.
    325      */
    326     private ElementDescriptor convertPref(ViewClassInfo info) {
    327         String xml_name = info.getShortClassName();
    328         String tooltip = info.getJavaDoc();
    329 
    330         // Process all Preference attributes
    331         ArrayList<AttributeDescriptor> attributes = new ArrayList<AttributeDescriptor>();
    332         DescriptorsUtils.appendAttributes(attributes,
    333                 null,   // elementName
    334                 SdkConstants.NS_RESOURCES,
    335                 info.getAttributes(),
    336                 null,   // requiredAttributes
    337                 null);  // overrides
    338 
    339         for (ViewClassInfo link = info.getSuperClass();
    340                 link != null;
    341                 link = link.getSuperClass()) {
    342             AttributeInfo[] attrList = link.getAttributes();
    343             if (attrList.length > 0) {
    344                 attributes.add(new SeparatorAttributeDescriptor(
    345                         String.format("Attributes from %1$s", link.getShortClassName())));
    346                 DescriptorsUtils.appendAttributes(attributes,
    347                         null,   // elementName
    348                         SdkConstants.NS_RESOURCES,
    349                         attrList,
    350                         null,   // requiredAttributes
    351                         null);  // overrides
    352             }
    353         }
    354 
    355         return new ViewElementDescriptor(xml_name,
    356                 xml_name, // ui_name
    357                 info.getFullClassName(),
    358                 tooltip,
    359                 null, // sdk_url
    360                 attributes.toArray(new AttributeDescriptor[attributes.size()]),
    361                 null,
    362                 null, // children
    363                 false /* mandatory */);
    364     }
    365 }
    366