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.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 OtherXmlDescriptors 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 @Override 62 public DocumentDescriptor getDescriptor() { 63 return mDescriptor; 64 } 65 66 @Override 67 public ElementDescriptor[] getRootElementDescriptors() { 68 return mDescriptor.getChildren(); 69 } 70 71 /** @return the root descriptor for searchable. */ 72 public DocumentDescriptor getSearchableDescriptor() { 73 return mSearchDescriptor; 74 } 75 76 /** @return the root descriptor for preferences. */ 77 public DocumentDescriptor getPreferencesDescriptor() { 78 return mPrefDescriptor; 79 } 80 81 /** @return the root descriptor for widget providers. */ 82 public DocumentDescriptor getAppWidgetDescriptor() { 83 return mAppWidgetDescriptor; 84 } 85 86 public IDescriptorProvider getSearchableProvider() { 87 return new IDescriptorProvider() { 88 @Override 89 public ElementDescriptor getDescriptor() { 90 return mSearchDescriptor; 91 } 92 93 @Override 94 public ElementDescriptor[] getRootElementDescriptors() { 95 return mSearchDescriptor.getChildren(); 96 } 97 }; 98 } 99 100 public IDescriptorProvider getPreferencesProvider() { 101 return new IDescriptorProvider() { 102 @Override 103 public ElementDescriptor getDescriptor() { 104 return mPrefDescriptor; 105 } 106 107 @Override 108 public ElementDescriptor[] getRootElementDescriptors() { 109 return mPrefDescriptor.getChildren(); 110 } 111 }; 112 } 113 114 public IDescriptorProvider getAppWidgetProvider() { 115 return new IDescriptorProvider() { 116 @Override 117 public ElementDescriptor getDescriptor() { 118 return mAppWidgetDescriptor; 119 } 120 121 @Override 122 public ElementDescriptor[] getRootElementDescriptors() { 123 return mAppWidgetDescriptor.getChildren(); 124 } 125 }; 126 } 127 128 /** 129 * Updates the document descriptor. 130 * <p/> 131 * It first computes the new children of the descriptor and then updates them 132 * all at once. 133 * 134 * @param searchableStyleMap The map style=>attributes for <searchable> from the attrs.xml file 135 * @param appWidgetStyleMap The map style=>attributes for <appwidget-provider> from the attrs.xml file 136 * @param prefs The list of non-group preference descriptions 137 * @param prefGroups The list of preference group descriptions 138 */ 139 public synchronized void updateDescriptors( 140 Map<String, DeclareStyleableInfo> searchableStyleMap, 141 Map<String, DeclareStyleableInfo> appWidgetStyleMap, 142 ViewClassInfo[] prefs, ViewClassInfo[] prefGroups) { 143 144 XmlnsAttributeDescriptor xmlns = new XmlnsAttributeDescriptor( 145 ANDROID_NS_NAME, 146 SdkConstants.NS_RESOURCES); 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