1 /* 2 * Copyright (C) 2011 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 package com.android.ide.eclipse.adt.internal.editors.drawable; 17 18 import static com.android.ide.common.layout.LayoutConstants.ANDROID_NS_NAME; 19 20 import com.android.ide.common.api.IAttributeInfo.Format; 21 import com.android.ide.common.resources.platform.AttributeInfo; 22 import com.android.ide.common.resources.platform.DeclareStyleableInfo; 23 import com.android.ide.eclipse.adt.internal.editors.animator.AnimatorDescriptors; 24 import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor; 25 import com.android.ide.eclipse.adt.internal.editors.descriptors.IDescriptorProvider; 26 import com.android.ide.eclipse.adt.internal.editors.descriptors.ReferenceAttributeDescriptor; 27 import com.android.ide.eclipse.adt.internal.editors.descriptors.XmlnsAttributeDescriptor; 28 import com.android.resources.ResourceType; 29 import com.android.sdklib.SdkConstants; 30 31 import java.util.ArrayList; 32 import java.util.HashMap; 33 import java.util.List; 34 import java.util.Map; 35 36 /** 37 * Descriptors for /res/drawable files 38 */ 39 public class DrawableDescriptors implements IDescriptorProvider { 40 private static final String SDK_URL_BASE = 41 "http://d.android.com/guide/topics/resources/"; //$NON-NLS-1$ 42 43 /** The root element descriptor */ 44 private ElementDescriptor mDescriptor; 45 /** The root element descriptors */ 46 private ElementDescriptor[] mRootDescriptors; 47 private Map<String, ElementDescriptor> nameToDescriptor; 48 49 /** @return the root descriptor. */ 50 public ElementDescriptor getDescriptor() { 51 if (mDescriptor == null) { 52 mDescriptor = new ElementDescriptor("", getRootElementDescriptors()); //$NON-NLS-1$ 53 } 54 55 return mDescriptor; 56 } 57 58 public ElementDescriptor[] getRootElementDescriptors() { 59 return mRootDescriptors; 60 } 61 62 /** 63 * Returns a descriptor for the given root tag name 64 * 65 * @param tag the tag name to look up a descriptor for 66 * @return a descriptor with the given tag name 67 */ 68 public ElementDescriptor getElementDescriptor(String tag) { 69 if (nameToDescriptor == null) { 70 nameToDescriptor = new HashMap<String, ElementDescriptor>(); 71 for (ElementDescriptor descriptor : getRootElementDescriptors()) { 72 nameToDescriptor.put(descriptor.getXmlName(), descriptor); 73 } 74 } 75 76 ElementDescriptor descriptor = nameToDescriptor.get(tag); 77 if (descriptor == null) { 78 descriptor = getDescriptor(); 79 } 80 return descriptor; 81 } 82 83 public synchronized void updateDescriptors(Map<String, DeclareStyleableInfo> styleMap) { 84 XmlnsAttributeDescriptor xmlns = new XmlnsAttributeDescriptor(ANDROID_NS_NAME, 85 SdkConstants.NS_RESOURCES); 86 Format[] referenceFormat = new Format[] { Format.REFERENCE }; 87 88 List<ElementDescriptor> descriptors = new ArrayList<ElementDescriptor>(); 89 90 AnimatorDescriptors.addElement(descriptors, styleMap, 91 "animation-list", "Animation List", "AnimationDrawable", null, //$NON-NLS-1$ //$NON-NLS-3$ 92 "An animation defined in XML that shows a sequence of images in " 93 + "order (like a film)", 94 SDK_URL_BASE + "animation-resource.html#Frame", 95 xmlns, null, true /*mandatory*/); 96 97 AnimatorDescriptors.addElement(descriptors, styleMap, 98 "animated-rotate", "Animated Rotate", "AnimatedRotateDrawable", null, //$NON-NLS-1$ //$NON-NLS-3$ 99 // Need docs 100 null /* tooltip */, 101 null /* sdk_url */, 102 xmlns, null, true /*mandatory*/); 103 104 AnimatorDescriptors.addElement(descriptors, styleMap, 105 "bitmap", "BitMap", "BitmapDrawable", null, //$NON-NLS-1$ //$NON-NLS-3$ 106 "An XML bitmap is a resource defined in XML that points to a bitmap file. " 107 + "The effect is an alias for a raw bitmap file. The XML can " 108 + "specify additional properties for the bitmap such as " 109 + "dithering and tiling.", 110 SDK_URL_BASE + "drawable-resource.html#Bitmap", //$NON-NLS-1$ 111 xmlns, null, true /* mandatory */); 112 113 AnimatorDescriptors.addElement(descriptors, styleMap, 114 "clip", "Clip", "ClipDrawable", null, //$NON-NLS-1$ //$NON-NLS-3$ 115 "An XML file that defines a drawable that clips another Drawable based on " 116 + "this Drawable's current level value.", 117 SDK_URL_BASE + "drawable-resource.html#Clip", //$NON-NLS-1$ 118 xmlns, null, true /*mandatory*/); 119 120 121 AnimatorDescriptors.addElement(descriptors, styleMap, 122 "color", "Color", "ColorDrawable", null, //$NON-NLS-1$ //$NON-NLS-3$ 123 "XML resource that carries a color value (a hexadecimal color)", 124 SDK_URL_BASE + "more-resources.html#Color", 125 xmlns, null, true /*mandatory*/); 126 127 AnimatorDescriptors.addElement(descriptors, styleMap, 128 "inset", "Inset", "InsetDrawable", null, //$NON-NLS-1$ //$NON-NLS-3$ 129 "An XML file that defines a drawable that insets another drawable by a " 130 + "specified distance. This is useful when a View needs a background " 131 + "drawble that is smaller than the View's actual bounds.", 132 SDK_URL_BASE + "drawable-resource.html#Inset", //$NON-NLS-1$ 133 xmlns, null, true /*mandatory*/); 134 135 // Layer list 136 137 // An <item> in a <selector> or < 138 ElementDescriptor layerItem = AnimatorDescriptors.addElement(null, styleMap, 139 "item", "Item", "LayerDrawableItem", null, //$NON-NLS-1$ //$NON-NLS-3$ 140 "Defines a drawable to place in the layer drawable, in a position " 141 + "defined by its attributes. Must be a child of a <selector> " 142 + "element. Accepts child <bitmap> elements.", 143 SDK_URL_BASE + "drawable-resource.html#LayerList", //$NON-NLS-1$ 144 null, /* extra attribute */ 145 null, /* This is wrong -- we can now embed any above drawable 146 (but without xmlns as extra) */ 147 false /*mandatory*/); 148 ElementDescriptor[] layerChildren = layerItem != null 149 ? new ElementDescriptor[] { layerItem } : null; 150 151 AnimatorDescriptors.addElement(descriptors, styleMap, 152 "layer-list", "Layer List", "LayerDrawable", null, //$NON-NLS-1$ //$NON-NLS-3$ 153 "A Drawable that manages an array of other Drawables. These are drawn in " 154 + "array order, so the element with the largest index is be drawn on top.", 155 SDK_URL_BASE + "drawable-resource.html#LayerList", //$NON-NLS-1$ 156 xmlns, 157 layerChildren, 158 true /*mandatory*/); 159 160 // Level list children 161 ElementDescriptor levelListItem = AnimatorDescriptors.addElement(null, styleMap, 162 "item", "Item", "LevelListDrawableItem", null, //$NON-NLS-1$ //$NON-NLS-3$ 163 "Defines a drawable to use at a certain level.", 164 SDK_URL_BASE + "drawable-resource.html#LevelList", //$NON-NLS-1$ 165 null, /* extra attribute */ 166 null, /* no further children */ 167 // TODO: The inflation code seems to show that all drawables can be nested here! 168 false /*mandatory*/); 169 AnimatorDescriptors.addElement(descriptors, styleMap, 170 "level-list", "Level List", "LevelListDrawable", null, //$NON-NLS-1$ //$NON-NLS-3$ 171 "An XML file that defines a drawable that manages a number of alternate " 172 + "Drawables, each assigned a maximum numerical value", 173 SDK_URL_BASE + "drawable-resource.html#LevelList", //$NON-NLS-1$ 174 xmlns, 175 levelListItem != null ? new ElementDescriptor[] { levelListItem } : null, 176 true /*mandatory*/); 177 178 // Not yet supported 179 //addElement(descriptors, styleMap, "mipmap", "Mipmap", "MipmapDrawable", null, 180 // null /* tooltip */, 181 // null /* sdk_url */, 182 // xmlns, null, true /*mandatory*/); 183 184 AnimatorDescriptors.addElement(descriptors, styleMap, 185 "nine-patch", "Nine Patch", "NinePatchDrawable", null, //$NON-NLS-1$ //$NON-NLS-3$ 186 "A PNG file with stretchable regions to allow image resizing " 187 + "based on content (.9.png).", 188 SDK_URL_BASE + "drawable-resource.html#NinePatch", //$NON-NLS-1$ 189 xmlns, null, true /*mandatory*/); 190 191 AnimatorDescriptors.addElement(descriptors, styleMap, 192 "rotate", "Rotate", "RotateDrawable", null, //$NON-NLS-1$ //$NON-NLS-3$ 193 // Need docs 194 null /* tooltip */, 195 null /* sdk_url */, 196 xmlns, null, true /*mandatory*/); 197 198 AnimatorDescriptors.addElement(descriptors, styleMap, 199 "scale", "Shape", "ScaleDrawable", null, //$NON-NLS-1$ //$NON-NLS-3$ 200 "An XML file that defines a drawable that changes the size of another Drawable " 201 + "based on its current level value.", 202 SDK_URL_BASE + "drawable-resource.html#Scale", //$NON-NLS-1$ 203 xmlns, null, true /*mandatory*/); 204 205 // Selector children 206 ElementDescriptor selectorItem = AnimatorDescriptors.addElement(null, styleMap, 207 "item", "Item", "DrawableStates", null, //$NON-NLS-1$ //$NON-NLS-3$ 208 "Defines a drawable to use during certain states, as described by " 209 + "its attributes. Must be a child of a <selector> element.", 210 SDK_URL_BASE + "drawable-resource.html#StateList", //$NON-NLS-1$ 211 new ReferenceAttributeDescriptor( 212 ResourceType.DRAWABLE, "drawable", "drawable", //$NON-NLS-1$ //$NON-NLS-2$ 213 SdkConstants.NS_RESOURCES, 214 "Reference to a drawable resource.", 215 new AttributeInfo("drawable", referenceFormat)), 216 null, /* This is wrong -- we can now embed any above drawable 217 (but without xmlns as extra) */ 218 false /*mandatory*/); 219 220 AnimatorDescriptors.addElement(descriptors, styleMap, 221 "selector", "Selector", "StateListDrawable", null, //$NON-NLS-1$ //$NON-NLS-3$ 222 "An XML file that references different bitmap graphics for different states " 223 + "(for example, to use a different image when a button is pressed).", 224 SDK_URL_BASE + "drawable-resource.html#StateList", //$NON-NLS-1$ 225 xmlns, 226 selectorItem != null ? new ElementDescriptor[] { selectorItem } : null, 227 true /*mandatory*/); 228 229 // Shape 230 // Shape children 231 List<ElementDescriptor> shapeChildren = new ArrayList<ElementDescriptor>(); 232 // Selector children 233 AnimatorDescriptors.addElement(shapeChildren, styleMap, 234 "size", "Size", "GradientDrawableSize", null, //$NON-NLS-1$ //$NON-NLS-3$ 235 null /* tooltip */, null /* sdk_url */, null /* extra attribute */, 236 null /* children */, false /* mandatory */); 237 AnimatorDescriptors.addElement(shapeChildren, styleMap, 238 "gradient", "Gradient", "GradientDrawableGradient", null, //$NON-NLS-1$ //$NON-NLS-3$ 239 null /* tooltip */, null /* sdk_url */, null /* extra attribute */, 240 null /* children */, false /* mandatory */); 241 AnimatorDescriptors.addElement(shapeChildren, styleMap, 242 "solid", "Solid", "GradientDrawableSolid", null, //$NON-NLS-1$ //$NON-NLS-3$ 243 null /* tooltip */, null /* sdk_url */, null /* extra attribute */, 244 null /* children */, false /* mandatory */); 245 AnimatorDescriptors.addElement(shapeChildren, styleMap, 246 "stroke", "Stroke", "GradientDrawableStroke", null, //$NON-NLS-1$ //$NON-NLS-3$ 247 null /* tooltip */, null /* sdk_url */, null /* extra attribute */, 248 null /* children */, false /* mandatory */); 249 AnimatorDescriptors.addElement(shapeChildren, styleMap, 250 "corners", "Corners", "DrawableCorners", null, //$NON-NLS-1$ //$NON-NLS-3$ 251 null /* tooltip */, null /* sdk_url */, null /* extra attribute */, 252 null /* children */, false /* mandatory */); 253 AnimatorDescriptors.addElement(shapeChildren, styleMap, 254 "padding", "Padding", "GradientDrawablePadding", null, //$NON-NLS-1$ //$NON-NLS-3$ 255 null /* tooltip */, null /* sdk_url */, null /* extra attribute */, 256 null /* children */, false /* mandatory */); 257 258 AnimatorDescriptors.addElement(descriptors, styleMap, 259 "shape", "Shape", //$NON-NLS-1$ 260 261 // The documentation says that a <shape> element creates a ShapeDrawable, 262 // but ShapeDrawable isn't finished and the code currently creates 263 // a GradientDrawable. 264 //"ShapeDrawable", //$NON-NLS-1$ 265 "GradientDrawable", //$NON-NLS-1$ 266 267 null, 268 "An XML file that defines a geometric shape, including colors and gradients.", 269 SDK_URL_BASE + "drawable-resource.html#Shape", //$NON-NLS-1$ 270 xmlns, 271 272 // These are the GradientDrawable children, not the ShapeDrawable children 273 shapeChildren.toArray(new ElementDescriptor[shapeChildren.size()]), 274 true /*mandatory*/); 275 276 AnimatorDescriptors.addElement(descriptors, styleMap, 277 "transition", "Transition", "TransitionDrawable", null, //$NON-NLS-1$ //$NON-NLS-3$ 278 "An XML file that defines a drawable that can cross-fade between two " 279 + "drawable resources. Each drawable is represented by an <item> " 280 + "element inside a single <transition> element. No more than two " 281 + "items are supported. To transition forward, call startTransition(). " 282 + "To transition backward, call reverseTransition().", 283 SDK_URL_BASE + "drawable-resource.html#Transition", //$NON-NLS-1$ 284 xmlns, 285 layerChildren, // children: a TransitionDrawable is a LayerDrawable 286 true /*mandatory*/); 287 288 mRootDescriptors = descriptors.toArray(new ElementDescriptor[descriptors.size()]); 289 290 // A <selector><item> can contain any of the top level drawables 291 if (selectorItem != null) { 292 selectorItem.setChildren(mRootDescriptors); 293 } 294 // Docs says it can accept <bitmap> but code comment suggests any is possible; 295 // test and either use this or just { bitmap } 296 if (layerItem != null) { 297 layerItem.setChildren(mRootDescriptors); 298 } 299 } 300 } 301