• 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 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. */
getDescriptor()61     public DocumentDescriptor getDescriptor() {
62         return mDescriptor;
63     }
64 
getRootElementDescriptors()65     public ElementDescriptor[] getRootElementDescriptors() {
66         return mDescriptor.getChildren();
67     }
68 
69     /** @return the root descriptor for searchable. */
getSearchableDescriptor()70     public DocumentDescriptor getSearchableDescriptor() {
71         return mSearchDescriptor;
72     }
73 
74     /** @return the root descriptor for preferences. */
getPreferencesDescriptor()75     public DocumentDescriptor getPreferencesDescriptor() {
76         return mPrefDescriptor;
77     }
78 
79     /** @return the root descriptor for widget providers. */
getAppWidgetDescriptor()80     public DocumentDescriptor getAppWidgetDescriptor() {
81         return mAppWidgetDescriptor;
82     }
83 
getSearchableProvider()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