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.SdkConstants.ANDROID_NS_NAME;
     20 import static com.android.SdkConstants.ANDROID_URI;
     21 
     22 import com.android.SdkConstants;
     23 import com.android.ide.common.resources.platform.AttributeInfo;
     24 import com.android.ide.common.resources.platform.DeclareStyleableInfo;
     25 import com.android.ide.common.resources.platform.ViewClassInfo;
     26 import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor;
     27 import com.android.ide.eclipse.adt.internal.editors.descriptors.DescriptorsUtils;
     28 import com.android.ide.eclipse.adt.internal.editors.descriptors.DocumentDescriptor;
     29 import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor;
     30 import com.android.ide.eclipse.adt.internal.editors.descriptors.IDescriptorProvider;
     31 import com.android.ide.eclipse.adt.internal.editors.descriptors.SeparatorAttributeDescriptor;
     32 import com.android.ide.eclipse.adt.internal.editors.descriptors.XmlnsAttributeDescriptor;
     33 import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.ViewElementDescriptor;
     34 
     35 import java.util.ArrayList;
     36 import java.util.Map;
     37 
     38 
     39 /**
     40  * Description of the /res/xml structure.
     41  * Currently supports the <searchable> and <preferences> root nodes.
     42  */
     43 public final class OtherXmlDescriptors implements IDescriptorProvider {
     44 
     45     // Public attributes names, attributes descriptors and elements descriptors referenced
     46     // elsewhere.
     47     public static final String PREF_KEY_ATTR = "key"; //$NON-NLS-1$
     48 
     49     /** The root document descriptor for both searchable and preferences. */
     50     private DocumentDescriptor mDescriptor = new DocumentDescriptor("xml_doc", null /* children */); //$NON-NLS-1$
     51 
     52     /** The root document descriptor for searchable. */
     53     private DocumentDescriptor mSearchDescriptor = new DocumentDescriptor("xml_doc", null /* children */); //$NON-NLS-1$
     54 
     55     /** The root document descriptor for preferences. */
     56     private DocumentDescriptor mPrefDescriptor = new DocumentDescriptor("xml_doc", null /* children */); //$NON-NLS-1$
     57 
     58     /** The root document descriptor for widget provider. */
     59     private DocumentDescriptor mAppWidgetDescriptor = new DocumentDescriptor("xml_doc", null /* children */); //$NON-NLS-1$
     60 
     61     /** @return the root descriptor for both searchable and preferences. */
     62     @Override
     63     public DocumentDescriptor getDescriptor() {
     64         return mDescriptor;
     65     }
     66 
     67     @Override
     68     public ElementDescriptor[] getRootElementDescriptors() {
     69         return mDescriptor.getChildren();
     70     }
     71 
     72     /** @return the root descriptor for searchable. */
     73     public DocumentDescriptor getSearchableDescriptor() {
     74         return mSearchDescriptor;
     75     }
     76 
     77     /** @return the root descriptor for preferences. */
     78     public DocumentDescriptor getPreferencesDescriptor() {
     79         return mPrefDescriptor;
     80     }
     81 
     82     /** @return the root descriptor for widget providers. */
     83     public DocumentDescriptor getAppWidgetDescriptor() {
     84         return mAppWidgetDescriptor;
     85     }
     86 
     87     public IDescriptorProvider getSearchableProvider() {
     88         return new IDescriptorProvider() {
     89             @Override
     90             public ElementDescriptor getDescriptor() {
     91                 return mSearchDescriptor;
     92             }
     93 
     94             @Override
     95             public ElementDescriptor[] getRootElementDescriptors() {
     96                 return mSearchDescriptor.getChildren();
     97             }
     98         };
     99     }
    100 
    101     public IDescriptorProvider getPreferencesProvider() {
    102         return new IDescriptorProvider() {
    103             @Override
    104             public ElementDescriptor getDescriptor() {
    105                 return mPrefDescriptor;
    106             }
    107 
    108             @Override
    109             public ElementDescriptor[] getRootElementDescriptors() {
    110                 return mPrefDescriptor.getChildren();
    111             }
    112         };
    113     }
    114 
    115     public IDescriptorProvider getAppWidgetProvider() {
    116         return new IDescriptorProvider() {
    117             @Override
    118             public ElementDescriptor getDescriptor() {
    119                 return mAppWidgetDescriptor;
    120             }
    121 
    122             @Override
    123             public ElementDescriptor[] getRootElementDescriptors() {
    124                 return mAppWidgetDescriptor.getChildren();
    125             }
    126         };
    127     }
    128 
    129     /**
    130      * Updates the document descriptor.
    131      * <p/>
    132      * It first computes the new children of the descriptor and then updates them
    133      * all at once.
    134      *
    135      * @param searchableStyleMap The map style=>attributes for <searchable> from the attrs.xml file
    136      * @param appWidgetStyleMap The map style=>attributes for <appwidget-provider> from the attrs.xml file
    137      * @param prefs The list of non-group preference descriptions
    138      * @param prefGroups The list of preference group descriptions
    139      */
    140     public synchronized void updateDescriptors(
    141             Map<String, DeclareStyleableInfo> searchableStyleMap,
    142             Map<String, DeclareStyleableInfo> appWidgetStyleMap,
    143             ViewClassInfo[] prefs, ViewClassInfo[] prefGroups) {
    144 
    145         XmlnsAttributeDescriptor xmlns = new XmlnsAttributeDescriptor(ANDROID_NS_NAME,
    146                 ANDROID_URI);
    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