blob: 213706ceeab452bb33b853d930619b01b0c0c568 [file] [log] [blame]
/*
* 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 &amp; 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 { }
}