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