blob: 3443272b2ef8378394a3a9da3aea8d4c1c5b1703 [file] [log] [blame]
/*
* Copyright (C) 2008 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.eclipse.adt.internal.editors.layout;
import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode;
import com.android.layoutlib.api.IXmlPullParser;
import org.w3c.dom.Node;
import org.xmlpull.v1.XmlPullParserException;
import java.util.ArrayList;
import java.util.List;
/**
* {@link IXmlPullParser} implementation on top of {@link UiElementNode}.
* <p/>It's designed to work on layout files, and will most likely not work on other resource
* files.
*/
public final class UiElementPullParser extends BasePullParser {
private final ArrayList<UiElementNode> mNodeStack = new ArrayList<UiElementNode>();
private UiElementNode mRoot;
public UiElementPullParser(UiElementNode top) {
super();
mRoot = top;
push(mRoot);
}
private UiElementNode getCurrentNode() {
if (mNodeStack.size() > 0) {
return mNodeStack.get(mNodeStack.size()-1);
}
return null;
}
private Node getAttribute(int i) {
if (mParsingState != START_TAG) {
throw new IndexOutOfBoundsException();
}
// get the current uiNode
UiElementNode uiNode = getCurrentNode();
// get its xml node
Node xmlNode = uiNode.getXmlNode();
if (xmlNode != null) {
return xmlNode.getAttributes().item(i);
}
return null;
}
private void push(UiElementNode node) {
mNodeStack.add(node);
}
private UiElementNode pop() {
return mNodeStack.remove(mNodeStack.size()-1);
}
// ------------- IXmlPullParser --------
/**
* {@inheritDoc}
*
* This implementation returns the underlying DOM node.
*/
public Object getViewKey() {
return getCurrentNode();
}
// ------------- XmlPullParser --------
public String getPositionDescription() {
return "XML DOM element depth:" + mNodeStack.size();
}
public int getAttributeCount() {
UiElementNode node = getCurrentNode();
if (node != null) {
return node.getUiAttributes().size();
}
return 0;
}
public String getAttributeName(int i) {
Node attribute = getAttribute(i);
if (attribute != null) {
return attribute.getLocalName();
}
return null;
}
public String getAttributeNamespace(int i) {
Node attribute = getAttribute(i);
if (attribute != null) {
return attribute.getNamespaceURI();
}
return ""; //$NON-NLS-1$
}
public String getAttributePrefix(int i) {
Node attribute = getAttribute(i);
if (attribute != null) {
return attribute.getPrefix();
}
return null;
}
public String getAttributeValue(int i) {
Node attribute = getAttribute(i);
if (attribute != null) {
return attribute.getNodeValue();
}
return null;
}
public String getAttributeValue(String namespace, String localName) {
// get the current uiNode
UiElementNode uiNode = getCurrentNode();
// get its xml node
Node xmlNode = uiNode.getXmlNode();
if (xmlNode != null) {
Node attribute = xmlNode.getAttributes().getNamedItemNS(namespace, localName);
if (attribute != null) {
return attribute.getNodeValue();
}
}
return null;
}
public int getDepth() {
return mNodeStack.size();
}
public String getName() {
if (mParsingState == START_TAG || mParsingState == END_TAG) {
return getCurrentNode().getDescriptor().getXmlLocalName();
}
return null;
}
public String getNamespace() {
if (mParsingState == START_TAG || mParsingState == END_TAG) {
return getCurrentNode().getDescriptor().getNamespace();
}
return null;
}
public String getPrefix() {
if (mParsingState == START_TAG || mParsingState == END_TAG) {
// FIXME will NEVER work
if (getCurrentNode().getDescriptor().getXmlLocalName().startsWith("android:")) { //$NON-NLS-1$
return "android"; //$NON-NLS-1$
}
}
return null;
}
public boolean isEmptyElementTag() throws XmlPullParserException {
if (mParsingState == START_TAG) {
return getCurrentNode().getUiChildren().size() == 0;
}
throw new XmlPullParserException("Call to isEmptyElementTag while not in START_TAG",
this, null);
}
@Override
public void onNextFromStartDocument() {
onNextFromStartTag();
}
@Override
public void onNextFromStartTag() {
// get the current node, and look for text or children (children first)
UiElementNode node = getCurrentNode();
List<UiElementNode> children = node.getUiChildren();
if (children.size() > 0) {
// move to the new child, and don't change the state.
push(children.get(0));
// in case the current state is CURRENT_DOC, we set the proper state.
mParsingState = START_TAG;
} else {
if (mParsingState == START_DOCUMENT) {
// this handles the case where there's no node.
mParsingState = END_DOCUMENT;
} else {
mParsingState = END_TAG;
}
}
}
@Override
public void onNextFromEndTag() {
// look for a sibling. if no sibling, go back to the parent
UiElementNode node = getCurrentNode();
node = node.getUiNextSibling();
if (node != null) {
// to go to the sibling, we need to remove the current node,
pop();
// and add its sibling.
push(node);
mParsingState = START_TAG;
} else {
// move back to the parent
pop();
// we have only one element left (mRoot), then we're done with the document.
if (mNodeStack.size() == 1) {
mParsingState = END_DOCUMENT;
} else {
mParsingState = END_TAG;
}
}
}
}