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