1 /* 2 * Copyright (C) 2009 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 18 package com.android.ide.common.api; 19 20 import com.android.annotations.NonNull; 21 import com.android.annotations.Nullable; 22 import com.android.ide.common.api.IDragElement.IDragAttribute; 23 import com.google.common.annotations.Beta; 24 25 import java.util.List; 26 27 28 /** 29 * Represents a view in the XML layout being edited. 30 * Each view or layout maps to exactly one XML node, thus the name. 31 * <p/> 32 * The primordial characteristic of a node is the fully qualified View class name that 33 * it represents (a.k.a FQCN), for example "android.view.View" or "android.widget.Button". 34 * <p/> 35 * There are 2 kind of nodes: 36 * - Nodes matching a view actually rendered in the layout canvas have a valid "bounds" 37 * rectangle that describe their position in pixels in the canvas. <br/> 38 * - Nodes created by IViewRule scripts but not yet rendered have an invalid bounds rectangle 39 * since they only exist in the uncommitted XML model and not yet in the rendered View model. 40 * <p> 41 * <b>NOTE: This is not a public or final API; if you rely on this be prepared 42 * to adjust your code for the next tools release.</b> 43 * </p> 44 */ 45 @Beta 46 public interface INode { 47 48 /** 49 * Returns the FQCN of the view class represented by this node. 50 */ 51 @NonNull getFqcn()52 String getFqcn(); 53 54 /** 55 * Returns the bounds of this node. 56 * <p/> 57 * The bounds are valid when this node maps a view that is already rendered. 58 * Typically, if the node is the target of a drag'n'drop operation then you can be 59 * guaranteed that its bounds are known and thus are valid. 60 * <p/> 61 * However the bounds are invalid (e.g. not known yet) for new XML elements 62 * that have just been created, e.g. by the {@link #appendChild(String)} method. 63 * 64 * @return A non-null rectangle, in canvas coordinates. 65 */ 66 @NonNull getBounds()67 Rect getBounds(); 68 69 /** 70 * Returns the margins for this node. 71 * 72 * @return the margins for this node, never null 73 */ 74 @NonNull getMargins()75 Margins getMargins(); 76 77 /** 78 * Returns the baseline of this node, or -1 if it has no baseline. 79 * The baseline is the distance from the top down to the baseline. 80 * 81 * @return the baseline, or -1 if not applicable 82 */ getBaseline()83 int getBaseline(); 84 85 // ---- Hierarchy handling ---- 86 87 /** 88 * Returns the root element of the view hierarchy. 89 * <p/> 90 * When a node is not attached to a hierarchy, it is its own root node. 91 * This may return null if the {@link INode} was not created using a correct UiNode, 92 * which is unlikely. 93 */ 94 @Nullable getRoot()95 INode getRoot(); 96 97 /** 98 * Returns the parent node of this node, corresponding to the parent view in the layout. 99 * The returned parent can be null when the node is the root element, or when the node is 100 * not yet or no longer attached to the hierarchy. 101 */ 102 @Nullable getParent()103 INode getParent(); 104 105 /** 106 * Returns the list of valid children nodes. The list can be empty but not null. 107 */ 108 @NonNull getChildren()109 INode[] getChildren(); 110 111 112 // ---- XML Editing --- 113 114 /** 115 * Absolutely <em>all</em> calls that are going to edit the XML must be wrapped 116 * by an editXml() call. This call creates both an undo context wrapper and an 117 * edit-XML wrapper. 118 * 119 * @param undoName The UI name that will be given to the undo action. 120 * @param callback The code to execute. 121 */ editXml(@onNull String undoName, @NonNull INodeHandler callback)122 void editXml(@NonNull String undoName, @NonNull INodeHandler callback); 123 124 // TODO define an exception that methods below will throw if editXml() is not wrapping 125 // these calls. 126 127 /** 128 * Creates a new XML element as a child of this node's XML element. 129 * <p/> 130 * For this to work, the editor must have a descriptor for the given FQCN. 131 * <p/> 132 * This call must be done in the context of editXml(). 133 * 134 * @param viewFqcn The FQCN of the element to create. The actual XML local name will 135 * depend on whether this is an Android view or a custom project view. 136 * @return The node for the newly created element. Can be null if we failed to create it. 137 */ 138 @NonNull appendChild(@onNull String viewFqcn)139 INode appendChild(@NonNull String viewFqcn); 140 141 /** 142 * Creates a new XML element as a child of this node's XML element and inserts 143 * it at the specified position in the children list. 144 * <p/> 145 * For this to work, the editor must have a descriptor for the given FQCN. 146 * <p/> 147 * This call must be done in the context of editXml(). 148 * 149 * @param viewFqcn The FQCN of the element to create. The actual XML local name will 150 * depend on whether this is an Android view or a custom project view. 151 * @param index Index of the child to insert before. If the index is out of bounds 152 * (less than zero or larger that current last child), appends at the end. 153 * @return The node for the newly created element. Can be null if we failed to create it. 154 */ 155 @NonNull insertChildAt(@onNull String viewFqcn, int index)156 INode insertChildAt(@NonNull String viewFqcn, int index); 157 158 /** 159 * Removes the given XML element child from this node's list of children. 160 * <p/> 161 * This call must be done in the context of editXml(). 162 * 163 * @param node The child to be deleted. 164 */ removeChild(@onNull INode node)165 void removeChild(@NonNull INode node); 166 167 /** 168 * Sets an attribute for the underlying XML element. 169 * Attributes are not written immediately -- instead the XML editor batches edits and 170 * then commits them all together at once later. 171 * <p/> 172 * Custom attributes will be created on the fly. 173 * <p/> 174 * Passing an empty value actually <em>removes</em> an attribute from the XML. 175 * <p/> 176 * This call must be done in the context of editXml(). 177 * 178 * @param uri The XML namespace URI of the attribute. 179 * @param localName The XML <em>local</em> name of the attribute to set. 180 * @param value It's value. Cannot be null. An empty value <em>removes</em> the attribute. 181 * @return Whether the attribute was actually set or not. 182 */ setAttribute(@ullable String uri, @NonNull String localName, @Nullable String value)183 boolean setAttribute(@Nullable String uri, @NonNull String localName, @Nullable String value); 184 185 /** 186 * Returns a given XML attribute. 187 * <p/> 188 * This looks up an attribute in the <em>current</em> XML source, not the in-memory model. 189 * That means that if called in the context of {@link #editXml(String, INodeHandler)}, the value 190 * returned here is not affected by {@link #setAttribute(String, String, String)} until 191 * the editXml closure is completed and the actual XML is updated. 192 * 193 * @param uri The XML name-space URI of the attribute. 194 * @param attrName The <em>local</em> name of the attribute. 195 * @return the attribute as a {@link String}, if it exists, or <code>null</code>. 196 */ 197 @Nullable getStringAttr(@ullable String uri, @NonNull String attrName)198 String getStringAttr(@Nullable String uri, @NonNull String attrName); 199 200 /** 201 * Returns the {@link IAttributeInfo} for a given attribute. 202 * <p/> 203 * The information is useful to determine the format of an attribute (e.g. reference, string, 204 * float, enum, flag, etc.) and in the case of enums and flags also gives the possible values. 205 * <p/> 206 * Note: in Android resources, an enum can only take one of the possible values (e.g. 207 * "visibility" can be either "visible" or "none"), whereas a flag can accept one or more 208 * value (e.g. "align" can be "center_vertical|center_horizontal".) 209 * <p/> 210 * Note that this method does not handle custom non-android attributes. It may either 211 * return null for these or it may return a synthetic "string" format attribute depending 212 * on how the attribute was loaded. 213 * 214 * @param uri The XML name-space URI of the attribute. 215 * @param attrName The <em>local</em> name of the attribute. 216 * @return the {@link IAttributeInfo} if the attribute is known, or <code>null</code>. 217 */ 218 @Nullable getAttributeInfo(@ullable String uri, @NonNull String attrName)219 public IAttributeInfo getAttributeInfo(@Nullable String uri, @NonNull String attrName); 220 221 /** 222 * Returns the list of all attributes declared by this node's descriptor. 223 * <p/> 224 * This returns a fixed list of all attributes known to the view or layout descriptor. 225 * This list does not depend on whether the attributes are actually used in the 226 * XML for this node. 227 * <p/> 228 * Note that for views, the list of attributes also includes the layout attributes 229 * inherited from the parent view. This means callers must not cache this list based 230 * solely on the type of the node, as its attribute list changes depending on the place 231 * of the view in the view hierarchy. 232 * <p/> 233 * If you want attributes actually written in the XML and their values, please use 234 * {@link #getStringAttr(String, String)} or {@link #getLiveAttributes()} instead. 235 * 236 * @return A non-null possibly-empty list of {@link IAttributeInfo}. 237 */ 238 @NonNull getDeclaredAttributes()239 public IAttributeInfo[] getDeclaredAttributes(); 240 241 /** 242 * Returns the list of classes (fully qualified class names) that are 243 * contributing properties to the {@link #getDeclaredAttributes()} attribute 244 * list, in order from most specific to least specific (in other words, 245 * android.view.View will be last in the list.) This is usually the same as 246 * the super class chain of a view, but it skips any views that do not 247 * contribute attributes. 248 * 249 * @return a list of views classes that contribute attributes to this node, 250 * which is never null because at least android.view.View will 251 * contribute attributes. 252 */ 253 @NonNull getAttributeSources()254 public List<String> getAttributeSources(); 255 256 /** 257 * Returns the list of all attributes defined in the XML for this node. 258 * <p/> 259 * This looks up an attribute in the <em>current</em> XML source, not the in-memory model. 260 * That means that if called in the context of {@link #editXml(String, INodeHandler)}, the value 261 * returned here is not affected by {@link #setAttribute(String, String, String)} until 262 * the editXml closure is completed and the actual XML is updated. 263 * <p/> 264 * If you want a list of all possible attributes, whether used in the XML or not by 265 * this node, please see {@link #getDeclaredAttributes()} instead. 266 * 267 * @return A non-null possibly-empty list of {@link IAttribute}. 268 */ 269 @NonNull getLiveAttributes()270 public IAttribute[] getLiveAttributes(); 271 272 // ----------- 273 274 /** 275 * An XML attribute in an {@link INode} with a namespace URI, a name and its current value. 276 * <p/> 277 * The name cannot be empty. 278 * The namespace URI can be empty for an attribute without a namespace but is never null. 279 * The value can be empty but cannot be null. 280 */ 281 public static interface IAttribute extends IDragAttribute { } 282 } 283