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