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.layout.descriptors;
18 
19 import static com.android.SdkConstants.ANDROID_VIEW_PKG;
20 import static com.android.SdkConstants.ANDROID_WEBKIT_PKG;
21 import static com.android.SdkConstants.ANDROID_WIDGET_PREFIX;
22 import static com.android.SdkConstants.VIEW;
23 import static com.android.SdkConstants.VIEW_TAG;
24 
25 import com.android.ide.common.resources.platform.AttributeInfo;
26 import com.android.ide.eclipse.adt.AdtPlugin;
27 import com.android.ide.eclipse.adt.internal.editors.IconFactory;
28 import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor;
29 import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor;
30 import com.android.ide.eclipse.adt.internal.editors.layout.uimodel.UiViewElementNode;
31 import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode;
32 
33 import org.eclipse.swt.graphics.Image;
34 
35 import java.util.Collections;
36 import java.util.List;
37 
38 /**
39  * {@link ViewElementDescriptor} describes the properties expected for a given XML element node
40  * representing a class in an XML Layout file.
41  * <p/>
42  * These descriptors describe Android views XML elements.
43  * <p/>
44  * The base class {@link ElementDescriptor} has a notion of "children", that is an XML element
45  * can produce another set of XML elements. Because of the flat nature of Android's layout
46  * XML files all possible views are children of the document and of themselves (that is any
47  * view group can contain any other view). This is an implied contract of this class that is
48  * enforces at construction by {@link LayoutDescriptors}. Note that by construction any code
49  * that deals with the children hierarchy must also deal with potential infinite loops since views
50  * <em>will</em> reference themselves (e.g. a ViewGroup can contain a ViewGroup).
51  * <p/>
52  * Since Views are also Java classes, they derive from each other. Here this is represented
53  * as the "super class", which denotes the fact that a given View java class derives from
54  * another class. These properties are also set at construction by {@link LayoutDescriptors}.
55  * The super class hierarchy is very different from the descriptor's children hierarchy: the
56  * later represents Java inheritance, the former represents an XML nesting capability.
57  *
58  * @see ElementDescriptor
59  */
60 public class ViewElementDescriptor extends ElementDescriptor {
61 
62     /** The full class name (FQCN) of this view. */
63     private final String mFullClassName;
64 
65     /** The list of layout attributes. Can be empty but not null. */
66     private AttributeDescriptor[] mLayoutAttributes;
67 
68     /** The super-class descriptor. Can be null. */
69     private ViewElementDescriptor mSuperClassDesc;
70 
71     /** List of attribute sources, classes that contribute attributes to {@link #mAttributes} */
72     private List<String> mAttributeSources;
73 
74     /**
75      * Constructs a new {@link ViewElementDescriptor} based on its XML name, UI name,
76      * the canonical name of the class it represents, its tooltip, its SDK url, its attributes list,
77      * its children list and its mandatory flag.
78      *
79      * @param xml_name The XML element node name. Case sensitive.
80      * @param ui_name The XML element name for the user interface, typically capitalized.
81      * @param fullClassName The fully qualified class name the {@link ViewElementDescriptor} is
82      *          representing.
83      * @param tooltip An optional tooltip. Can be null or empty.
84      * @param sdk_url An optional SKD URL. Can be null or empty.
85      * @param attributes The list of allowed attributes. Can be null or empty.
86      * @param layoutAttributes The list of layout attributes. Can be null or empty.
87      * @param children The list of allowed children. Can be null or empty.
88      * @param mandatory Whether this node must always exist (even for empty models). A mandatory
89      *  UI node is never deleted and it may lack an actual XML node attached. A non-mandatory
90      *  UI node MUST have an XML node attached and it will cease to exist when the XML node
91      *  ceases to exist.
92      */
ViewElementDescriptor(String xml_name, String ui_name, String fullClassName, String tooltip, String sdk_url, AttributeDescriptor[] attributes, AttributeDescriptor[] layoutAttributes, ElementDescriptor[] children, boolean mandatory)93     public ViewElementDescriptor(String xml_name, String ui_name,
94             String fullClassName,
95             String tooltip, String sdk_url,
96             AttributeDescriptor[] attributes, AttributeDescriptor[] layoutAttributes,
97             ElementDescriptor[] children, boolean mandatory) {
98         super(xml_name, ui_name, tooltip, sdk_url, attributes, children, mandatory);
99         mFullClassName = fullClassName;
100         mLayoutAttributes = layoutAttributes != null ? layoutAttributes : new AttributeDescriptor[0];
101     }
102 
103     /**
104      * Constructs a new {@link ElementDescriptor} based on its XML name and on the canonical
105      * name of the class it represents.
106      * The UI name is build by capitalizing the XML name.
107      * The UI nodes will be non-mandatory.
108      *
109      * @param xml_name The XML element node name. Case sensitive.
110      * @param fullClassName The fully qualified class name the {@link ViewElementDescriptor} is
111      * representing.
112      */
ViewElementDescriptor(String xml_name, String fullClassName)113     public ViewElementDescriptor(String xml_name, String fullClassName) {
114         super(xml_name);
115         mFullClassName = fullClassName;
116         mLayoutAttributes = null;
117     }
118 
119     /**
120      * Returns the fully qualified name of the View class represented by this element descriptor
121      * e.g. "android.view.View".
122      *
123      * @return the fully qualified class name, never null
124      */
getFullClassName()125     public String getFullClassName() {
126         return mFullClassName;
127     }
128 
129     /** Returns the list of layout attributes. Can be empty but not null.
130      *
131      * @return the list of layout attributes, never null
132      */
getLayoutAttributes()133     public AttributeDescriptor[] getLayoutAttributes() {
134         return mLayoutAttributes;
135     }
136 
137     /**
138      * Sets the list of layout attribute attributes.
139      *
140      * @param attributes the new layout attributes, not null
141      */
setLayoutAttributes(AttributeDescriptor[] attributes)142     public void setLayoutAttributes(AttributeDescriptor[] attributes) {
143         assert attributes != null;
144         mLayoutAttributes = attributes;
145     }
146 
147     /**
148      * Returns a new {@link UiViewElementNode} linked to this descriptor.
149      */
150     @Override
createUiNode()151     public UiElementNode createUiNode() {
152         return new UiViewElementNode(this);
153     }
154 
155     /**
156      * Returns the {@link ViewElementDescriptor} of the super-class of this View descriptor
157      * that matches the java View hierarchy. Can be null.
158      *
159      * @return the super class' descriptor or null
160      */
getSuperClassDesc()161     public ViewElementDescriptor getSuperClassDesc() {
162         return mSuperClassDesc;
163     }
164 
165     /**
166      * Sets the {@link ViewElementDescriptor} of the super-class of this View descriptor
167      * that matches the java View hierarchy. Can be null.
168      *
169      * @param superClassDesc the descriptor for the super class, or null
170      */
setSuperClass(ViewElementDescriptor superClassDesc)171     public void setSuperClass(ViewElementDescriptor superClassDesc) {
172         mSuperClassDesc = superClassDesc;
173     }
174 
175     /**
176      * Returns an optional icon for the element.
177      * <p/>
178      * By default this tries to return an icon based on the XML name of the element.
179      * If this fails, it tries to return the default element icon as defined in the
180      * plugin. If all fails, it returns null.
181      *
182      * @return An icon for this element or null.
183      */
184     @Override
getGenericIcon()185     public Image getGenericIcon() {
186         IconFactory factory = IconFactory.getInstance();
187         String name = mXmlName;
188         if (name.indexOf('.') != -1) {
189             // If the user uses a fully qualified name, such as
190             // "android.gesture.GestureOverlayView" in their XML, we need to look up
191             // only by basename
192             name = name.substring(name.lastIndexOf('.') + 1);
193         } else if (VIEW_TAG.equals(name)) {
194             // Can't have both view.png and View.png; issues on case sensitive vs
195             // case insensitive file systems
196             name = VIEW;
197         }
198 
199         Image icon = factory.getIcon(name);
200         if (icon == null) {
201             icon = AdtPlugin.getAndroidLogo();
202         }
203 
204         return icon;
205     }
206 
207     /**
208      * Returns the list of attribute sources for the attributes provided by this
209      * descriptor. An attribute source is the fully qualified class name of the
210      * defining class for some of the properties. The specific attribute source
211      * of a given {@link AttributeInfo} can be found by calling
212      * {@link AttributeInfo#getDefinedBy()}.
213      * <p>
214      * The attribute sources are ordered from class to super class.
215      * <p>
216      * The list may <b>not</b> be modified by clients.
217      *
218      * @return a non null list of attribute sources for this view
219      */
getAttributeSources()220     public List<String> getAttributeSources() {
221         return mAttributeSources != null ? mAttributeSources : Collections.<String>emptyList();
222     }
223 
224     /**
225      * Sets the attribute sources for this view. See {@link #getAttributes()}
226      * for details.
227      *
228      * @param attributeSources a non null list of attribute sources for this
229      *            view descriptor
230      * @see #getAttributeSources()
231      */
setAttributeSources(List<String> attributeSources)232     public void setAttributeSources(List<String> attributeSources) {
233         mAttributeSources = attributeSources;
234     }
235 
236     /**
237      * Returns true if views with the given fully qualified class name need to include
238      * their package in the layout XML tag
239      *
240      * @param fqcn the fully qualified class name, such as android.widget.Button
241      * @return true if the full package path should be included in the layout XML element
242      *         tag
243      */
viewNeedsPackage(String fqcn)244     public static boolean viewNeedsPackage(String fqcn) {
245         return !(fqcn.startsWith(ANDROID_WIDGET_PREFIX)
246               || fqcn.startsWith(ANDROID_VIEW_PKG)
247               || fqcn.startsWith(ANDROID_WEBKIT_PKG));
248     }
249 }
250