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