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