package hep.io.root.util; import hep.io.root.RootClass; import hep.io.root.RootMember; import hep.io.root.RootObject; import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.Map; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreeNode; /** * An adaptor which converts a RootObject to a TreeModel. * This allows the super classes and member variables of * the RootObject to be viewed in a JTree. If member variables * are themselves RootObjects, or arrays, they can be * browsed in turn by "drilling down" in the tree. * @author Tony Johnson (tonyj@slac.stanford.edu) * @version $Id: RootObjectTreeModel.java 8584 2006-08-10 23:06:37Z duns $ */ /* * Implementation notes: * Since there are not already existing objects which represent all the nodes * in the tree, we use the TreeNode approach to building the TreeModel. * Consecutive requests for the same node may result in different objects, so * this will only work when the JTree caches the nodes, i.e. when "largeModel" * has not been set on the JTree. */ public class RootObjectTreeModel extends DefaultTreeModel { /** * Create the RootObjectTreeModel * @param top The RootObject to appear at the "root" of the tree */ public RootObjectTreeModel(Object top, String name) { super(RootObjectTreeNode.getNodeForValue(null, top, name, 0)); } protected RootObjectTreeModel(TreeNode node) { super(node); } protected static int getIndex(TreeNode child) { return ((RootObjectTreeNode) child).index; } protected static TreeNode getNodeForChild(TreeNode parent, Object child, String name, int index) { return RootObjectTreeNode.getNodeForValue(parent, child, name, index); } static abstract class RootObjectTreeNode implements TreeNode { private String tooltip; private TreeNode parent; private int index; RootObjectTreeNode(TreeNode parent, int index) { this.parent = parent; this.index = index; } public boolean getAllowsChildren() { return true; } public TreeNode getChildAt(int p1) { throw new InternalError("getChildAt() called"); } public int getChildCount() { return 0; } public int getIndex(TreeNode child) { return ((RootObjectTreeNode) child).index; } public boolean isLeaf() { return false; } public TreeNode getParent() { return parent; } public Enumeration children() { return new Enumeration() { private int n = getChildCount(); private int i = 0; public boolean hasMoreElements() { return i < n; } public Object nextElement() { return getChildAt(i++); } }; } public boolean equals(Object obj) { if (obj instanceof RootObjectTreeNode) { RootObjectTreeNode other = (RootObjectTreeNode) obj; if (this.index != other.index) return false; if (this.parent == null) return other.parent == null; return this.parent.equals(other.parent); } return false; } public int hashCode() { return index + ((parent == null) ? 0 : parent.hashCode()); } public String toString() { return description(); } static RootObjectTreeNode getNodeForValue(TreeNode parent, Object value, String name, int index) { if (value == null) return new RootSimpleValue(parent, "null", name, index); else if (value instanceof List) return new RootListNode(parent, (List) value, name, index); else if (value instanceof Map) return new RootMapNode(parent, (Map) value, name, index); else if (value.getClass().isArray()) return new RootArrayNode(parent, value, name, index); else if (value instanceof RootObject) return new RootObjectNode(parent, (RootObject) value, name, index); else return new RootSimpleValue(parent, value, name, index); } void setToolTip(String value) { tooltip = value; } abstract String description(); String toolTip() { return tooltip; } } static class RootArrayNode extends RootObjectTreeNode { private Object array; private String name; RootArrayNode(TreeNode parent, Object array, String name, int index) { super(parent, index); this.array = array; this.name = name; } public TreeNode getChildAt(int index) { return getNodeForValue(this, Array.get(array, index), "[" + index + "]", index); } public int getChildCount() { return Array.getLength(array); } String description() { return name + " (Array)"; } } static class RootListNode extends RootObjectTreeNode { private List list; private String name; RootListNode(TreeNode parent, List list, String name, int index) { super(parent, index); this.list = list; this.name = name; } public TreeNode getChildAt(int index) { return getNodeForValue(this, list.get(index), "[" + index + "]", index); } public int getChildCount() { return list.size(); } String description() { return name + " (List)"; } } static class RootMapNode extends RootObjectTreeNode { private List list; private String name; RootMapNode(TreeNode parent, Map map, String name, int index) { super(parent, index); this.list = new ArrayList(map.entrySet()); this.name = name; } public TreeNode getChildAt(int index) { return new RootMapEntryNode(this, (Map.Entry) list.get(index), "[" + index + "]", index); } public int getChildCount() { return list.size(); } String description() { return name + " (Map)"; } } static class RootMapEntryNode extends RootObjectTreeNode { private Map.Entry entry; private String name; RootMapEntryNode(TreeNode parent, Map.Entry entry, String name, int index) { super(parent, index); this.entry = entry; this.name = name; } public TreeNode getChildAt(int index) { if (index == 0) return getNodeForValue(this, entry.getKey (), "key", index); else return getNodeForValue(this, entry.getValue(), "value", index); } public int getChildCount() { return 2; } String description() { return name + " (MapEntry)"; } } static class RootObjectNode extends RootSubObject { private String name; RootObjectNode(TreeNode parent, RootObject obj, String name, int index) { super(parent, obj, obj.getRootClass(), index); this.name = name; } String description() { return name + " (" + super.description() + ")"; } } static class RootSimpleValue extends RootObjectTreeNode { private Object value; private String name; RootSimpleValue(TreeNode parent, Object value, String name, int index) { super(parent, index); this.value = value; this.name = name; } public boolean isLeaf() { return true; } String description() { return name + " = " + value; } } static class RootSubObject extends RootObjectTreeNode { private RootClass klass; private RootObject obj; RootSubObject(TreeNode parent, RootObject obj, RootClass klass, int index) { super(parent, index); this.obj = obj; this.klass = klass; } public TreeNode getChildAt(int index) { RootClass[] superClasses = klass.getSuperClasses(); if (index < superClasses.length) { return new RootSubObject(this, obj, superClasses[index], index); } else { RootMember member = klass.getMembers()[index - superClasses.length]; // TODO: Some better way to tell if object is composite Object value = null; try { value = member.getValue(obj); } catch (Exception x) { x.printStackTrace(); value = x.getMessage(); } RootObjectTreeNode node = getNodeForValue(this, value, member.getName(), index); node.setToolTip(member.getComment()); return node; } } public int getChildCount() { int n = klass.getSuperClasses().length; n += klass.getMembers().length; return n; } String description() { return "Class " + klass.getClassName(); } } }