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