Home | History | Annotate | Download | only in descriptors
      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      */
     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      */
    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      */
    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      */
    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      */
    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
    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      */
    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      */
    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
    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      */
    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      */
    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      */
    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