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