/* * Copyright (C) 2009 The Android Open Source Project * * Licensed under the Eclipse Public License, Version 1.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.eclipse.org/org/documents/epl-v10.php * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.ide.common.api; import com.android.annotations.NonNull; import com.android.annotations.Nullable; import com.android.ide.common.api.IDragElement.IDragAttribute; import com.google.common.annotations.Beta; import java.util.List; /** * Represents a view in the XML layout being edited. * Each view or layout maps to exactly one XML node, thus the name. * <p/> * The primordial characteristic of a node is the fully qualified View class name that * it represents (a.k.a FQCN), for example "android.view.View" or "android.widget.Button". * <p/> * There are 2 kind of nodes: * - Nodes matching a view actually rendered in the layout canvas have a valid "bounds" * rectangle that describe their position in pixels in the canvas. <br/> * - Nodes created by IViewRule scripts but not yet rendered have an invalid bounds rectangle * since they only exist in the uncommitted XML model and not yet in the rendered View model. * <p> * <b>NOTE: This is not a public or final API; if you rely on this be prepared * to adjust your code for the next tools release.</b> * </p> */ @Beta public interface INode { /** * Returns the FQCN of the view class represented by this node. */ @NonNull String getFqcn(); /** * Returns the bounds of this node. * <p/> * The bounds are valid when this node maps a view that is already rendered. * Typically, if the node is the target of a drag & drop operation then you can be * guaranteed that its bounds are known and thus are valid. * <p/> * However the bounds are invalid (e.g. not known yet) for new XML elements * that have just been created, e.g. by the {@link #appendChild(String)} method. * * @return A non-null rectangle, in canvas coordinates. */ @NonNull Rect getBounds(); /** * Returns the margins for this node. * * @return the margins for this node, never null */ @NonNull Margins getMargins(); /** * Returns the baseline of this node, or -1 if it has no baseline. * The baseline is the distance from the top down to the baseline. * * @return the baseline, or -1 if not applicable */ int getBaseline(); // ---- Hierarchy handling ---- /** * Returns the root element of the view hierarchy. * <p/> * When a node is not attached to a hierarchy, it is its own root node. * This may return null if the {@link INode} was not created using a correct UiNode, * which is unlikely. */ @Nullable INode getRoot(); /** * Returns the parent node of this node, corresponding to the parent view in the layout. * The returned parent can be null when the node is the root element, or when the node is * not yet or no longer attached to the hierarchy. */ @Nullable INode getParent(); /** * Returns the list of valid children nodes. The list can be empty but not null. */ @NonNull INode[] getChildren(); // ---- XML Editing --- /** * Absolutely <em>all</em> calls that are going to edit the XML must be wrapped * by an editXml() call. This call creates both an undo context wrapper and an * edit-XML wrapper. * * @param undoName The UI name that will be given to the undo action. * @param callback The code to execute. */ void editXml(@NonNull String undoName, @NonNull INodeHandler callback); // TODO define an exception that methods below will throw if editXml() is not wrapping // these calls. /** * Creates a new XML element as a child of this node's XML element. * <p/> * For this to work, the editor must have a descriptor for the given FQCN. * <p/> * This call must be done in the context of editXml(). * * @param viewFqcn The FQCN of the element to create. The actual XML local name will * depend on whether this is an Android view or a custom project view. * @return The node for the newly created element. Can be null if we failed to create it. */ @NonNull INode appendChild(@NonNull String viewFqcn); /** * Creates a new XML element as a child of this node's XML element and inserts * it at the specified position in the children list. * <p/> * For this to work, the editor must have a descriptor for the given FQCN. * <p/> * This call must be done in the context of editXml(). * * @param viewFqcn The FQCN of the element to create. The actual XML local name will * depend on whether this is an Android view or a custom project view. * @param index Index of the child to insert before. If the index is out of bounds * (less than zero or larger that current last child), appends at the end. * @return The node for the newly created element. Can be null if we failed to create it. */ @NonNull INode insertChildAt(@NonNull String viewFqcn, int index); /** * Removes the given XML element child from this node's list of children. * <p/> * This call must be done in the context of editXml(). * * @param node The child to be deleted. */ void removeChild(@NonNull INode node); /** * Sets an attribute for the underlying XML element. * Attributes are not written immediately -- instead the XML editor batches edits and * then commits them all together at once later. * <p/> * Custom attributes will be created on the fly. * <p/> * Passing an empty value actually <em>removes</em> an attribute from the XML. * <p/> * This call must be done in the context of editXml(). * * @param uri The XML namespace URI of the attribute. * @param localName The XML <em>local</em> name of the attribute to set. * @param value It's value. Cannot be null. An empty value <em>removes</em> the attribute. * @return Whether the attribute was actually set or not. */ boolean setAttribute(@Nullable String uri, @NonNull String localName, @Nullable String value); /** * Returns a given XML attribute. * <p/> * This looks up an attribute in the <em>current</em> XML source, not the in-memory model. * That means that if called in the context of {@link #editXml(String, INodeHandler)}, the value * returned here is not affected by {@link #setAttribute(String, String, String)} until * the editXml closure is completed and the actual XML is updated. * * @param uri The XML name-space URI of the attribute. * @param attrName The <em>local</em> name of the attribute. * @return the attribute as a {@link String}, if it exists, or <code>null</code>. */ @Nullable String getStringAttr(@Nullable String uri, @NonNull String attrName); /** * Returns the {@link IAttributeInfo} for a given attribute. * <p/> * The information is useful to determine the format of an attribute (e.g. reference, string, * float, enum, flag, etc.) and in the case of enums and flags also gives the possible values. * <p/> * Note: in Android resources, an enum can only take one of the possible values (e.g. * "visibility" can be either "visible" or "none"), whereas a flag can accept one or more * value (e.g. "align" can be "center_vertical|center_horizontal".) * <p/> * Note that this method does not handle custom non-android attributes. It may either * return null for these or it may return a synthetic "string" format attribute depending * on how the attribute was loaded. * * @param uri The XML name-space URI of the attribute. * @param attrName The <em>local</em> name of the attribute. * @return the {@link IAttributeInfo} if the attribute is known, or <code>null</code>. */ @Nullable IAttributeInfo getAttributeInfo(@Nullable String uri, @NonNull String attrName); /** * Returns the list of all attributes declared by this node's descriptor. * <p/> * This returns a fixed list of all attributes known to the view or layout descriptor. * This list does not depend on whether the attributes are actually used in the * XML for this node. * <p/> * Note that for views, the list of attributes also includes the layout attributes * inherited from the parent view. This means callers must not cache this list based * solely on the type of the node, as its attribute list changes depending on the place * of the view in the view hierarchy. * <p/> * If you want attributes actually written in the XML and their values, please use * {@link #getStringAttr(String, String)} or {@link #getLiveAttributes()} instead. * * @return A non-null possibly-empty list of {@link IAttributeInfo}. */ @NonNull IAttributeInfo[] getDeclaredAttributes(); /** * Returns the list of classes (fully qualified class names) that are * contributing properties to the {@link #getDeclaredAttributes()} attribute * list, in order from most specific to least specific (in other words, * android.view.View will be last in the list.) This is usually the same as * the super class chain of a view, but it skips any views that do not * contribute attributes. * * @return a list of views classes that contribute attributes to this node, * which is never null because at least android.view.View will * contribute attributes. */ @NonNull List<String> getAttributeSources(); /** * Returns the list of all attributes defined in the XML for this node. * <p/> * This looks up an attribute in the <em>current</em> XML source, not the in-memory model. * That means that if called in the context of {@link #editXml(String, INodeHandler)}, the value * returned here is not affected by {@link #setAttribute(String, String, String)} until * the editXml closure is completed and the actual XML is updated. * <p/> * If you want a list of all possible attributes, whether used in the XML or not by * this node, please see {@link #getDeclaredAttributes()} instead. * * @return A non-null possibly-empty list of {@link IAttribute}. */ @NonNull IAttribute[] getLiveAttributes(); // ----------- /** * An XML attribute in an {@link INode} with a namespace URI, a name and its current value. * <p/> * The name cannot be empty. * The namespace URI can be empty for an attribute without a namespace but is never null. * The value can be empty but cannot be null. */ interface IAttribute extends IDragAttribute { } }