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