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