blob: 3529d1052547103861d92d145643e1f348580256 [file] [log] [blame]
package com.xtremelabs.droidsugar.view;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import java.io.File;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ViewLoader extends XmlLoader {
private Map<String, ViewNode> viewNodesByLayoutName = new HashMap<String, ViewNode>();
public ViewLoader(ResourceExtractor resourceExtractor) {
super(resourceExtractor);
}
@Override
protected void processResourceXml(File xmlFile, Document document) throws Exception {
ViewNode topLevelNode = new ViewNode("top-level", new HashMap<String, String>());
processChildren(document.getChildNodes(), topLevelNode);
viewNodesByLayoutName.put(
"layout/" + xmlFile.getName().replace(".xml", ""),
topLevelNode.getChildren().get(0));
}
private void processChildren(NodeList childNodes, ViewNode parent) {
for (int i = 0; i < childNodes.getLength(); i++) {
Node node = childNodes.item(i);
processNode(node, parent);
}
}
private void processNode(Node node, ViewNode parent) {
String name = node.getNodeName();
NamedNodeMap attributes = node.getAttributes();
Map<String, String> attrMap = new HashMap<String, String>();
if (attributes != null) {
int length = attributes.getLength();
for (int i = 0; i < length; i++) {
Node attr = attributes.item(i);
attrMap.put(attr.getNodeName(), attr.getNodeValue());
}
}
if (!name.startsWith("#")) {
ViewNode viewNode = new ViewNode(name, attrMap);
if (parent != null) parent.addChild(viewNode);
String idAttr = getIdAttr(node);
if (idAttr != null && idAttr.startsWith("@+id/")) {
idAttr = idAttr.substring(5);
Integer id = resourceExtractor.getResourceStringToId().get("id/" + idAttr);
if (id == null) {
throw new RuntimeException("unknown id " + getIdAttr(node));
}
viewNode.setId(id);
}
processChildren(node.getChildNodes(), viewNode);
}
}
public View inflateView(Context context, String key) {
ViewNode viewNode = viewNodesByLayoutName.get(key);
if (viewNode == null) {
throw new RuntimeException("no such layout " + key);
}
try {
return viewNode.inflate(context);
} catch (Exception e) {
throw new RuntimeException("error inflating " + key, e);
}
}
public View inflateView(Context context, int resourceId) {
return inflateView(context, resourceExtractor.getResourceName(resourceId));
}
private class ViewNode {
private String name;
private final Map<String, String> attributes;
private List<ViewNode> children = new ArrayList<ViewNode>();
private Integer id;
public ViewNode(String name, Map<String, String> attributes) {
this.name = name;
this.attributes = attributes;
}
public List<ViewNode> getChildren() {
return children;
}
public void addChild(ViewNode viewNode) {
children.add(viewNode);
}
public View inflate(Context context) throws Exception {
View view = create(context);
if (id != null && view.getId() == 0) {
view.setId(id);
}
for (ViewNode child : children) {
((ViewGroup) view).addView(child.inflate(context));
}
return view;
}
private View create(Context context) throws Exception {
if (name.equals("include")) {
String layout = attributes.get("layout");
return inflateView(context, layout.substring(1));
} else if (name.equals("merge")) {
return new LinearLayout(context);
} else {
Class<? extends View> clazz = loadClass(name);
if (clazz == null) {
clazz = loadClass("android.view." + name);
}
if (clazz == null) {
clazz = loadClass("android.widget." + name);
}
if (clazz == null) {
clazz = loadClass("com.google.android.maps." + name);
}
if (clazz == null) {
throw new RuntimeException("couldn't find view class " + name);
}
Constructor<? extends View> constructor;
try {
constructor = clazz.getConstructor(Context.class);
return constructor.newInstance(context);
} catch (NoSuchMethodException e) {
constructor = clazz.getConstructor(Context.class, String.class);
return constructor.newInstance(context, "");
}
}
}
private Class<? extends View> loadClass(String className) {
try {
//noinspection unchecked
return (Class<? extends View>) getClass().getClassLoader().loadClass(className);
} catch (ClassNotFoundException e) {
return null;
}
}
public void setId(Integer id) {
this.id = id;
}
}
}