/** * */ package org.seqcode.gseutils.datastructures; import javax.swing.event.*; import javax.swing.tree.TreeModel; import javax.swing.tree.TreePath; import org.seqcode.gseutils.Listener; import org.seqcode.gseutils.datastructures.Taxonomy; import org.seqcode.gseutils.datastructures.TaxonomyEvent; import java.util.*; /** * @author Timothy Danford */ public class TaxonomyTreeModel<X> implements TreeModel, Listener<TaxonomyEvent> { private Taxonomy<X> taxonomy; private TaxonomyAddr<X> root; private LinkedList<TreeModelListener> listeners; public TaxonomyTreeModel(Taxonomy<X> tax) { root = new TaxonomyAddr<X>(tax); listeners = new LinkedList<TreeModelListener>(); taxonomy = tax; taxonomy.addEventListener(this); } public void eventRegistered(TaxonomyEvent te) { System.out.println("Taxonomy Event Registered: " + te.toString()); root.handleTaxonomyEvent(this, te); } public void addElement(Collection<String> addr, X e) { taxonomy.addElement(addr, e); } public void removeElement(X e) { taxonomy.recursiveRemoveElement(e); } protected void fireTreeNodesInserted(Object[] path, int[] childInds, Object[] children) { TreeModelEvent e = new TreeModelEvent(this, path, childInds, children); for(TreeModelListener l : listeners) { l.treeNodesInserted(e); } } protected void fireTreeNodesChanged(Object[] path, int[] childInds, Object[] children) { TreeModelEvent e = new TreeModelEvent(this, path, childInds, children); for(TreeModelListener l : listeners) { l.treeNodesChanged(e); } } protected void fireTreeNodesRemoved(Object[] path, int[] childInds, Object[] children) { TreeModelEvent e = new TreeModelEvent(this, path, childInds, children); for(TreeModelListener l : listeners) { l.treeNodesRemoved(e); } } /* (non-Javadoc) * @see javax.swing.tree.TreeModel#getRoot() */ public Object getRoot() { return root; } /* (non-Javadoc) * @see javax.swing.tree.TreeModel#getChild(java.lang.Object, int) */ public Object getChild(Object parent, int index) { TaxonomyAddr parentAddr = (TaxonomyAddr)parent; if(index < parentAddr.getNumElements()) { return parentAddr.getElement(index); } else { return parentAddr.getNextAddr(index-parentAddr.getNumElements()); } } /* (non-Javadoc) * @see javax.swing.tree.TreeModel#getChildCount(java.lang.Object) */ public int getChildCount(Object parent) { if(parent instanceof TaxonomyAddr) { TaxonomyAddr ta = (TaxonomyAddr)parent; return ta.getNumElements() + ta.getNumSubTaxa(); } else { return 0; } } /* (non-Javadoc) * @see javax.swing.tree.TreeModel#isLeaf(java.lang.Object) */ public boolean isLeaf(Object value) { if(value instanceof TaxonomyAddr) { TaxonomyAddr ta = (TaxonomyAddr)value; return ta.getNumElements() == 0 && ta.getNumSubTaxa() == 0; } else { return true; } } /* (non-Javadoc) * @see javax.swing.tree.TreeModel#valueForPathChanged(javax.swing.tree.TreePath, java.lang.Object) */ public void valueForPathChanged(TreePath path, Object value) { } /* (non-Javadoc) * @see javax.swing.tree.TreeModel#getIndexOfChild(java.lang.Object, java.lang.Object) */ public int getIndexOfChild(Object parent, Object child) { TaxonomyAddr parentAddr = (TaxonomyAddr)parent; int index = parentAddr.indexOfElement(child); if(index != -1) { return index; } return parentAddr.indexOfAddr((TaxonomyAddr)child) + parentAddr.getNumElements(); } /* (non-Javadoc) * @see javax.swing.tree.TreeModel#addTreeModelListener(javax.swing.event.TreeModelListener) */ public void addTreeModelListener(TreeModelListener listener) { listeners.addLast(listener); } /* (non-Javadoc) * @see javax.swing.tree.TreeModel#removeTreeModelListener(javax.swing.event.TreeModelListener) */ public void removeTreeModelListener(TreeModelListener listener) { listeners.remove(listener); } } class TaxonomyAddr<X> { private Object[] path; private TaxonomyAddr parent; private LinkedList<String> addr; private Vector<TaxonomyAddr> nextAddrs; private Vector<X> elmts; public TaxonomyAddr(Taxonomy<X> base) { parent = null; path = new Object[1]; path[0] = this; addr = new LinkedList<String>(); SortedSet<String> ss = new TreeSet<String>(base.getAddrs()); nextAddrs = new Vector<TaxonomyAddr>(); for(String s : ss) { nextAddrs.add(new TaxonomyAddr<X>(this, addr, s, base)); } elmts = new Vector<X>(new TreeSet<X>(base.getImmediateElements())); } public TaxonomyAddr(TaxonomyAddr p, Collection<String> a, String next, Taxonomy<X> base) { parent = p; path = new Object[p.path.length+1]; for(int i = 0; i < p.path.length; i++) { path[i] = p.path[i]; } path[path.length-1] = this; addr = new LinkedList<String>(a); addr.addLast(next); Taxonomy<X> sub = getTaxonomy(base); SortedSet<String> ss = new TreeSet<String>(sub.getAddrs()); nextAddrs = new Vector<TaxonomyAddr>(); for(String s : ss) { nextAddrs.add(new TaxonomyAddr<X>(this, addr, s, base)); } elmts = new Vector<X>(new TreeSet<X>(sub.getImmediateElements())); } public TaxonomyAddr(TaxonomyAddr p, Collection<String> a, String next) { parent = p; path = new Object[p.path.length+1]; for(int i = 0; i < p.path.length; i++) { path[i] = p.path[i]; } path[path.length-1] = this; addr = new LinkedList<String>(a); addr.addLast(next); elmts = new Vector<X>(); nextAddrs = new Vector<TaxonomyAddr>(); } public void handleTaxonomyEvent(TaxonomyTreeModel<X> ttm, TaxonomyEvent te) { System.out.println(getAddrString() + " [" + addr.size() + "] :: " + te.toString()); int[] childinds = new int[1]; Object[] children = new Object[1]; if(te.getAddrLength() == 0) { children[0] = te.getLeaf(); X v = (X)te.getLeaf(); switch(te.getType()) { case TaxonomyEvent.ELEMENT_ADDED: elmts.insertElementAt(v, 0); childinds[0] = 0; ttm.fireTreeNodesInserted(path, childinds, children); break; case TaxonomyEvent.ELEMENT_REMOVED: childinds[0] = indexOfElement(v); elmts.removeElementAt(childinds[0]); ttm.fireTreeNodesRemoved(path, childinds, children); break; case TaxonomyEvent.ELEMENT_CHANGED: childinds[0] = indexOfElement(v); ttm.fireTreeNodesChanged(path, childinds, children); break; case TaxonomyEvent.TAXON_ADDED: case TaxonomyEvent.TAXON_REMOVED: default: throw new IllegalArgumentException("type: " + te.getType()); } } else { String addr_key = te.removeAddr(); System.out.println(">>> Addr key: " + addr_key); Iterator<TaxonomyAddr> taItr = nextAddrs.iterator(); boolean found = false; while(taItr.hasNext() && !found) { TaxonomyAddr nextA = taItr.next(); if(found = nextA.addr.getLast().equals(addr_key)) { nextA.handleTaxonomyEvent(ttm, te); } } if(!found) { System.out.println(">> No match found to addr_key: {" + addr_key + "}"); TaxonomyAddr newAddr = new TaxonomyAddr<X>(this, addr, addr_key); childinds[0] = elmts.size(); System.out.println("new index: " + childinds[0]); children[0] = newAddr; nextAddrs.insertElementAt(newAddr, 0); ttm.fireTreeNodesInserted(path, childinds, children); newAddr.handleTaxonomyEvent(ttm, te); } } } public int indexOfAddr(TaxonomyAddr next) { for(int i = 0; i < nextAddrs.size(); i++) { if(nextAddrs.get(i).equals(next)) { return i; } } return -1; } public int indexOfElement(X v) { for(int i = 0; i < elmts.size(); i++) { if(elmts.get(i).equals(v)) { return i; } } return -1; } public TaxonomyAddr getNextAddr(int i) { return nextAddrs.get(i); } public X getElement(int i) { return elmts.get(i); } public int getNumSubTaxa() { return nextAddrs.size(); } public int getNumElements() { return elmts.size(); } public int length() { return addr.size(); } public LinkedList<String> getAddr() { return addr; } public Taxonomy<X> getTaxonomy(Taxonomy<X> base) { Taxonomy<X> current = base; for(String a : addr) { if(!current.hasAddr(a)) { throw new IllegalArgumentException(a); } current = current.getSubTaxonomy(a); } return current; } public String getLast() { return addr.getLast(); } public boolean equals(Object o) { if(!(o instanceof TaxonomyAddr)) { return false; } TaxonomyAddr ta = (TaxonomyAddr)o; if(addr.size() != ta.addr.size()) { return false; } for(int i = 0; i < addr.size(); i++) { if(!(addr.get(i).equals(ta.addr.get(i)))) { return false; } } return true; } public int hashCode() { int code = 17; for(String a : addr) { code += a.hashCode(); code *= 37; } return code; } public String getAddrString() { StringBuilder sb = new StringBuilder(); boolean first = true; for(String a : addr) { if(!first) { sb.append(","); } sb.append(a); first = false; } return sb.toString(); } public String toString() { if(addr.size() == 0) { return "Root"; } return addr.getLast(); } }