/** * Invoked after the tree has drastically changed structure from a given node down. If the path * returned by e.getPath() is of length one and the first element does not identify the current * root node the first element should become the new root of the tree. * * <p>e.path() holds the path to the node. * * <p>e.childIndices() returns null. */ public void treeStructureChanged(TreeModelEvent e) { if (e != null) { TreePath changedPath = SwingUtilities2.getTreePath(e, getModel()); FHTreeStateNode changedNode = getNodeForPath(changedPath, false, false); // Check if root has changed, either to a null root, or // to an entirely new root. if (changedNode == root || (changedNode == null && ((changedPath == null && treeModel != null && treeModel.getRoot() == null) || (changedPath != null && changedPath.getPathCount() <= 1)))) { rebuild(true); } else if (changedNode != null) { boolean wasExpanded, wasVisible; FHTreeStateNode parent = (FHTreeStateNode) changedNode.getParent(); wasExpanded = changedNode.isExpanded(); wasVisible = changedNode.isVisible(); int index = parent.getIndex(changedNode); changedNode.collapse(false); parent.remove(index); if (wasVisible && wasExpanded) { int row = changedNode.getRow(); parent.resetChildrenRowsFrom(row, index, changedNode.getChildIndex()); changedNode = getNodeForPath(changedPath, false, true); changedNode.expand(); } if (treeSelectionModel != null && wasVisible && wasExpanded) treeSelectionModel.resetRowSelection(); if (wasVisible) this.visibleNodesChanged(); } } }
/** * Messaged when the node has expanded. This updates all of the receivers children rows, as well * as the total row count. */ protected void didExpand() { int nextRow = setRowAndChildren(row); FHTreeStateNode parent = (FHTreeStateNode) getParent(); int childRowCount = nextRow - row - 1; if (parent != null) { parent.adjustRowBy(childRowCount, parent.getIndex(this) + 1); } adjustRowCountBy(childRowCount); }
/** * Adjusts this node, its child, and its parent starting at an index of <code>index</code> index * is the index of the child to start adjusting from, which is not necessarily the model index. */ protected void adjustRowBy(int amount, int startIndex) { // Could check isVisible, but probably isn't worth it. if (isExpanded) { // children following startIndex. for (int counter = getChildCount() - 1; counter >= startIndex; counter--) ((FHTreeStateNode) getChildAt(counter)).adjustRowBy(amount); } // Parent FHTreeStateNode parent = (FHTreeStateNode) getParent(); if (parent != null) { parent.adjustRowBy(amount, parent.getIndex(this) + 1); } }
/** * Returns the number of children in the receiver by descending all expanded nodes and messaging * them with getTotalChildCount. */ public int getTotalChildCount() { if (isExpanded()) { FHTreeStateNode parent = (FHTreeStateNode) getParent(); int pIndex; if (parent != null && (pIndex = parent.getIndex(this)) + 1 < parent.getChildCount()) { // This node has a created sibling, to calc total // child count directly from that! FHTreeStateNode nextSibling = (FHTreeStateNode) parent.getChildAt(pIndex + 1); return nextSibling.row - row - (nextSibling.childIndex - childIndex); } else { int retCount = childCount; for (int counter = getChildCount() - 1; counter >= 0; counter--) { retCount += ((FHTreeStateNode) getChildAt(counter)).getTotalChildCount(); } return retCount; } } return 0; }
// This can be rather expensive, but is needed for the collapse // case this is resulting from a remove (although I could fix // that by having instances of FHTreeStateNode hold a ref to // the number of children). I prefer this though, making determing // the row of a particular node fast is very nice! protected void resetChildrenRowsFrom(int newRow, int childIndex, int modelIndex) { int lastRow = newRow; int lastModelIndex = modelIndex; FHTreeStateNode node; int maxCounter = getChildCount(); for (int counter = childIndex; counter < maxCounter; counter++) { node = (FHTreeStateNode) getChildAt(counter); lastRow += (node.childIndex - lastModelIndex); lastModelIndex = node.childIndex + 1; if (node.isExpanded) { lastRow = node.setRowAndChildren(lastRow); } else { node.row = lastRow++; } } lastRow += childCount - lastModelIndex; node = (FHTreeStateNode) getParent(); if (node != null) { node.resetChildrenRowsFrom(lastRow, node.getIndex(this) + 1, this.childIndex + 1); } else { // This is the root, reset total ROWCOUNT! rowCount = lastRow; } }