Methods Summary |
---|
public void | addUpdateListener(IUiUpdateListener listener)Adds a new {@link IUiUpdateListener} to the internal update listener list.
if (mUiUpdateListeners == null) {
mUiUpdateListeners = new ArrayList<IUiUpdateListener>();
}
if (!mUiUpdateListeners.contains(listener)) {
mUiUpdateListeners.add(listener);
}
|
public com.android.ide.eclipse.editors.uimodel.UiElementNode | appendNewUiChild(com.android.ide.eclipse.editors.descriptors.ElementDescriptor descriptor)Creates a new {@link UiElementNode} from the given {@link ElementDescriptor}
and appends it to the end of the element children list.
UiElementNode ui_node;
ui_node = descriptor.createUiNode();
mUiChildren.add(ui_node);
ui_node.setUiParent(this);
ui_node.invokeUiUpdateListeners(UiUpdateState.CREATED);
return ui_node;
|
private void | clearAttributes()Clears the internal list of attributes, the read-only cached version of it
and the read-only cached hidden attribute list.
mUiAttributes = null;
mReadOnlyUiAttributes = null;
mCachedHiddenAttributes = null;
mUnknownUiAttributes = new HashSet<UiAttributeNode>();
|
void | clearContent()Clears the {@link UiElementNode} by resetting the children list and
the {@link UiAttributeNode}s list.
Also resets the attached XML node, document, editor if any.
The parent {@link UiElementNode} node is not reset so that it's position
in the hierarchy be left intact, if any.
mXmlNode = null;
mXmlDocument = null;
mEditor = null;
clearAttributes();
mReadOnlyUiChildren = null;
if (mUiChildren == null) {
mUiChildren = new ArrayList<UiElementNode>();
} else {
// We can't remove mandatory nodes, we just clear them.
for (int i = mUiChildren.size() - 1; i >= 0; --i) {
removeUiChildAtIndex(i);
}
}
|
public void | commit()Commits the attributes (all internal, inherited from UI parent & unknown attributes).
This is called by the UI when the embedding part needs to be committed.
for (UiAttributeNode ui_attr : getInternalUiAttributes().values()) {
ui_attr.commit();
}
for (UiAttributeNode ui_attr : mUnknownUiAttributes) {
ui_attr.commit();
}
|
public boolean | commitAttributeToXml(UiAttributeNode uiAttr, java.lang.String newValue)Helper method to commit a single attribute value to XML.
This method updates the XML regardless of the current XML value.
Callers should check first if an update is needed.
If the new value is empty, the XML attribute will be actually removed.
Note that the caller MUST ensure that modifying the underlying XML model is
safe and must take care of marking the model as dirty if necessary.
// Get (or create) the underlying XML element node that contains the attributes.
Node element = prepareCommit();
if (element != null && uiAttr != null) {
String attrLocalName = uiAttr.getDescriptor().getXmlLocalName();
String attrNsUri = uiAttr.getDescriptor().getNamespaceUri();
NamedNodeMap attrMap = element.getAttributes();
if (newValue == null || newValue.length() == 0) {
// Remove attribute if it's empty
if (attrMap.getNamedItemNS(attrNsUri, attrLocalName) != null) {
attrMap.removeNamedItemNS(attrNsUri, attrLocalName);
return true;
}
} else {
// Add or replace an attribute
Document doc = element.getOwnerDocument();
if (doc != null) {
Attr attr = doc.createAttributeNS(attrNsUri, attrLocalName);
attr.setValue(newValue);
attr.setPrefix(lookupNamespacePrefix(element, attrNsUri));
attrMap.setNamedItemNS(attr);
return true;
}
}
}
return false;
|
public boolean | commitDirtyAttributesToXml()Helper method to commit all dirty attributes values to XML.
This method is useful if {@link #setAttributeValue(String, String, boolean)} has been
called more than once and all the attributes marked as dirty must be commited to the
XML. It calls {@link #commitAttributeToXml(UiAttributeNode, String)} on each dirty
attribute.
Note that the caller MUST ensure that modifying the underlying XML model is
safe and must take care of marking the model as dirty if necessary.
boolean result = false;
HashMap<AttributeDescriptor, UiAttributeNode> attributeMap = getInternalUiAttributes();
for (Entry<AttributeDescriptor, UiAttributeNode> entry : attributeMap.entrySet()) {
UiAttributeNode ui_attr = entry.getValue();
if (ui_attr.isDirty()) {
result |= commitAttributeToXml(ui_attr, ui_attr.getCurrentValue());
ui_attr.setDirty(false);
}
}
return result;
|
public org.w3c.dom.Node | createXmlNode()Creates the underlying XML element node for this UI node if it doesn't already
exists.
if (mXmlNode != null) {
return null;
}
Node parentXmlNode = null;
if (mUiParent != null) {
parentXmlNode = mUiParent.prepareCommit();
if (parentXmlNode == null) {
// The parent failed to create its own backing XML node. Abort.
// No need to throw an exception, the parent will most likely
// have done so itself.
return null;
}
}
String element_name = getDescriptor().getXmlName();
Document doc = getXmlDocument();
// We *must* have a root node. If not, we need to abort.
if (doc == null) {
throw new RuntimeException(
String.format("Missing XML document for %1$s XML node.", element_name));
}
// If we get here and parent_xml_node is null, the node is to be created
// as the root node of the document (which can't be null, cf check above).
if (parentXmlNode == null) {
parentXmlNode = doc;
}
mXmlNode = doc.createElement(element_name);
Node xmlNextSibling = null;
UiElementNode uiNextSibling = getUiNextSibling();
if (uiNextSibling != null) {
xmlNextSibling = uiNextSibling.getXmlNode();
}
parentXmlNode.insertBefore(mXmlNode, xmlNextSibling);
// Insert a separator after the tag, to make it easier to read
Text sep = doc.createTextNode("\n");
parentXmlNode.appendChild(sep);
// Set all initial attributes in the XML node if they are not empty.
// Iterate on the descriptor list to get the desired order and then use the
// internal values, if any.
for (AttributeDescriptor attr_desc : getAttributeDescriptors()) {
if (attr_desc instanceof XmlnsAttributeDescriptor) {
XmlnsAttributeDescriptor desc = (XmlnsAttributeDescriptor) attr_desc;
Attr attr = doc.createAttributeNS(XmlnsAttributeDescriptor.XMLNS_URI,
desc.getXmlNsName());
attr.setValue(desc.getValue());
attr.setPrefix(desc.getXmlNsPrefix());
mXmlNode.getAttributes().setNamedItemNS(attr);
} else {
UiAttributeNode ui_attr = getInternalUiAttributes().get(attr_desc);
commitAttributeToXml(ui_attr, ui_attr.getCurrentValue());
}
}
invokeUiUpdateListeners(UiUpdateState.CREATED);
return mXmlNode;
|
public org.w3c.dom.Node | deleteXmlNode()Removes the XML node corresponding to this UI node if it exists
and also removes all mirrored information in this UI node (i.e. children, attributes)
if (mXmlNode == null) {
return null;
}
// First clear the internals of the node and *then* actually deletes the XML
// node (because doing so will generate an update even and this node may be
// revisited via loadFromXmlNode).
Node old_xml_node = mXmlNode;
clearContent();
Node xml_parent = old_xml_node.getParentNode();
if (xml_parent == null) {
xml_parent = getXmlDocument();
}
old_xml_node = xml_parent.removeChild(old_xml_node);
invokeUiUpdateListeners(UiUpdateState.DELETED);
return old_xml_node;
|
public UiAttributeNode | findUiAttribute(com.android.ide.eclipse.editors.descriptors.AttributeDescriptor attr_desc)Returns the {@link UiAttributeNode} matching this attribute descriptor or
null if not found.
return getInternalUiAttributes().get(attr_desc);
|
public com.android.ide.eclipse.editors.uimodel.UiElementNode | findUiChildNode(java.lang.String path)Finds a child node relative to this node using a path-like expression.
F.ex. "node1/node2" would find a child "node1" that contains a child "node2" and
returns the latter. If there are multiple nodes with the same name at the same
level, always uses the first one found.
String[] items = path.split("/"); //$NON-NLS-1$
UiElementNode ui_node = this;
for (String item : items) {
boolean next_segment = false;
for (UiElementNode c : ui_node.mUiChildren) {
if (c.getDescriptor().getXmlName().equals(item)) {
ui_node = c;
next_segment = true;
break;
}
}
if (!next_segment) {
return null;
}
}
return ui_node;
|
public com.android.ide.eclipse.editors.uimodel.UiElementNode | findXmlNode(org.w3c.dom.Node xmlNode)Finds an {@link UiElementNode} which contains the give XML {@link Node}.
Looks recursively in all children UI nodes.
if (xmlNode == null) {
return null;
}
if (getXmlNode() == xmlNode) {
return this;
}
for (UiElementNode uiChild : mUiChildren) {
UiElementNode found = uiChild.findXmlNode(xmlNode);
if (found != null) {
return found;
}
}
return null;
|
public com.android.ide.eclipse.adt.sdk.AndroidTargetData | getAndroidTarget()Returns the Android target data for the file being edited.
return getEditor().getTargetData();
|
public com.android.ide.eclipse.editors.descriptors.AttributeDescriptor[] | getAttributeDescriptors()Returns the {@link AttributeDescriptor} array for the descriptor of this node.
Use this instead of getDescriptor().getAttributes() -- derived classes can override
this to manipulate the attribute descriptor list depending on the current UI node.
return mDescriptor.getAttributes();
|
public java.lang.String | getAttributeValue(java.lang.String attrXmlName)Utility method to retrieve the internal value of an attribute.
Note that this retrieves the *field* value if the attribute has some UI, and
not the actual XML value. They may differ if the attribute is dirty.
HashMap<AttributeDescriptor, UiAttributeNode> attributeMap = getInternalUiAttributes();
for (Entry<AttributeDescriptor, UiAttributeNode> entry : attributeMap.entrySet()) {
AttributeDescriptor ui_desc = entry.getKey();
if (ui_desc.getXmlLocalName().equals(attrXmlName)) {
UiAttributeNode ui_attr = entry.getValue();
return ui_attr.getCurrentValue();
}
}
return null;
|
public java.lang.String | getBreadcrumbTrailDescription(boolean include_root)Computes a "breadcrumb trail" description for this node.
It will look something like "Manifest > Application > .myactivity (Activity) > Intent-Filter"
StringBuilder sb = new StringBuilder(getShortDescription());
for (UiElementNode ui_node = getUiParent();
ui_node != null;
ui_node = ui_node.getUiParent()) {
if (!include_root && ui_node.getUiParent() == null) {
break;
}
sb.insert(0, String.format("%1$s > ", ui_node.getShortDescription())); //$NON-NLS-1$
}
return sb.toString();
|
public com.android.ide.eclipse.editors.descriptors.ElementDescriptor | getDescriptor()Returns the {@link ElementDescriptor} for this node. This is never null.
Do not use this to call getDescriptor().getAttributes(), instead call
getAttributeDescriptors() which can be overriden by derived classes.
return mDescriptor;
|
public java.lang.Object | getEditData()Returns the temporary data used by the editors for this object.
return mEditData;
|
public java.lang.Object | getEditableValue()
return null;
|
public com.android.ide.eclipse.editors.AndroidEditor | getEditor()Returns the {@link AndroidEditor} that embeds this {@link UiElementNode}.
The value is initially null until the node is attached to its parent -- the value
of the root node is then propagated.
return mUiParent == null ? mEditor : mUiParent.getEditor();
|
private java.util.Map | getHiddenAttributeDescriptors()Returns the hidden {@link AttributeDescriptor} array for the descriptor of this node.
This is a subset of the getAttributeDescriptors() list.
Use this instead of getDescriptor().getHiddenAttributes() -- potentially derived classes
could override this to manipulate the attribute descriptor list depending on the current
UI node. There's no need for it right now so keep it private.
if (mCachedHiddenAttributes == null) {
mCachedHiddenAttributes = new HashMap<String, AttributeDescriptor>();
for (AttributeDescriptor attr_desc : getAttributeDescriptors()) {
if (attr_desc instanceof XmlnsAttributeDescriptor) {
mCachedHiddenAttributes.put(
((XmlnsAttributeDescriptor) attr_desc).getXmlNsName(),
attr_desc);
}
}
}
return mCachedHiddenAttributes;
|
private java.util.HashMap | getInternalUiAttributes()Gets or creates the internal UiAttributes list.
When the descriptor derives from ViewElementDescriptor, this list depends on the
current UiParent node.
if (mUiAttributes == null) {
AttributeDescriptor[] attr_list = getAttributeDescriptors();
mUiAttributes = new HashMap<AttributeDescriptor, UiAttributeNode>(attr_list.length);
for (AttributeDescriptor desc : attr_list) {
UiAttributeNode ui_node = desc.createUiNode(this);
if (ui_node != null) { // Some AttributeDescriptors do not have UI associated
mUiAttributes.put(desc, ui_node);
}
}
}
return mUiAttributes;
|
public org.eclipse.ui.views.properties.IPropertyDescriptor[] | getPropertyDescriptors()
List<IPropertyDescriptor> propDescs = new ArrayList<IPropertyDescriptor>();
// get the standard descriptors
HashMap<AttributeDescriptor, UiAttributeNode> attributeMap = getInternalUiAttributes();
Set<AttributeDescriptor> keys = attributeMap.keySet();
// we only want the descriptor that do implement the IPropertyDescriptor interface.
for (AttributeDescriptor key : keys) {
if (key instanceof IPropertyDescriptor) {
propDescs.add((IPropertyDescriptor)key);
}
}
// now get the descriptor from the unknown attributes
for (UiAttributeNode unknownNode : mUnknownUiAttributes) {
if (unknownNode.getDescriptor() instanceof IPropertyDescriptor) {
propDescs.add((IPropertyDescriptor)unknownNode.getDescriptor());
}
}
// TODO cache this maybe, as it's not going to change (except for unknown descriptors)
return propDescs.toArray(new IPropertyDescriptor[propDescs.size()]);
|
public java.lang.Object | getPropertyValue(java.lang.Object id)
HashMap<AttributeDescriptor, UiAttributeNode> attributeMap = getInternalUiAttributes();
UiAttributeNode attribute = attributeMap.get(id);
if (attribute == null) {
// look for the id in the unknown attributes.
for (UiAttributeNode unknownAttr : mUnknownUiAttributes) {
if (id == unknownAttr.getDescriptor()) {
return unknownAttr;
}
}
}
return attribute;
|
public java.lang.String | getShortDescription()Computes a short string describing the UI node suitable for tree views.
Uses the element's attribute "android:name" if present, or the "android:label" one
followed by the element's name.
if (mXmlNode != null && mXmlNode instanceof Element && mXmlNode.hasAttributes()) {
// Application and Manifest nodes have a special treatment: they are unique nodes
// so we don't bother trying to differentiate their strings and we fall back to
// just using the UI name below.
Element elem = (Element) mXmlNode;
String attr = elem.getAttributeNS(SdkConstants.NS_RESOURCES,
AndroidManifestDescriptors.ANDROID_NAME_ATTR);
if (attr == null || attr.length() == 0) {
attr = elem.getAttributeNS(SdkConstants.NS_RESOURCES,
AndroidManifestDescriptors.ANDROID_LABEL_ATTR);
}
if (attr == null || attr.length() == 0) {
attr = elem.getAttributeNS(SdkConstants.NS_RESOURCES,
XmlDescriptors.PREF_KEY_ATTR);
}
if (attr == null || attr.length() == 0) {
attr = elem.getAttribute(ResourcesDescriptors.NAME_ATTR);
}
if (attr == null || attr.length() == 0) {
attr = elem.getAttributeNS(SdkConstants.NS_RESOURCES,
LayoutDescriptors.ID_ATTR);
if (attr != null && attr.length() > 0) {
for (String prefix : ID_PREFIXES) {
if (attr.startsWith(prefix)) {
attr = attr.substring(prefix.length());
break;
}
}
}
}
if (attr != null && attr.length() > 0) {
return String.format("%1$s (%2$s)", attr, mDescriptor.getUiName());
}
}
return String.format("%1$s", mDescriptor.getUiName());
|
public java.util.Collection | getUiAttributes()
if (mReadOnlyUiAttributes == null) {
mReadOnlyUiAttributes = Collections.unmodifiableCollection(
getInternalUiAttributes().values());
}
return mReadOnlyUiAttributes;
|
public java.util.List | getUiChildren()
if (mReadOnlyUiChildren == null) {
mReadOnlyUiChildren = Collections.unmodifiableList(mUiChildren);
}
return mReadOnlyUiChildren;
|
public com.android.ide.eclipse.editors.uimodel.UiElementNode | getUiNextSibling()Returns the next UI sibling of this UI node.
If the node does not have a next sibling, returns null.
if (mUiParent != null) {
List<UiElementNode> childlist = mUiParent.getUiChildren();
if (childlist != null) {
int size = childlist.size();
if (size > 1 && childlist.get(size - 1) != this) {
int index = childlist.indexOf(this);
return index >= 0 && index < size - 1 ? childlist.get(index + 1) : null;
}
}
}
return null;
|
public com.android.ide.eclipse.editors.uimodel.UiElementNode | getUiParent()
return mUiParent;
|
public com.android.ide.eclipse.editors.uimodel.UiElementNode | getUiPreviousSibling()Returns the previous UI sibling of this UI node.
If the node does not have a previous sibling, returns null.
if (mUiParent != null) {
List<UiElementNode> childlist = mUiParent.getUiChildren();
if (childlist != null && childlist.size() > 1 && childlist.get(0) != this) {
int index = childlist.indexOf(this);
return index > 0 ? childlist.get(index - 1) : null;
}
}
return null;
|
public com.android.ide.eclipse.editors.uimodel.UiElementNode | getUiRoot()Returns The root {@link UiElementNode}.
UiElementNode root = this;
while (root.mUiParent != null) {
root = root.mUiParent;
}
return root;
|
public java.util.Collection | getUnknownUiAttributes()
return Collections.unmodifiableCollection(mUnknownUiAttributes);
|
public org.w3c.dom.Document | getXmlDocument()Returns the XML {@link Document}.
The value is initially null until the UI node is attached to its UI parent -- the value
of the document is then propagated.
if (mXmlDocument != null) {
return mXmlDocument;
} else if (mUiParent != null) {
return mUiParent.getXmlDocument();
}
return null;
|
public org.w3c.dom.Node | getXmlNode()Returns the XML node associated with this UI node.
Some {@link ElementDescriptor} are declared as being "mandatory". This means the
corresponding UI node will exist even if there is no corresponding XML node. Such structure
is created and enforced by the parent of the tree, not the element themselves. However
such nodes will likely not have an XML node associated, so getXmlNode() can return null.
return mXmlNode;
|
public final boolean | hasError()Returns whether this node, its attributes, or one of the children nodes (and attributes)
has errors.
if (mHasError) {
return true;
}
// get the error value from the attributes.
Collection<UiAttributeNode> attributes = getInternalUiAttributes().values();
for (UiAttributeNode attribute : attributes) {
if (attribute.hasError()) {
return true;
}
}
// and now from the children.
for (UiElementNode child : mUiChildren) {
if (child.hasError()) {
return true;
}
}
return false;
|
public com.android.ide.eclipse.editors.uimodel.UiElementNode | insertNewUiChild(int index, com.android.ide.eclipse.editors.descriptors.ElementDescriptor descriptor)Creates a new {@link UiElementNode} from the given {@link ElementDescriptor}
and inserts it in the element children list at the specified position.
UiElementNode ui_node;
ui_node = descriptor.createUiNode();
mUiChildren.add(index, ui_node);
ui_node.setUiParent(this);
ui_node.invokeUiUpdateListeners(UiUpdateState.CREATED);
return ui_node;
|
protected void | invokeUiUpdateListeners(com.android.ide.eclipse.editors.uimodel.IUiUpdateListener.UiUpdateState state)Invoke all registered {@link IUiUpdateListener} listening on this UI updates for this node.
if (mUiUpdateListeners != null) {
for (IUiUpdateListener listener : mUiUpdateListeners) {
try {
listener.uiElementNodeUpdated(this, state);
} catch (Exception e) {
// prevent a crashing listener from crashing the whole invocation chain
AdtPlugin.log(e, "UIElement Listener failed: %s, state=%s", //$NON-NLS-1$
getBreadcrumbTrailDescription(true),
state.toString());
}
}
}
|
public boolean | isDirty()Returns true if the part has been modified with respect to the data
loaded from the model.
for (UiAttributeNode ui_attr : getInternalUiAttributes().values()) {
if (ui_attr.isDirty()) {
return true;
}
}
for (UiAttributeNode ui_attr : mUnknownUiAttributes) {
if (ui_attr.isDirty()) {
return true;
}
}
return false;
|
public boolean | isPropertySet(java.lang.Object id)
HashMap<AttributeDescriptor, UiAttributeNode> attributeMap = getInternalUiAttributes();
UiAttributeNode attribute = attributeMap.get(id);
if (attribute != null) {
return attribute.getCurrentValue().length() > 0;
}
// look for the id in the unknown attributes.
for (UiAttributeNode unknownAttr : mUnknownUiAttributes) {
if (id == unknownAttr.getDescriptor()) {
return unknownAttr.getCurrentValue().length() > 0;
}
}
return false;
|
public boolean | loadFromXmlNode(org.w3c.dom.Node xml_node)Populate this element node with all values from the given XML node.
This fails if the given XML node has a different element name -- it won't change the
type of this ui node.
This method can be both used for populating values the first time and updating values
after the XML model changed.
boolean structure_changed = (mXmlNode != xml_node);
mXmlNode = xml_node;
if (xml_node != null) {
updateAttributeList(xml_node);
structure_changed |= updateElementList(xml_node);
invokeUiUpdateListeners(structure_changed ? UiUpdateState.CHILDREN_CHANGED
: UiUpdateState.ATTR_UPDATED);
}
return structure_changed;
|
private java.lang.String | lookupNamespacePrefix(org.w3c.dom.Node node, java.lang.String nsUri)Returns the namespace prefix matching the requested namespace URI.
If no such declaration is found, returns the default "android" prefix.
// Note: Node.lookupPrefix is not implemented in wst/xml/core NodeImpl.java
// The following code emulates this simple call:
// String prefix = node.lookupPrefix(SdkConstants.NS_RESOURCES);
// if the requested URI is null, it denotes an attribute with no namespace.
if (nsUri == null) {
return null;
}
// per XML specification, the "xmlns" URI is reserved
if (XmlnsAttributeDescriptor.XMLNS_URI.equals(nsUri)) {
return "xmlns"; //$NON-NLS-1$
}
HashSet<String> visited = new HashSet<String>();
Document doc = node == null ? null : node.getOwnerDocument();
for (; node != null && node.getNodeType() == Node.ELEMENT_NODE;
node = node.getParentNode()) {
NamedNodeMap attrs = node.getAttributes();
for (int n = attrs.getLength() - 1; n >= 0; --n) {
Node attr = attrs.item(n);
if ("xmlns".equals(attr.getPrefix())) { //$NON-NLS-1$
String uri = attr.getNodeValue();
String nsPrefix = attr.getLocalName();
// Is this the URI we are looking for? If yes, we found its prefix.
if (nsUri.equals(uri)) {
return nsPrefix;
}
visited.add(nsPrefix);
}
}
}
// Use a sensible default prefix if we can't find one.
// We need to make sure the prefix is not one that was declared in the scope
// visited above. Use a default namespace prefix "android" for the Android resource
// NS and use "ns" for all other custom namespaces.
String prefix = SdkConstants.NS_RESOURCES.equals(nsUri) ? "android" : "ns"; //$NON-NLS-1$ //$NON-NLS-2$
String base = prefix;
for (int i = 1; visited.contains(prefix); i++) {
prefix = base + Integer.toString(i);
}
// Also create & define this prefix/URI in the XML document as an attribute in the
// first element of the document.
if (doc != null) {
node = doc.getFirstChild();
while (node != null && node.getNodeType() != Node.ELEMENT_NODE) {
node = node.getNextSibling();
}
if (node != null) {
Attr attr = doc.createAttributeNS(XmlnsAttributeDescriptor.XMLNS_URI, prefix);
attr.setValue(nsUri);
attr.setPrefix("xmlns"); //$NON-NLS-1$
node.getAttributes().setNamedItemNS(attr);
}
}
return prefix;
|
public org.w3c.dom.Node | prepareCommit()Called by attributes when they want to commit their value
to an XML node.
For mandatory nodes, this makes sure the underlying XML element node
exists in the model. If not, it is created and assigned as the underlying
XML node.
For non-mandatory nodes, simply return the underlying XML node, which
must always exists.
if (getDescriptor().isMandatory()) {
createXmlNode();
// The new XML node has been created.
// We don't need to refresh using loadFromXmlNode() since there are
// no attributes or elements that need to be loading into this node.
}
return getXmlNode();
|
public void | refreshUi()
invokeUiUpdateListeners(UiUpdateState.ATTR_UPDATED);
|
public void | reloadFromXmlNode(org.w3c.dom.Node xml_node)Clears the UI node and reload it from the given XML node.
This works by clearing all references to any previous XML or UI nodes and
then reloads the XML document from scratch. The editor reference is kept.
This is used in the special case where the ElementDescriptor structure has changed.
Rather than try to diff inflated UI nodes (as loadFromXmlNode does), we don't bother
and reload everything. This is not subtle and should be used very rarely.
// The editor needs to be preserved, it is not affected by an XML change.
AndroidEditor editor = getEditor();
clearContent();
setEditor(editor);
if (xml_node != null) {
setXmlDocument(xml_node.getOwnerDocument());
}
// This will reload all the XML and recreate the UI structure from scratch.
loadFromXmlNode(xml_node);
|
private boolean | removeUiChildAtIndex(int ui_index)Internal helper to remove an UI child node given by its index in the
internal child list.
Also invokes the update listener on the node to be deleted.
UiElementNode ui_node = mUiChildren.get(ui_index);
invokeUiUpdateListeners(UiUpdateState.DELETED);
if (ui_node.getDescriptor().isMandatory()) {
// We can't remove a mandatory node, we just clear its content.
// A mandatory node with no XML means it doesn't really exist, so it can't be
// deleted.
boolean xml_exists = (ui_node.getXmlNode() != null);
ui_node.clearContent();
return xml_exists;
} else {
mUiChildren.remove(ui_index);
return true;
}
|
public void | removeUpdateListener(IUiUpdateListener listener)Removes an existing {@link IUiUpdateListener} from the internal update listener list.
Does nothing if the list is empty or the listener is not registered.
if (mUiUpdateListeners != null) {
mUiUpdateListeners.remove(listener);
}
|
public void | resetPropertyValue(java.lang.Object id)
HashMap<AttributeDescriptor, UiAttributeNode> attributeMap = getInternalUiAttributes();
UiAttributeNode attribute = attributeMap.get(id);
if (attribute != null) {
// TODO: reset the value of the attribute
return;
}
// look for the id in the unknown attributes.
for (UiAttributeNode unknownAttr : mUnknownUiAttributes) {
if (id == unknownAttr.getDescriptor()) {
// TODO: reset the value of the attribute
return;
}
}
|
public UiAttributeNode | setAttributeValue(java.lang.String attrXmlName, java.lang.String value, boolean override)Utility method to internally set the value of a text attribute for the current
UiElementNode.
This method is a helper. It silently ignores the errors such as the requested
attribute not being present in the element or attribute not being settable.
It accepts inherited attributes (such as layout).
This does not commit to the XML model. It does mark the attribute node as dirty.
This is up to the caller.
HashMap<AttributeDescriptor, UiAttributeNode> attributeMap = getInternalUiAttributes();
if (value == null) {
value = ""; //$NON-NLS-1$ -- this removes an attribute
}
for (Entry<AttributeDescriptor, UiAttributeNode> entry : attributeMap.entrySet()) {
AttributeDescriptor ui_desc = entry.getKey();
if (ui_desc.getXmlLocalName().equals(attrXmlName)) {
UiAttributeNode ui_attr = entry.getValue();
// Not all attributes are editable, ignore those which are not
if (ui_attr instanceof IUiSettableAttributeNode) {
String current = ui_attr.getCurrentValue();
// Only update (and mark as dirty) if the attribute did not have any
// value or if the value was different.
if (override || current == null || !current.equals(value)) {
((IUiSettableAttributeNode) ui_attr).setCurrentValue(value);
// mark the attribute as dirty since their internal content
// as been modified, but not the underlying XML model
ui_attr.setDirty(true);
return ui_attr;
}
}
break;
}
}
return null;
|
public void | setEditData(java.lang.Object data)Sets the temporary data used by the editors.
mEditData = data;
|
public void | setEditor(com.android.ide.eclipse.editors.AndroidEditor editor)Sets the {@link AndroidEditor} handling this {@link UiElementNode} hierarchy.
The editor must always be set on the root node. This method takes care of that.
if (mUiParent == null) {
mEditor = editor;
} else {
mUiParent.setEditor(editor);
}
|
public final void | setHasError(boolean errorFlag)Sets the error flag value.
mHasError = errorFlag;
|
public void | setPropertyValue(java.lang.Object id, java.lang.Object value)
HashMap<AttributeDescriptor, UiAttributeNode> attributeMap = getInternalUiAttributes();
UiAttributeNode attribute = attributeMap.get(id);
if (attribute == null) {
// look for the id in the unknown attributes.
for (UiAttributeNode unknownAttr : mUnknownUiAttributes) {
if (id == unknownAttr.getDescriptor()) {
attribute = unknownAttr;
break;
}
}
}
if (attribute != null) {
// get the current value and compare it to the new value
String oldValue = attribute.getCurrentValue();
final String newValue = (String)value;
if (oldValue.equals(newValue)) {
return;
}
final UiAttributeNode fAttribute = attribute;
AndroidEditor editor = getEditor();
editor.editXmlModel(new Runnable() {
public void run() {
commitAttributeToXml(fAttribute, newValue);
}
});
}
|
protected void | setUiParent(com.android.ide.eclipse.editors.uimodel.UiElementNode parent)Sets the parent of this UiElementNode.
The root node has no parent.
mUiParent = parent;
// Invalidate the internal UiAttributes list, as it may depend on the actual UiParent.
clearAttributes();
|
public void | setXmlDocument(org.w3c.dom.Document xml_doc)Sets the XML {@link Document}.
The XML {@link Document} is initially null. The XML {@link Document} must be set only on the
UI root element node (this method takes care of that.)
if (mUiParent == null) {
mXmlDocument = xml_doc;
} else {
mUiParent.setXmlDocument(xml_doc);
}
|
protected void | setXmlNode(org.w3c.dom.Node xml_node)
mXmlNode = xml_node;
|
protected void | updateAttributeList(org.w3c.dom.Node xmlNode)Updates the {@link UiAttributeNode} list for this {@link UiElementNode}.
For a given {@link UiElementNode}, the attribute list always exists in
full and is totally independent of whether the XML model actually
has the corresponding attributes.
For each attribute declared in this {@link UiElementNode}, get
the corresponding XML attribute. It may not exist, in which case the
value will be null. We don't really know if a value has changed, so
the updateValue() is called on the UI sattribute in all cases.
NamedNodeMap xmlAttrMap = xmlNode.getAttributes();
HashSet<Node> visited = new HashSet<Node>();
// For all known (i.e. expected) UI attributes, find an existing XML attribute of
// same (uri, local name) and update the internal Ui attribute value.
for (UiAttributeNode uiAttr : getInternalUiAttributes().values()) {
AttributeDescriptor desc = uiAttr.getDescriptor();
if (!(desc instanceof SeparatorAttributeDescriptor)) {
Node xmlAttr = xmlAttrMap == null ? null :
xmlAttrMap.getNamedItemNS(desc.getNamespaceUri(), desc.getXmlLocalName());
uiAttr.updateValue(xmlAttr);
visited.add(xmlAttr);
}
}
// Clone the current list of unknown attributes. We'll then remove from this list when
// we still attributes which are still unknown. What will be left are the old unknown
// attributes that have been deleted in the current XML attribute list.
@SuppressWarnings("unchecked") //$NON-NLS-1$
HashSet<UiAttributeNode> deleted = (HashSet<UiAttributeNode>) mUnknownUiAttributes.clone();
// We need to ignore hidden attributes.
Map<String, AttributeDescriptor> hiddenAttrDesc = getHiddenAttributeDescriptors();
// Traverse the actual XML attribute list to find unknown attributes
if (xmlAttrMap != null) {
for (int i = 0; i < xmlAttrMap.getLength(); i++) {
Node xmlAttr = xmlAttrMap.item(i);
// Ignore attributes which have actual descriptors
if (visited.contains(xmlAttr)) {
continue;
}
String xmlFullName = xmlAttr.getNodeName();
// Ignore attributes which are hidden (based on the prefix:localName key)
if (hiddenAttrDesc.containsKey(xmlFullName)) {
continue;
}
String xmlAttrLocalName = xmlAttr.getLocalName();
String xmlNsUri = xmlAttr.getNamespaceURI();
UiAttributeNode uiAttr = null;
for (UiAttributeNode a : mUnknownUiAttributes) {
String aLocalName = a.getDescriptor().getXmlLocalName();
String aNsUri = a.getDescriptor().getNamespaceUri();
if (aLocalName.equals(xmlAttrLocalName) &&
(aNsUri == xmlNsUri || (aNsUri != null && aNsUri.equals(xmlNsUri)))) {
// This attribute is still present in the unknown list
uiAttr = a;
// It has not been deleted
deleted.remove(a);
break;
}
}
if (uiAttr == null) {
// Create a new unknown attribute
TextAttributeDescriptor desc = new TextAttributeDescriptor(
xmlAttrLocalName, // xml name
xmlFullName, // ui name
xmlNsUri, // NS uri
"Unknown XML attribute"); // tooltip, translatable
uiAttr = desc.createUiNode(this);
mUnknownUiAttributes.add(uiAttr);
}
uiAttr.updateValue(xmlAttr);
}
// Remove from the internal list unknown attributes that have been deleted from the xml
for (UiAttributeNode a : deleted) {
mUnknownUiAttributes.remove(a);
}
}
|
protected boolean | updateElementList(org.w3c.dom.Node xml_node)Updates the element list for this UiElementNode.
At the end, the list of children UiElementNode here will match the one from the
provided XML {@link Node}:
- Walk both the current ui children list and the xml children list at the same time.
- If we have a new xml child but already reached the end of the ui child list, add the
new xml node.
- Otherwise, check if the xml node is referenced later in the ui child list and if so,
move it here. It means the XML child list has been reordered.
- Otherwise, this is a new XML node that we add in the middle of the ui child list.
- At the end, we may have finished walking the xml child list but still have remaining
ui children, simply delete them as they matching trailing xml nodes that have been
removed unless they are mandatory ui nodes.
Note that only the first case is used when populating the ui list the first time.
boolean structure_changed = false;
int ui_index = 0;
Node xml_child = xml_node.getFirstChild();
while (xml_child != null) {
if (xml_child.getNodeType() == Node.ELEMENT_NODE) {
String element_name = xml_child.getNodeName();
UiElementNode ui_node = null;
if (mUiChildren.size() <= ui_index) {
// A new node is being added at the end of the list
ElementDescriptor desc = mDescriptor.findChildrenDescriptor(element_name,
false /* recursive */);
if (desc == null) {
// Unknown node. Create a temporary descriptor for it.
// most important we want to auto-add unknown attributes to it.
AndroidEditor editor = getEditor();
IEditorInput editorInput = editor.getEditorInput();
if (editorInput instanceof IFileEditorInput) {
IFileEditorInput fileInput = (IFileEditorInput)editorInput;
desc = CustomViewDescriptorService.getInstance().getDescriptor(
fileInput.getFile().getProject(), element_name);
if (desc == null) {
desc = new ElementDescriptor(element_name);
}
} else {
desc = new ElementDescriptor(element_name);
// TODO associate a new "?" icon to this descriptor.
}
}
structure_changed = true;
ui_node = appendNewUiChild(desc);
ui_index++;
} else {
// A new node is being inserted or moved.
// Note: mandatory nodes can be created without an XML node in which case
// getXmlNode() is null.
UiElementNode ui_child;
int n = mUiChildren.size();
for (int j = ui_index; j < n; j++) {
ui_child = mUiChildren.get(j);
if (ui_child.getXmlNode() != null && ui_child.getXmlNode() == xml_child) {
if (j > ui_index) {
// Found the same XML node at some later index, now move it here.
mUiChildren.remove(j);
mUiChildren.add(ui_index, ui_child);
structure_changed = true;
}
ui_node = ui_child;
ui_index++;
break;
}
}
if (ui_node == null) {
// Look for an unused mandatory node with no XML node attached
// referencing the same XML element name
for (int j = ui_index; j < n; j++) {
ui_child = mUiChildren.get(j);
if (ui_child.getXmlNode() == null &&
ui_child.getDescriptor().isMandatory() &&
ui_child.getDescriptor().getXmlName().equals(element_name)) {
if (j > ui_index) {
// Found it, now move it here
mUiChildren.remove(j);
mUiChildren.add(ui_index, ui_child);
}
// assign the XML node to this empty mandatory element.
ui_child.mXmlNode = xml_child;
structure_changed = true;
ui_node = ui_child;
ui_index++;
}
}
}
if (ui_node == null) {
// Inserting new node
ElementDescriptor desc = mDescriptor.findChildrenDescriptor(element_name,
false /* recursive */);
if (desc == null) {
// Unknown element. Simply ignore it.
AdtPlugin.log(IStatus.WARNING,
"AndroidManifest: Ignoring unknown '%s' XML element", //$NON-NLS-1$
element_name);
} else {
structure_changed = true;
ui_node = insertNewUiChild(ui_index, desc);
ui_index++;
}
}
}
if (ui_node != null) {
// If we touched an UI Node, even an existing one, refresh its content.
// For new nodes, this will populate them recursively.
structure_changed |= ui_node.loadFromXmlNode(xml_child);
}
}
xml_child = xml_child.getNextSibling();
}
// There might be extra UI nodes at the end if the XML node list got shorter.
for (int index = mUiChildren.size() - 1; index >= ui_index; --index) {
structure_changed |= removeUiChildAtIndex(index);
}
return structure_changed;
|