package hep.io.root.util; import hep.io.root.RootClass; import hep.io.root.RootClassNotFound; import hep.io.root.RootObject; import hep.io.root.interfaces.TBranch; import hep.io.root.interfaces.TBranchClones; import hep.io.root.interfaces.TDirectory; import hep.io.root.interfaces.TKey; import hep.io.root.interfaces.TLeaf; import hep.io.root.interfaces.TNamed; import hep.io.root.interfaces.TTree; import java.io.IOException; import javax.swing.tree.TreeModel; import javax.swing.tree.TreePath; /** * An adaptor that converts a root TDirectory into * a TreeModel, allowing any directory structure to * be dislayed by a Swing JTree. * <p> * This model will also drill down into TTree's, showing the branch and * leaf structure inside. * * @author Tony Johnson (tonyj@slac.stanford.edu) * @version $Id: RootDirectoryTreeModel.java 13617 2009-04-09 22:48:46Z tonyj $ */ /* * Implementation notes: * * Nodes in the tree may be: * TKey's corresponding to entries in Directories * (a fake TKey is created for the top level directory) * TBranch a branch of a tree * TBranchClones * BranchEntry -- representing an occurence of a Leaf */ public class RootDirectoryTreeModel implements TreeModel { private TKey top; /** * Create the tree model * @param topDir The TDirectory that is to appear as the "root" of the tree */ public RootDirectoryTreeModel(TDirectory topDir) { /** * In our tree all the nodes correspond to TKeys, so we need to * create a "fake" TKey to represent the top of the tree */ this.top = new FakeTKey(topDir); } public Object getChild(Object parent, int index) { try { if (parent instanceof TKey) { TKey node = (TKey) parent; Object object = node.getObject(); if (object instanceof TDirectory) { TDirectory dir = (TDirectory) object; return dir.getKey(index); } else // if (object instanceof TTree) { TTree tree = (TTree) object; return tree.getBranch(index); } } else // if (node instanceof TBranch) { TBranch branch = (TBranch) parent; int n = branch.getBranches().size(); if (index < n) { // These are the sub-branches Object p = branch.getBranches().get(index); if (p instanceof TBranch) return p; if (p instanceof TBranchClones) return p; return new BranchEntry("????" + p.getClass(), index); } // Otherwise this is the data for the branch else { TLeaf leaf = (TLeaf) branch.getLeaves().get(0); // TODO: more leaves return new BranchEntry(leaf, index, n); } } } catch (RootClassNotFound x) { handleException(x); return new BranchEntry(x, index); } catch (IOException x) { handleException(x); return new BranchEntry(x, index); } } public int getChildCount(Object parent) { try { if (parent instanceof TKey) { TKey node = (TKey) parent; Object object = node.getObject(); if (object instanceof TDirectory) { TDirectory dir = (TDirectory) object; return dir.nKeys(); } else // if (object instanceof TTree) { TTree tree = (TTree) object; return tree.getNBranches(); } } else // if (object instanceof TBranch) { TBranch branch = (TBranch) parent; long n = branch.getBranches().size(); n += branch.getEntries(); return (int) n; } } catch (RootClassNotFound x) { handleException(x); return -1; } catch (IOException x) { handleException(x); return 0; } } public int getIndexOfChild(Object parent, Object child) { try { if (parent instanceof TKey) { TKey node = (TKey) parent; Object object = node.getObject(); if (object instanceof TDirectory) { TDirectory dir = (TDirectory) object; int n = dir.nKeys(); for (int i = 0; i < n; i++) if (dir.getKey(i).equals(child)) return i; throw new IOException("Could not find " + child + " in " + dir); } else // if (object instanceof TTree) { TTree tree = (TTree) object; for (int i = 0; i < tree.getNBranches(); i++) if (tree.getBranch(i).equals(child)) return i; throw new IOException("Could not find " + child + " in " + tree); } } else { if (child instanceof BranchEntry) { BranchEntry entry = (BranchEntry) child; return entry.getIndex(); } else { TBranch branch = (TBranch) parent; int index = branch.getBranches().indexOf(child); if (index < 0) System.out.println("Illegal index " + index + " " + child + " " + branch); return index; } } } catch (RootClassNotFound x) { handleException(x); return -1; } catch (IOException x) { handleException(x); return -1; } } public boolean isLeaf(Object parent) { try { if (parent instanceof TKey) { TKey key = (TKey) parent; RootClass rc = key.getObjectClass(); Class jc = rc.getJavaClass(); // We need something better here! if (TDirectory.class.isAssignableFrom(jc)) return false; if (TTree.class.isAssignableFrom(jc)) return false; return true; } else if (parent instanceof TBranch) return false; else return true; } catch (IOException x) { handleException(x); return true; } catch (Throwable t) { t.printStackTrace(); return true; } } public Object getRoot() { return top; } public void addTreeModelListener(javax.swing.event.TreeModelListener p1) {} //The remaining methods are not implemented since the root tree //is assumed for now to be immutable. public void removeTreeModelListener(javax.swing.event.TreeModelListener p1) {} public void valueForPathChanged(TreePath p1, Object p2) {} /** * Handle IOExceptions when reading the root file. * Can be overriden in order to handle IOExceptions * encountered when reading objects from the root file. * The default implementation throws a RuntimeException */ protected void handleException(IOException x) { throw new RuntimeException("IOException reading root file",x); } protected void handleException(RootClassNotFound x) { throw new RuntimeException("Root class not found reading root file: " + x.getClassName(),x); } } class FakeTKey implements TKey { private TNamed target; FakeTKey(TNamed target) { this.target = target; //System.out.println("Created fakeTKey for "+target.getName()); } public int getBits() { return 0; } public short getCycle() { return 1; } public String getName() { return target.getName(); } /** * Returns the proxy for the object */ public RootObject getObject() throws IOException { return target; } public RootClass getObjectClass() { return target.getRootClass(); } public RootClass getRootClass() { return target.getRootClass(); } public String getTitle() { return target.getTitle(); } public int getUniqueID() { return 0; } public boolean equals(Object other) { if (other instanceof FakeTKey) { return this.target.equals(((FakeTKey) other).target); } return false; } public int hashCode() { return target.hashCode(); } public RootObject readObject() { return target; } } /** * Represents an element in an array. * We cannot use the value of the array element itself * as the tree node since the same object may be referenced * by multiple elements of the array, and since the value * may be null. */ class BranchEntry { private TLeaf leaf; private int index; private int offset; BranchEntry(Object entry, int index) { this(null, index, 0); } BranchEntry(TLeaf leaf, int index, int offset) { this.leaf = leaf; this.index = index; this.offset = offset; } public String toString() { String name; try { Object o = getValue(); if (o == null) name = "null"; else if (o.getClass().isArray()) name = "Array"; // Too bad we dont know this without calling getValue else if (o instanceof java.util.List) name = "List"; else name = o.toString(); } catch (IOException x) { name = "????"; } return "[" + (index - offset) + "] " + name; } int getIndex() { return index; } Object getValue() throws IOException { return leaf.getWrappedValue(index - offset); } }