INode.java revision 5d7dc30638953195ed55d32bc9dc37102a613ff8
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.annotations.NonNull;
21import com.android.annotations.Nullable;
22import com.android.ide.common.api.IDragElement.IDragAttribute;
23import com.google.common.annotations.Beta;
24
25import 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
46public interface INode {
47
48    /**
49     * Returns the FQCN of the view class represented by this node.
50     */
51    @NonNull
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
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
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     */
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
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
103    INode getParent();
104
105    /**
106     * Returns the list of valid children nodes. The list can be empty but not null.
107     */
108    @NonNull
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     */
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
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
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     */
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     */
183    boolean setAttribute(@Nullable String uri, @NonNull String localName, @NonNull 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
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
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
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
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
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