1 7 8 package javax.swing.tree; 9 10 import javax.swing.event.TreeModelEvent ; 11 import java.awt.Dimension ; 12 import java.awt.Rectangle ; 13 import java.util.Enumeration ; 14 import java.util.Hashtable ; 15 import java.util.NoSuchElementException ; 16 import java.util.Stack ; 17 import java.util.Vector ; 18 19 36 37 public class VariableHeightLayoutCache extends AbstractLayoutCache { 38 42 private Vector visibleNodes; 43 44 47 private boolean updateNodeSizes; 48 49 54 private TreeStateNode root; 55 56 60 private Rectangle boundsBuffer; 61 62 65 private Hashtable treePathMapping; 66 67 70 private Stack tempStacks; 71 72 73 public VariableHeightLayoutCache() { 74 super(); 75 tempStacks = new Stack (); 76 visibleNodes = new Vector (); 77 boundsBuffer = new Rectangle (); 78 treePathMapping = new Hashtable (); 79 } 80 81 89 public void setModel(TreeModel newModel) { 90 super.setModel(newModel); 91 rebuild(false); 92 } 93 94 105 public void setRootVisible(boolean rootVisible) { 106 if(isRootVisible() != rootVisible && root != null) { 107 if(rootVisible) { 108 root.updatePreferredSize(0); 109 visibleNodes.insertElementAt(root, 0); 110 } 111 else if(visibleNodes.size() > 0) { 112 visibleNodes.removeElementAt(0); 113 if(treeSelectionModel != null) 114 treeSelectionModel.removeSelectionPath 115 (root.getTreePath()); 116 } 117 if(treeSelectionModel != null) 118 treeSelectionModel.resetRowSelection(); 119 if(getRowCount() > 0) 120 getNode(0).setYOrigin(0); 121 updateYLocationsFrom(0); 122 visibleNodesChanged(); 123 } 124 super.setRootVisible(rootVisible); 125 } 126 127 137 public void setRowHeight(int rowHeight) { 138 if(rowHeight != getRowHeight()) { 139 super.setRowHeight(rowHeight); 140 invalidateSizes(); 141 this.visibleNodesChanged(); 142 } 143 } 144 145 149 public void setNodeDimensions(NodeDimensions nd) { 150 super.setNodeDimensions(nd); 151 invalidateSizes(); 152 visibleNodesChanged(); 153 } 154 155 161 public void setExpandedState(TreePath path, boolean isExpanded) { 162 if(path != null) { 163 if(isExpanded) 164 ensurePathIsExpanded(path, true); 165 else { 166 TreeStateNode node = getNodeForPath(path, false, true); 167 168 if(node != null) { 169 node.makeVisible(); 170 node.collapse(); 171 } 172 } 173 } 174 } 175 176 180 public boolean getExpandedState(TreePath path) { 181 TreeStateNode node = getNodeForPath(path, true, false); 182 183 return (node != null) ? (node.isVisible() && node.isExpanded()) : 184 false; 185 } 186 187 196 public Rectangle getBounds(TreePath path, Rectangle placeIn) { 197 TreeStateNode node = getNodeForPath(path, true, false); 198 199 if(node != null) { 200 if(updateNodeSizes) 201 updateNodeSizes(false); 202 return node.getNodeBounds(placeIn); 203 } 204 return null; 205 } 206 207 215 public TreePath getPathForRow(int row) { 216 if(row >= 0 && row < getRowCount()) { 217 return getNode(row).getTreePath(); 218 } 219 return null; 220 } 221 222 230 public int getRowForPath(TreePath path) { 231 if(path == null) 232 return -1; 233 234 TreeStateNode visNode = getNodeForPath(path, true, false); 235 236 if(visNode != null) 237 return visNode.getRow(); 238 return -1; 239 } 240 241 245 public int getRowCount() { 246 return visibleNodes.size(); 247 } 248 249 255 public void invalidatePathBounds(TreePath path) { 256 TreeStateNode node = getNodeForPath(path, true, false); 257 258 if(node != null) { 259 node.markSizeInvalid(); 260 if(node.isVisible()) 261 updateYLocationsFrom(node.getRow()); 262 } 263 } 264 265 269 public int getPreferredHeight() { 270 int rowCount = getRowCount(); 272 273 if(rowCount > 0) { 274 TreeStateNode node = getNode(rowCount - 1); 275 276 return node.getYOrigin() + node.getPreferredHeight(); 277 } 278 return 0; 279 } 280 281 287 public int getPreferredWidth(Rectangle bounds) { 288 if(updateNodeSizes) 289 updateNodeSizes(false); 290 291 return getMaxNodeWidth(); 292 } 293 294 306 public TreePath getPathClosestTo(int x, int y) { 307 if(getRowCount() == 0) 308 return null; 309 310 if(updateNodeSizes) 311 updateNodeSizes(false); 312 313 int row = getRowContainingYLocation(y); 314 315 return getNode(row).getTreePath(); 316 } 317 318 327 public Enumeration <TreePath > getVisiblePathsFrom(TreePath path) { 328 TreeStateNode node = getNodeForPath(path, true, false); 329 330 if(node != null) { 331 return new VisibleTreeStateNodeEnumeration(node); 332 } 333 return null; 334 } 335 336 340 public int getVisibleChildCount(TreePath path) { 341 TreeStateNode node = getNodeForPath(path, true, false); 342 343 return (node != null) ? node.getVisibleChildCount() : 0; 344 } 345 346 350 public void invalidateSizes() { 351 if(root != null) 352 root.deepMarkSizeInvalid(); 353 if(!isFixedRowHeight() && visibleNodes.size() > 0) { 354 updateNodeSizes(true); 355 } 356 } 357 358 364 public boolean isExpanded(TreePath path) { 365 if(path != null) { 366 TreeStateNode lastNode = getNodeForPath(path, true, false); 367 368 return (lastNode != null && lastNode.isExpanded()); 369 } 370 return false; 371 } 372 373 377 393 public void treeNodesChanged(TreeModelEvent e) { 394 if(e != null) { 395 int changedIndexs[]; 396 TreeStateNode changedNode; 397 398 changedIndexs = e.getChildIndices(); 399 changedNode = getNodeForPath(e.getTreePath(), false, false); 400 if(changedNode != null) { 401 Object changedValue = changedNode.getValue(); 402 403 405 changedNode.updatePreferredSize(); 406 if(changedNode.hasBeenExpanded() && changedIndexs != null) { 407 int counter; 408 TreeStateNode changedChildNode; 409 410 for(counter = 0; counter < changedIndexs.length; 411 counter++) { 412 changedChildNode = (TreeStateNode)changedNode 413 .getChildAt(changedIndexs[counter]); 414 415 changedChildNode.setUserObject 416 (treeModel.getChild(changedValue, 417 changedIndexs[counter])); 418 changedChildNode.updatePreferredSize(); 419 } 420 } 421 else if (changedNode == root) { 422 changedNode.updatePreferredSize(); 424 } 425 if(!isFixedRowHeight()) { 426 int aRow = changedNode.getRow(); 427 428 if(aRow != -1) 429 this.updateYLocationsFrom(aRow); 430 } 431 this.visibleNodesChanged(); 432 } 433 } 434 } 435 436 437 446 public void treeNodesInserted(TreeModelEvent e) { 447 if(e != null) { 448 int changedIndexs[]; 449 TreeStateNode changedParentNode; 450 451 changedIndexs = e.getChildIndices(); 452 changedParentNode = getNodeForPath(e.getTreePath(), false, false); 453 455 if(changedParentNode != null && changedIndexs != null && 457 changedIndexs.length > 0) { 458 if(changedParentNode.hasBeenExpanded()) { 459 boolean makeVisible; 460 int counter; 461 Object changedParent; 462 TreeStateNode newNode; 463 int oldChildCount = changedParentNode. 464 getChildCount(); 465 466 changedParent = changedParentNode.getValue(); 467 makeVisible = ((changedParentNode == root && 468 !rootVisible) || 469 (changedParentNode.getRow() != -1 && 470 changedParentNode.isExpanded())); 471 for(counter = 0;counter < changedIndexs.length;counter++) 472 { 473 newNode = this.createNodeAt(changedParentNode, 474 changedIndexs[counter]); 475 } 476 if(oldChildCount == 0) { 477 changedParentNode.updatePreferredSize(); 479 } 480 if(treeSelectionModel != null) 481 treeSelectionModel.resetRowSelection(); 482 484 if(!isFixedRowHeight() && (makeVisible || 485 (oldChildCount == 0 && 486 changedParentNode.isVisible()))) { 487 if(changedParentNode == root) 488 this.updateYLocationsFrom(0); 489 else 490 this.updateYLocationsFrom(changedParentNode. 491 getRow()); 492 this.visibleNodesChanged(); 493 } 494 else if(makeVisible) 495 this.visibleNodesChanged(); 496 } 497 else if(treeModel.getChildCount(changedParentNode.getValue()) 498 - changedIndexs.length == 0) { 499 changedParentNode.updatePreferredSize(); 500 if(!isFixedRowHeight() && changedParentNode.isVisible()) 501 updateYLocationsFrom(changedParentNode.getRow()); 502 } 503 } 504 } 505 } 506 507 520 public void treeNodesRemoved(TreeModelEvent e) { 521 if(e != null) { 522 int changedIndexs[]; 523 TreeStateNode changedParentNode; 524 525 changedIndexs = e.getChildIndices(); 526 changedParentNode = getNodeForPath(e.getTreePath(), false, false); 527 if(changedParentNode != null && changedIndexs != null && 530 changedIndexs.length > 0) { 531 if(changedParentNode.hasBeenExpanded()) { 532 boolean makeInvisible; 533 int counter; 534 int removedRow; 535 TreeStateNode removedNode; 536 537 makeInvisible = ((changedParentNode == root && 538 !rootVisible) || 539 (changedParentNode.getRow() != -1 && 540 changedParentNode.isExpanded())); 541 for(counter = changedIndexs.length - 1;counter >= 0; 542 counter--) { 543 removedNode = (TreeStateNode)changedParentNode. 544 getChildAt(changedIndexs[counter]); 545 if(removedNode.isExpanded()) { 546 removedNode.collapse(false); 547 } 548 549 550 if(makeInvisible) { 551 removedRow = removedNode.getRow(); 552 if(removedRow != -1) { 553 visibleNodes.removeElementAt(removedRow); 554 } 555 } 556 changedParentNode.remove(changedIndexs[counter]); 557 } 558 if(changedParentNode.getChildCount() == 0) { 559 changedParentNode.updatePreferredSize(); 561 if (changedParentNode.isExpanded() && 562 changedParentNode.isLeaf()) { 563 changedParentNode.collapse(false); 565 } 566 } 567 if(treeSelectionModel != null) 568 treeSelectionModel.resetRowSelection(); 569 571 if(!isFixedRowHeight() && (makeInvisible || 572 (changedParentNode.getChildCount() == 0 && 573 changedParentNode.isVisible()))) { 574 if(changedParentNode == root) { 575 578 if(getRowCount() > 0) 579 getNode(0).setYOrigin(0); 580 updateYLocationsFrom(0); 581 } 582 else 583 updateYLocationsFrom(changedParentNode.getRow()); 584 this.visibleNodesChanged(); 585 } 586 else if(makeInvisible) 587 this.visibleNodesChanged(); 588 } 589 else if(treeModel.getChildCount(changedParentNode.getValue()) 590 == 0) { 591 changedParentNode.updatePreferredSize(); 592 if(!isFixedRowHeight() && changedParentNode.isVisible()) 593 this.updateYLocationsFrom(changedParentNode.getRow()); 594 } 595 } 596 } 597 } 598 599 611 public void treeStructureChanged(TreeModelEvent e) { 612 if(e != null) 613 { 614 TreePath changedPath = e.getTreePath(); 615 TreeStateNode changedNode; 616 617 changedNode = getNodeForPath(changedPath, false, false); 618 619 if(changedNode == root || 622 (changedNode == null && 623 ((changedPath == null && treeModel != null && 624 treeModel.getRoot() == null) || 625 (changedPath != null && changedPath.getPathCount() == 1)))) { 626 rebuild(true); 627 } 628 else if(changedNode != null) { 629 int nodeIndex, oldRow; 630 TreeStateNode newNode, parent; 631 boolean wasExpanded, wasVisible; 632 int newIndex; 633 634 wasExpanded = changedNode.isExpanded(); 635 wasVisible = (changedNode.getRow() != -1); 636 637 parent = (TreeStateNode)changedNode.getParent(); 638 nodeIndex = parent.getIndex(changedNode); 639 if(wasVisible && wasExpanded) { 640 changedNode.collapse(false); 641 } 642 if(wasVisible) 643 visibleNodes.removeElement(changedNode); 644 changedNode.removeFromParent(); 645 createNodeAt(parent, nodeIndex); 646 newNode = (TreeStateNode)parent.getChildAt(nodeIndex); 647 if(wasVisible && wasExpanded) 648 newNode.expand(false); 649 newIndex = newNode.getRow(); 650 if(!isFixedRowHeight() && wasVisible) { 651 if(newIndex == 0) 652 updateYLocationsFrom(newIndex); 653 else 654 updateYLocationsFrom(newIndex - 1); 655 this.visibleNodesChanged(); 656 } 657 else if(wasVisible) 658 this.visibleNodesChanged(); 659 } 660 } 661 } 662 663 664 668 private void visibleNodesChanged() { 669 } 670 671 674 private void addMapping(TreeStateNode node) { 675 treePathMapping.put(node.getTreePath(), node); 676 } 677 678 681 private void removeMapping(TreeStateNode node) { 682 treePathMapping.remove(node.getTreePath()); 683 } 684 685 689 private TreeStateNode getMapping(TreePath path) { 690 return (TreeStateNode)treePathMapping.get(path); 691 } 692 693 698 private Rectangle getBounds(int row, Rectangle placeIn) { 699 if(updateNodeSizes) 700 updateNodeSizes(false); 701 702 if(row >= 0 && row < getRowCount()) { 703 return getNode(row).getNodeBounds(placeIn); 704 } 705 return null; 706 } 707 708 712 private void rebuild(boolean clearSelection) { 713 Object rootObject; 714 715 treePathMapping.clear(); 716 if(treeModel != null && (rootObject = treeModel.getRoot()) != null) { 717 root = createNodeForValue(rootObject); 718 root.path = new TreePath (rootObject); 719 addMapping(root); 720 root.updatePreferredSize(0); 721 visibleNodes.removeAllElements(); 722 if (isRootVisible()) 723 visibleNodes.addElement(root); 724 if(!root.isExpanded()) 725 root.expand(); 726 else { 727 Enumeration cursor = root.children(); 728 while(cursor.hasMoreElements()) { 729 visibleNodes.addElement(cursor.nextElement()); 730 } 731 if(!isFixedRowHeight()) 732 updateYLocationsFrom(0); 733 } 734 } 735 else { 736 visibleNodes.removeAllElements(); 737 root = null; 738 } 739 if(clearSelection && treeSelectionModel != null) { 740 treeSelectionModel.clearSelection(); 741 } 742 this.visibleNodesChanged(); 743 } 744 745 755 private TreeStateNode createNodeAt(TreeStateNode parent, 756 int childIndex) { 757 boolean isParentRoot; 758 Object newValue; 759 TreeStateNode newChildNode; 760 761 newValue = treeModel.getChild(parent.getValue(), childIndex); 762 newChildNode = createNodeForValue(newValue); 763 parent.insert(newChildNode, childIndex); 764 newChildNode.updatePreferredSize(-1); 765 isParentRoot = (parent == root); 766 if(newChildNode != null && parent.isExpanded() && 767 (parent.getRow() != -1 || isParentRoot)) { 768 int newRow; 769 770 771 if(childIndex == 0) { 772 if(isParentRoot && !isRootVisible()) 773 newRow = 0; 774 else 775 newRow = parent.getRow() + 1; 776 } 777 else if(childIndex == parent.getChildCount()) 778 newRow = parent.getLastVisibleNode().getRow() + 1; 779 else { 780 TreeStateNode previousNode; 781 782 previousNode = (TreeStateNode)parent. 783 getChildAt(childIndex - 1); 784 newRow = previousNode.getLastVisibleNode().getRow() + 1; 785 } 786 visibleNodes.insertElementAt(newChildNode, newRow); 787 } 788 return newChildNode; 789 } 790 791 796 private TreeStateNode getNodeForPath(TreePath path, 797 boolean onlyIfVisible, 798 boolean shouldCreate) { 799 if(path != null) { 800 TreeStateNode node; 801 802 node = getMapping(path); 803 if(node != null) { 804 if(onlyIfVisible && !node.isVisible()) 805 return null; 806 return node; 807 } 808 809 Stack paths; 811 812 if(tempStacks.size() == 0) { 813 paths = new Stack (); 814 } 815 else { 816 paths = (Stack )tempStacks.pop(); 817 } 818 819 try { 820 paths.push(path); 821 path = path.getParentPath(); 822 node = null; 823 while(path != null) { 824 node = getMapping(path); 825 if(node != null) { 826 while(node != null && paths.size() > 0) { 829 path = (TreePath )paths.pop(); 830 node.getLoadedChildren(shouldCreate); 831 832 int childIndex = treeModel. 833 getIndexOfChild(node.getUserObject(), 834 path.getLastPathComponent()); 835 836 if(childIndex == -1 || 837 childIndex >= node.getChildCount() || 838 (onlyIfVisible && !node.isVisible())) { 839 node = null; 840 } 841 else 842 node = (TreeStateNode)node.getChildAt 843 (childIndex); 844 } 845 return node; 846 } 847 paths.push(path); 848 path = path.getParentPath(); 849 } 850 } 851 finally { 852 paths.removeAllElements(); 853 tempStacks.push(paths); 854 } 855 } 858 return null; 859 } 860 861 865 private void updateYLocationsFrom(int location) { 866 if(location >= 0 && location < getRowCount()) { 867 int counter, maxCounter, newYOrigin; 868 TreeStateNode aNode; 869 870 aNode = getNode(location); 871 newYOrigin = aNode.getYOrigin() + aNode.getPreferredHeight(); 872 for(counter = location + 1, maxCounter = visibleNodes.size(); 873 counter < maxCounter;counter++) { 874 aNode = (TreeStateNode)visibleNodes. 875 elementAt(counter); 876 aNode.setYOrigin(newYOrigin); 877 newYOrigin += aNode.getPreferredHeight(); 878 } 879 } 880 } 881 882 890 private void updateNodeSizes(boolean updateAll) { 891 int aY, counter, maxCounter; 892 TreeStateNode node; 893 894 updateNodeSizes = false; 895 for(aY = counter = 0, maxCounter = visibleNodes.size(); 896 counter < maxCounter; counter++) { 897 node = (TreeStateNode)visibleNodes.elementAt(counter); 898 node.setYOrigin(aY); 899 if(updateAll || !node.hasValidSize()) 900 node.updatePreferredSize(counter); 901 aY += node.getPreferredHeight(); 902 } 903 } 904 905 910 private int getRowContainingYLocation(int location) { 911 if(isFixedRowHeight()) { 912 if(getRowCount() == 0) 913 return -1; 914 return Math.max(0, Math.min(getRowCount() - 1, 915 location / getRowHeight())); 916 } 917 918 int max, maxY, mid, min, minY; 919 TreeStateNode node; 920 921 if((max = getRowCount()) <= 0) 922 return -1; 923 mid = min = 0; 924 while(min < max) { 925 mid = (max - min) / 2 + min; 926 node = (TreeStateNode)visibleNodes.elementAt(mid); 927 minY = node.getYOrigin(); 928 maxY = minY + node.getPreferredHeight(); 929 if(location < minY) { 930 max = mid - 1; 931 } 932 else if(location >= maxY) { 933 min = mid + 1; 934 } 935 else 936 break; 937 } 938 if(min == max) { 939 mid = min; 940 if(mid >= getRowCount()) 941 mid = getRowCount() - 1; 942 } 943 return mid; 944 } 945 946 952 private void ensurePathIsExpanded(TreePath aPath, boolean expandLast) { 953 if(aPath != null) { 954 if(treeModel.isLeaf(aPath.getLastPathComponent())) { 956 aPath = aPath.getParentPath(); 957 expandLast = true; 958 } 959 if(aPath != null) { 960 TreeStateNode lastNode = getNodeForPath(aPath, false, 961 true); 962 963 if(lastNode != null) { 964 lastNode.makeVisible(); 965 if(expandLast) 966 lastNode.expand(); 967 } 968 } 969 } 970 } 971 972 975 private TreeStateNode getNode(int row) { 976 return (TreeStateNode)visibleNodes.elementAt(row); 977 } 978 979 982 private int getMaxNodeWidth() { 983 int maxWidth = 0; 984 int nodeWidth; 985 int counter; 986 TreeStateNode node; 987 988 for(counter = getRowCount() - 1;counter >= 0;counter--) { 989 node = this.getNode(counter); 990 nodeWidth = node.getPreferredWidth() + node.getXOrigin(); 991 if(nodeWidth > maxWidth) 992 maxWidth = nodeWidth; 993 } 994 return maxWidth; 995 } 996 997 1001 private TreeStateNode createNodeForValue(Object value) { 1002 return new TreeStateNode(value); 1003 } 1004 1005 1006 1011 private class TreeStateNode extends DefaultMutableTreeNode { 1012 1013 protected int preferredWidth; 1014 protected int preferredHeight; 1015 1016 1017 protected int xOrigin; 1018 1019 1020 protected int yOrigin; 1021 1022 1023 protected boolean expanded; 1024 1025 1026 protected boolean hasBeenExpanded; 1027 1028 1029 protected TreePath path; 1030 1031 1032 public TreeStateNode(Object value) { 1033 super(value); 1034 } 1035 1036 1040 1044 public void setParent(MutableTreeNode parent) { 1045 super.setParent(parent); 1046 if(parent != null) { 1047 path = ((TreeStateNode)parent).getTreePath(). 1048 pathByAddingChild(getUserObject()); 1049 addMapping(this); 1050 } 1051 } 1052 1053 1057 public void remove(int childIndex) { 1058 TreeStateNode node = (TreeStateNode)getChildAt(childIndex); 1059 1060 node.removeFromMapping(); 1061 super.remove(childIndex); 1062 } 1063 1064 1067 public void setUserObject(Object o) { 1068 super.setUserObject(o); 1069 if(path != null) { 1070 TreeStateNode parent = (TreeStateNode)getParent(); 1071 1072 if(parent != null) 1073 resetChildrenPaths(parent.getTreePath()); 1074 else 1075 resetChildrenPaths(null); 1076 } 1077 } 1078 1079 1084 public Enumeration children() { 1085 if (!this.isExpanded()) { 1086 return DefaultMutableTreeNode.EMPTY_ENUMERATION; 1087 } else { 1088 return super.children(); 1089 } 1090 } 1091 1092 1095 public boolean isLeaf() { 1096 return getModel().isLeaf(this.getValue()); 1097 } 1098 1099 1103 1106 public Rectangle getNodeBounds(Rectangle placeIn) { 1107 if(placeIn == null) 1108 placeIn = new Rectangle (getXOrigin(), getYOrigin(), 1109 getPreferredWidth(), 1110 getPreferredHeight()); 1111 else { 1112 placeIn.x = getXOrigin(); 1113 placeIn.y = getYOrigin(); 1114 placeIn.width = getPreferredWidth(); 1115 placeIn.height = getPreferredHeight(); 1116 } 1117 return placeIn; 1118 } 1119 1120 1123 public int getXOrigin() { 1124 if(!hasValidSize()) 1125 updatePreferredSize(getRow()); 1126 return xOrigin; 1127 } 1128 1129 1132 public int getYOrigin() { 1133 if(isFixedRowHeight()) { 1134 int aRow = getRow(); 1135 1136 if(aRow == -1) 1137 return -1; 1138 return getRowHeight() * aRow; 1139 } 1140 return yOrigin; 1141 } 1142 1143 1146 public int getPreferredHeight() { 1147 if(isFixedRowHeight()) 1148 return getRowHeight(); 1149 else if(!hasValidSize()) 1150 updatePreferredSize(getRow()); 1151 return preferredHeight; 1152 } 1153 1154 1157 public int getPreferredWidth() { 1158 if(!hasValidSize()) 1159 updatePreferredSize(getRow()); 1160 return preferredWidth; 1161 } 1162 1163 1166 public boolean hasValidSize() { 1167 return (preferredHeight != 0); 1168 } 1169 1170 1173 public int getRow() { 1174 return visibleNodes.indexOf(this); 1175 } 1176 1177 1180 public boolean hasBeenExpanded() { 1181 return hasBeenExpanded; 1182 } 1183 1184 1187 public boolean isExpanded() { 1188 return expanded; 1189 } 1190 1191 1195 public TreeStateNode getLastVisibleNode() { 1196 TreeStateNode node = this; 1197 1198 while(node.isExpanded() && node.getChildCount() > 0) 1199 node = (TreeStateNode)node.getLastChild(); 1200 return node; 1201 } 1202 1203 1206 public boolean isVisible() { 1207 if(this == root) 1208 return true; 1209 1210 TreeStateNode parent = (TreeStateNode)getParent(); 1211 1212 return (parent != null && parent.isExpanded() && 1213 parent.isVisible()); 1214 } 1215 1216 1220 public int getModelChildCount() { 1221 if(hasBeenExpanded) 1222 return super.getChildCount(); 1223 return getModel().getChildCount(getValue()); 1224 } 1225 1226 1230 public int getVisibleChildCount() { 1231 int childCount = 0; 1232 1233 if(isExpanded()) { 1234 int maxCounter = getChildCount(); 1235 1236 childCount += maxCounter; 1237 for(int counter = 0; counter < maxCounter; counter++) 1238 childCount += ((TreeStateNode)getChildAt(counter)). 1239 getVisibleChildCount(); 1240 } 1241 return childCount; 1242 } 1243 1244 1247 public void toggleExpanded() { 1248 if (isExpanded()) { 1249 collapse(); 1250 } else { 1251 expand(); 1252 } 1253 } 1254 1255 1259 public void makeVisible() { 1260 TreeStateNode parent = (TreeStateNode)getParent(); 1261 1262 if(parent != null) 1263 parent.expandParentAndReceiver(); 1264 } 1265 1266 1269 public void expand() { 1270 expand(true); 1271 } 1272 1273 1276 public void collapse() { 1277 collapse(true); 1278 } 1279 1280 1284 public Object getValue() { 1285 return getUserObject(); 1286 } 1287 1288 1291 public TreePath getTreePath() { 1292 return path; 1293 } 1294 1295 1299 1302 protected void resetChildrenPaths(TreePath parentPath) { 1303 removeMapping(this); 1304 if(parentPath == null) 1305 path = new TreePath (getUserObject()); 1306 else 1307 path = parentPath.pathByAddingChild(getUserObject()); 1308 addMapping(this); 1309 for(int counter = getChildCount() - 1; counter >= 0; counter--) 1310 ((TreeStateNode)getChildAt(counter)).resetChildrenPaths(path); 1311 } 1312 1313 1317 protected void setYOrigin(int newYOrigin) { 1318 yOrigin = newYOrigin; 1319 } 1320 1321 1324 protected void shiftYOriginBy(int offset) { 1325 yOrigin += offset; 1326 } 1327 1328 1332 protected void updatePreferredSize() { 1333 updatePreferredSize(getRow()); 1334 } 1335 1336 1341 protected void updatePreferredSize(int index) { 1342 Rectangle bounds = getNodeDimensions(this.getUserObject(), 1343 index, getLevel(), 1344 isExpanded(), 1345 boundsBuffer); 1346 1347 if(bounds == null) { 1348 xOrigin = 0; 1349 preferredWidth = preferredHeight = 0; 1350 updateNodeSizes = true; 1351 } 1352 else if(bounds.height == 0) { 1353 xOrigin = 0; 1354 preferredWidth = preferredHeight = 0; 1355 updateNodeSizes = true; 1356 } 1357 else { 1358 xOrigin = bounds.x; 1359 preferredWidth = bounds.width; 1360 if(isFixedRowHeight()) 1361 preferredHeight = getRowHeight(); 1362 else 1363 preferredHeight = bounds.height; 1364 } 1365 } 1366 1367 1371 protected void markSizeInvalid() { 1372 preferredHeight = 0; 1373 } 1374 1375 1378 protected void deepMarkSizeInvalid() { 1379 markSizeInvalid(); 1380 for(int counter = getChildCount() - 1; counter >= 0; counter--) 1381 ((TreeStateNode)getChildAt(counter)).deepMarkSizeInvalid(); 1382 } 1383 1384 1390 protected Enumeration getLoadedChildren(boolean createIfNeeded) { 1391 if(!createIfNeeded || hasBeenExpanded) 1392 return super.children(); 1393 1394 TreeStateNode newNode; 1395 Object realNode = getValue(); 1396 TreeModel treeModel = getModel(); 1397 int count = treeModel.getChildCount(realNode); 1398 1399 hasBeenExpanded = true; 1400 1401 int childRow = getRow(); 1402 1403 if(childRow == -1) { 1404 for (int i = 0; i < count; i++) { 1405 newNode = createNodeForValue 1406 (treeModel.getChild(realNode, i)); 1407 this.add(newNode); 1408 newNode.updatePreferredSize(-1); 1409 } 1410 } 1411 else { 1412 childRow++; 1413 for (int i = 0; i < count; i++) { 1414 newNode = createNodeForValue 1415 (treeModel.getChild(realNode, i)); 1416 this.add(newNode); 1417 newNode.updatePreferredSize(childRow++); 1418 } 1419 } 1420 return super.children(); 1421 } 1422 1423 1427 protected void didAdjustTree() { 1428 } 1429 1430 1434 protected void expandParentAndReceiver() { 1435 TreeStateNode parent = (TreeStateNode)getParent(); 1436 1437 if(parent != null) 1438 parent.expandParentAndReceiver(); 1439 expand(); 1440 } 1441 1442 1448 protected void expand(boolean adjustTree) { 1449 if (!isExpanded() && !isLeaf()) { 1450 boolean isFixed = isFixedRowHeight(); 1451 int startHeight = getPreferredHeight(); 1452 int originalRow = getRow(); 1453 1454 expanded = true; 1455 updatePreferredSize(originalRow); 1456 1457 if (!hasBeenExpanded) { 1458 TreeStateNode newNode; 1459 Object realNode = getValue(); 1460 TreeModel treeModel = getModel(); 1461 int count = treeModel.getChildCount(realNode); 1462 1463 hasBeenExpanded = true; 1464 if(originalRow == -1) { 1465 for (int i = 0; i < count; i++) { 1466 newNode = createNodeForValue(treeModel.getChild 1467 (realNode, i)); 1468 this.add(newNode); 1469 newNode.updatePreferredSize(-1); 1470 } 1471 } 1472 else { 1473 int offset = originalRow + 1; 1474 for (int i = 0; i < count; i++) { 1475 newNode = createNodeForValue(treeModel.getChild 1476 (realNode, i)); 1477 this.add(newNode); 1478 newNode.updatePreferredSize(offset); 1479 } 1480 } 1481 } 1482 1483 int i = originalRow; 1484 Enumeration cursor = preorderEnumeration(); 1485 cursor.nextElement(); 1487 int newYOrigin; 1488 1489 if(isFixed) 1490 newYOrigin = 0; 1491 else if(this == root && !isRootVisible()) 1492 newYOrigin = 0; 1493 else 1494 newYOrigin = getYOrigin() + this.getPreferredHeight(); 1495 TreeStateNode aNode; 1496 if(!isFixed) { 1497 while (cursor.hasMoreElements()) { 1498 aNode = (TreeStateNode)cursor.nextElement(); 1499 if(!updateNodeSizes && !aNode.hasValidSize()) 1500 aNode.updatePreferredSize(i + 1); 1501 aNode.setYOrigin(newYOrigin); 1502 newYOrigin += aNode.getPreferredHeight(); 1503 visibleNodes.insertElementAt(aNode, ++i); 1504 } 1505 } 1506 else { 1507 while (cursor.hasMoreElements()) { 1508 aNode = (TreeStateNode)cursor.nextElement(); 1509 visibleNodes.insertElementAt(aNode, ++i); 1510 } 1511 } 1512 1513 if(adjustTree && (originalRow != i || 1514 getPreferredHeight() != startHeight)) { 1515 if(!isFixed && ++i < getRowCount()) { 1517 int counter; 1518 int heightDiff = newYOrigin - 1519 (getYOrigin() + getPreferredHeight()) + 1520 (getPreferredHeight() - startHeight); 1521 1522 for(counter = visibleNodes.size() - 1;counter >= i; 1523 counter--) 1524 ((TreeStateNode)visibleNodes.elementAt(counter)). 1525 shiftYOriginBy(heightDiff); 1526 } 1527 didAdjustTree(); 1528 visibleNodesChanged(); 1529 } 1530 1531 if(treeSelectionModel != null) { 1533 treeSelectionModel.resetRowSelection(); 1534 } 1535 } 1536 } 1537 1538 1542 protected void collapse(boolean adjustTree) { 1543 if (isExpanded()) { 1544 Enumeration cursor = preorderEnumeration(); 1545 cursor.nextElement(); int rowsDeleted = 0; 1547 boolean isFixed = isFixedRowHeight(); 1548 int lastYEnd; 1549 if(isFixed) 1550 lastYEnd = 0; 1551 else 1552 lastYEnd = getPreferredHeight() + getYOrigin(); 1553 int startHeight = getPreferredHeight(); 1554 int startYEnd = lastYEnd; 1555 int myRow = getRow(); 1556 1557 if(!isFixed) { 1558 while(cursor.hasMoreElements()) { 1559 TreeStateNode node = (TreeStateNode)cursor. 1560 nextElement(); 1561 if (node.isVisible()) { 1562 rowsDeleted++; 1563 lastYEnd = node.getYOrigin() + 1565 node.getPreferredHeight(); 1566 } 1567 } 1568 } 1569 else { 1570 while(cursor.hasMoreElements()) { 1571 TreeStateNode node = (TreeStateNode)cursor. 1572 nextElement(); 1573 if (node.isVisible()) { 1574 rowsDeleted++; 1575 } 1577 } 1578 } 1579 1580 for (int counter = rowsDeleted + myRow; counter > myRow; 1582 counter--) { 1583 visibleNodes.removeElementAt(counter); 1584 } 1585 1586 expanded = false; 1587 1588 if(myRow == -1) 1589 markSizeInvalid(); 1590 else if (adjustTree) 1591 updatePreferredSize(myRow); 1592 1593 if(myRow != -1 && adjustTree && 1594 (rowsDeleted > 0 || startHeight != getPreferredHeight())) { 1595 startYEnd += (getPreferredHeight() - startHeight); 1597 if(!isFixed && (myRow + 1) < getRowCount() && 1598 startYEnd != lastYEnd) { 1599 int counter, maxCounter, shiftAmount; 1600 1601 shiftAmount = startYEnd - lastYEnd; 1602 for(counter = myRow + 1, maxCounter = 1603 visibleNodes.size(); 1604 counter < maxCounter;counter++) 1605 ((TreeStateNode)visibleNodes.elementAt(counter)) 1606 .shiftYOriginBy(shiftAmount); 1607 } 1608 didAdjustTree(); 1609 visibleNodesChanged(); 1610 } 1611 if(treeSelectionModel != null && rowsDeleted > 0 && 1612 myRow != -1) { 1613 treeSelectionModel.resetRowSelection(); 1614 } 1615 } 1616 } 1617 1618 1622 protected void removeFromMapping() { 1623 if(path != null) { 1624 removeMapping(this); 1625 for(int counter = getChildCount() - 1; counter >= 0; counter--) 1626 ((TreeStateNode)getChildAt(counter)).removeFromMapping(); 1627 } 1628 } 1629 } 1631 1632 1635 private class VisibleTreeStateNodeEnumeration implements 1636 Enumeration <TreePath > { 1637 1638 protected TreeStateNode parent; 1639 1641 protected int nextIndex; 1642 1643 protected int childCount; 1644 1645 protected VisibleTreeStateNodeEnumeration(TreeStateNode node) { 1646 this(node, -1); 1647 } 1648 1649 protected VisibleTreeStateNodeEnumeration(TreeStateNode parent, 1650 int startIndex) { 1651 this.parent = parent; 1652 this.nextIndex = startIndex; 1653 this.childCount = this.parent.getChildCount(); 1654 } 1655 1656 1659 public boolean hasMoreElements() { 1660 return (parent != null); 1661 } 1662 1663 1666 public TreePath nextElement() { 1667 if(!hasMoreElements()) 1668 throw new NoSuchElementException ("No more visible paths"); 1669 1670 TreePath retObject; 1671 1672 if(nextIndex == -1) { 1673 retObject = parent.getTreePath(); 1674 } 1675 else { 1676 TreeStateNode node = (TreeStateNode)parent. 1677 getChildAt(nextIndex); 1678 1679 retObject = node.getTreePath(); 1680 } 1681 updateNextObject(); 1682 return retObject; 1683 } 1684 1685 1689 protected void updateNextObject() { 1690 if(!updateNextIndex()) { 1691 findNextValidParent(); 1692 } 1693 } 1694 1695 1699 protected boolean findNextValidParent() { 1700 if(parent == root) { 1701 parent = null; 1703 return false; 1704 } 1705 while(parent != null) { 1706 TreeStateNode newParent = (TreeStateNode)parent. 1707 getParent(); 1708 1709 if(newParent != null) { 1710 nextIndex = newParent.getIndex(parent); 1711 parent = newParent; 1712 childCount = parent.getChildCount(); 1713 if(updateNextIndex()) 1714 return true; 1715 } 1716 else 1717 parent = null; 1718 } 1719 return false; 1720 } 1721 1722 1726 protected boolean updateNextIndex() { 1727 if(nextIndex == -1 && !parent.isExpanded()) 1730 return false; 1731 1732 if(childCount == 0) 1734 return false; 1735 else if(++nextIndex >= childCount) 1737 return false; 1738 1739 TreeStateNode child = (TreeStateNode)parent. 1740 getChildAt(nextIndex); 1741 1742 if(child != null && child.isExpanded()) { 1743 parent = child; 1744 nextIndex = -1; 1745 childCount = child.getChildCount(); 1746 } 1747 return true; 1748 } 1749 } } 1751 | Popular Tags |