• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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. */
getDescriptor()50     public ElementDescriptor getDescriptor() {
51         if (mDescriptor == null) {
52             mDescriptor = new ElementDescriptor("", getRootElementDescriptors()); //$NON-NLS-1$
53         }
54 
55         return mDescriptor;
56     }
57 
getRootElementDescriptors()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      */
getElementDescriptor(String tag)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 
updateDescriptors(Map<String, DeclareStyleableInfo> styleMap)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