package com.robonobo.common.swing; import javax.swing.event.TreeModelEvent; import javax.swing.event.TreeModelListener; import javax.swing.tree.*; public class SortedTreeModel extends DefaultTreeModel { public SortedTreeModel(TreeNode root) { super(root); } public synchronized void replaceNodeSorted(SortableTreeNode parent, SortableTreeNode changedNode) { removeNodeFromParent(changedNode); insertNodeSorted(parent, changedNode); } public synchronized void insertNodeSorted(SortableTreeNode parent, SortableTreeNode newNode) { // If the parent has no children, just insert it if (parent.getChildCount() == 0) { insertNodeInto(newNode, parent, 0); return; } // If it's before the first one or after the last one, just put it in SortableTreeNode firstChild = (SortableTreeNode) parent.getFirstChild(); if (newNode.compareTo(firstChild) < 0) { insertNodeInto(newNode, parent, 0); return; } SortableTreeNode lastChild = (SortableTreeNode) parent.getLastChild(); if (newNode.compareTo(lastChild) >= 0) { insertNodeInto(newNode, parent, parent.getChildCount()); return; } // Otherwise, use binary search to find the place insertNodeInto(newNode, parent, getInsertIndex(newNode, parent, 0, parent.getChildCount() - 1)); } private int getInsertIndex(SortableTreeNode newNode, SortableTreeNode parent, int low, int high) { if (low == high || high == (low + 1)) return high; int pivot = (high + low) / 2; SortableTreeNode pNode = (SortableTreeNode) parent.getChildAt(pivot); int cmp = newNode.compareTo(pNode); if (cmp == 0) return pivot; if (cmp < 0) return getInsertIndex(newNode, parent, low, pivot); else return getInsertIndex(newNode, parent, pivot, high); } public void firePathToRootChanged(TreeNode n) { // Why isn't this in DefaultTreeModel? TreeModelEvent e = new TreeModelEvent(this, getPathToRoot(n)); for (TreeModelListener l : getTreeModelListeners()) { l.treeNodesChanged(e); } } }