908 int aY, counter, maxCounter;
909 TreeStateNode node;
910
911 updateNodeSizes = false;
912 for(aY = counter = 0, maxCounter = visibleNodes.size();
913 counter < maxCounter; counter++) {
914 node = (TreeStateNode)visibleNodes.elementAt(counter);
915 node.setYOrigin(aY);
916 if(updateAll || !node.hasValidSize())
917 node.updatePreferredSize(counter);
918 aY += node.getPreferredHeight();
919 }
920 }
921
922 /**
923 * Returns the index of the row containing location. If there
924 * are no rows, -1 is returned. If location is beyond the last
925 * row index, the last row index is returned.
926 */
927 private int getRowContainingYLocation(int location) {
928 if(isFixedRowHeight()) {
929 if(getRowCount() == 0)
930 return -1;
931 return Math.max(0, Math.min(getRowCount() - 1,
932 location / getRowHeight()));
933 }
934
935 int max, maxY, mid, min, minY;
936 TreeStateNode node;
937
938 if((max = getRowCount()) <= 0)
939 return -1;
940 mid = min = 0;
941 while(min < max) {
942 mid = (max - min) / 2 + min;
943 node = (TreeStateNode)visibleNodes.elementAt(mid);
944 minY = node.getYOrigin();
945 maxY = minY + node.getPreferredHeight();
946 if(location < minY) {
947 max = mid - 1;
948 }
949 else if(location >= maxY) {
950 min = mid + 1;
951 }
952 else
953 break;
954 }
955 if(min == max) {
956 mid = min;
957 if(mid >= getRowCount())
958 mid = getRowCount() - 1;
959 }
960 return mid;
961 }
962
963 /**
964 * Ensures that all the path components in path are expanded, accept
965 * for the last component which will only be expanded if expandLast
966 * is true.
967 * Returns true if succesful in finding the path.
968 */
969 private void ensurePathIsExpanded(TreePath aPath, boolean expandLast) {
970 if(aPath != null) {
971 // Make sure the last entry isn't a leaf.
972 if(treeModel.isLeaf(aPath.getLastPathComponent())) {
973 aPath = aPath.getParentPath();
974 expandLast = true;
975 }
976 if(aPath != null) {
977 TreeStateNode lastNode = getNodeForPath(aPath, false,
978 true);
991 */
992 private TreeStateNode getNode(int row) {
993 return (TreeStateNode)visibleNodes.elementAt(row);
994 }
995
996 /**
997 * Returns the maximum node width.
998 */
999 private int getMaxNodeWidth() {
1000 int maxWidth = 0;
1001 int nodeWidth;
1002 int counter;
1003 TreeStateNode node;
1004
1005 for(counter = getRowCount() - 1;counter >= 0;counter--) {
1006 node = this.getNode(counter);
1007 nodeWidth = node.getPreferredWidth() + node.getXOrigin();
1008 if(nodeWidth > maxWidth)
1009 maxWidth = nodeWidth;
1010 }
1011 return maxWidth;
1012 }
1013
1014 /**
1015 * Responsible for creating a TreeStateNode that will be used
1016 * to track display information about value.
1017 */
1018 private TreeStateNode createNodeForValue(Object value) {
1019 return new TreeStateNode(value);
1020 }
1021
1022
1023 /**
1024 * TreeStateNode is used to keep track of each of
1025 * the nodes that have been expanded. This will also cache the preferred
1026 * size of the value it represents.
1027 */
1028 private class TreeStateNode extends DefaultMutableTreeNode {
1029 /** Preferred size needed to draw the user object. */
1030 protected int preferredWidth;
1031 protected int preferredHeight;
1032
1033 /** X location that the user object will be drawn at. */
1345
1346 /**
1347 * Updates the receivers preferredSize by invoking
1348 * <code>updatePreferredSize</code> with an argument of -1.
1349 */
1350 protected void updatePreferredSize() {
1351 updatePreferredSize(getRow());
1352 }
1353
1354 /**
1355 * Updates the preferred size by asking the current renderer
1356 * for the Dimension needed to draw the user object this
1357 * instance represents.
1358 */
1359 protected void updatePreferredSize(int index) {
1360 Rectangle bounds = getNodeDimensions(this.getUserObject(),
1361 index, getLevel(),
1362 isExpanded(),
1363 boundsBuffer);
1364
1365 if(bounds == null) {
1366 xOrigin = 0;
1367 preferredWidth = preferredHeight = 0;
1368 updateNodeSizes = true;
1369 }
1370 else if(bounds.height == 0) {
1371 xOrigin = 0;
1372 preferredWidth = preferredHeight = 0;
1373 updateNodeSizes = true;
1374 }
1375 else {
1376 xOrigin = bounds.x;
1377 preferredWidth = bounds.width;
1378 if(isFixedRowHeight())
1379 preferredHeight = getRowHeight();
1380 else
1381 preferredHeight = bounds.height;
1382 }
1383 }
1384
1385 /**
1386 * Marks the receivers size as invalid. Next time the size, location
1387 * is asked for it will be obtained.
1388 */
1389 protected void markSizeInvalid() {
1390 preferredHeight = 0;
1391 }
1392
1393 /**
1394 * Marks the receivers size, and all its descendants sizes, as invalid.
1395 */
1460 /**
1461 * Expands this node in the tree. This will load the children
1462 * from the treeModel if this node has not previously been
1463 * expanded. If <I>adjustTree</I> is true the tree and selection
1464 * are updated accordingly.
1465 */
1466 protected void expand(boolean adjustTree) {
1467 if (!isExpanded() && !isLeaf()) {
1468 boolean isFixed = isFixedRowHeight();
1469 int startHeight = getPreferredHeight();
1470 int originalRow = getRow();
1471
1472 expanded = true;
1473 updatePreferredSize(originalRow);
1474
1475 if (!hasBeenExpanded) {
1476 TreeStateNode newNode;
1477 Object realNode = getValue();
1478 TreeModel treeModel = getModel();
1479 int count = treeModel.getChildCount(realNode);
1480
1481 hasBeenExpanded = true;
1482 if(originalRow == -1) {
1483 for (int i = 0; i < count; i++) {
1484 newNode = createNodeForValue(treeModel.getChild
1485 (realNode, i));
1486 this.add(newNode);
1487 newNode.updatePreferredSize(-1);
1488 }
1489 }
1490 else {
1491 int offset = originalRow + 1;
1492 for (int i = 0; i < count; i++) {
1493 newNode = createNodeForValue(treeModel.getChild
1494 (realNode, i));
1495 this.add(newNode);
1496 newNode.updatePreferredSize(offset);
1497 }
1498 }
1499 }
1500
1501 int i = originalRow;
1502 Enumeration<TreeNode> cursor = preorderEnumeration();
1503 cursor.nextElement(); // don't add me, I'm already in
1504
1505 int newYOrigin;
1506
1507 if(isFixed)
1508 newYOrigin = 0;
1509 else if(this == root && !isRootVisible())
1510 newYOrigin = 0;
1511 else
1512 newYOrigin = getYOrigin() + this.getPreferredHeight();
1513 TreeStateNode aNode;
1514 if(!isFixed) {
1515 while (cursor.hasMoreElements()) {
1516 aNode = (TreeStateNode) cursor.nextElement();
1517 if(!updateNodeSizes && !aNode.hasValidSize())
1518 aNode.updatePreferredSize(i + 1);
1519 aNode.setYOrigin(newYOrigin);
1520 newYOrigin += aNode.getPreferredHeight();
1521 visibleNodes.insertElementAt(aNode, ++i);
1522 }
1523 }
1524 else {
1525 while (cursor.hasMoreElements()) {
1526 aNode = (TreeStateNode) cursor.nextElement();
1527 visibleNodes.insertElementAt(aNode, ++i);
1528 }
1529 }
1530
1531 if(adjustTree && (originalRow != i ||
1532 getPreferredHeight() != startHeight)) {
1727 if(newParent != null) {
1728 nextIndex = newParent.getIndex(parent);
1729 parent = newParent;
1730 childCount = parent.getChildCount();
1731 if(updateNextIndex())
1732 return true;
1733 }
1734 else
1735 parent = null;
1736 }
1737 return false;
1738 }
1739
1740 /**
1741 * Updates <code>nextIndex</code> returning false if it is beyond
1742 * the number of children of parent.
1743 */
1744 protected boolean updateNextIndex() {
1745 // nextIndex == -1 identifies receiver, make sure is expanded
1746 // before descend.
1747 if(nextIndex == -1 && !parent.isExpanded())
1748 return false;
1749
1750 // Check that it can have kids
1751 if(childCount == 0)
1752 return false;
1753 // Make sure next index not beyond child count.
1754 else if(++nextIndex >= childCount)
1755 return false;
1756
1757 TreeStateNode child = (TreeStateNode)parent.
1758 getChildAt(nextIndex);
1759
1760 if(child != null && child.isExpanded()) {
1761 parent = child;
1762 nextIndex = -1;
1763 childCount = child.getChildCount();
1764 }
1765 return true;
1766 }
1767 } // VariableHeightLayoutCache.VisibleTreeStateNodeEnumeration
1768 }
|
908 int aY, counter, maxCounter;
909 TreeStateNode node;
910
911 updateNodeSizes = false;
912 for(aY = counter = 0, maxCounter = visibleNodes.size();
913 counter < maxCounter; counter++) {
914 node = (TreeStateNode)visibleNodes.elementAt(counter);
915 node.setYOrigin(aY);
916 if(updateAll || !node.hasValidSize())
917 node.updatePreferredSize(counter);
918 aY += node.getPreferredHeight();
919 }
920 }
921
922 /**
923 * Returns the index of the row containing location. If there
924 * are no rows, -1 is returned. If location is beyond the last
925 * row index, the last row index is returned.
926 */
927 private int getRowContainingYLocation(int location) {
928 final int rows = getRowCount();
929
930 if(rows <= 0)
931 return -1;
932 if(isFixedRowHeight()) {
933 return Math.max(0, Math.min(rows - 1,
934 location / getRowHeight()));
935 }
936
937 int max = rows, min = 0, mid = 0;
938
939 while(min < max) {
940 mid = (max - min) / 2 + min;
941 TreeStateNode node = (TreeStateNode)visibleNodes.elementAt(mid);
942 int minY = node.getYOrigin();
943 int maxY = minY + node.getPreferredHeight();
944 if(location < minY) {
945 max = mid - 1;
946 }
947 else if(location >= maxY) {
948 min = mid + 1;
949 }
950 else
951 break;
952 }
953 if(min == max) {
954 mid = min;
955 if(mid >= rows)
956 mid = rows - 1;
957 }
958 return mid;
959 }
960
961 /**
962 * Ensures that all the path components in path are expanded, accept
963 * for the last component which will only be expanded if expandLast
964 * is true.
965 * Returns true if succesful in finding the path.
966 */
967 private void ensurePathIsExpanded(TreePath aPath, boolean expandLast) {
968 if(aPath != null) {
969 // Make sure the last entry isn't a leaf.
970 if(treeModel.isLeaf(aPath.getLastPathComponent())) {
971 aPath = aPath.getParentPath();
972 expandLast = true;
973 }
974 if(aPath != null) {
975 TreeStateNode lastNode = getNodeForPath(aPath, false,
976 true);
989 */
990 private TreeStateNode getNode(int row) {
991 return (TreeStateNode)visibleNodes.elementAt(row);
992 }
993
994 /**
995 * Returns the maximum node width.
996 */
997 private int getMaxNodeWidth() {
998 int maxWidth = 0;
999 int nodeWidth;
1000 int counter;
1001 TreeStateNode node;
1002
1003 for(counter = getRowCount() - 1;counter >= 0;counter--) {
1004 node = this.getNode(counter);
1005 nodeWidth = node.getPreferredWidth() + node.getXOrigin();
1006 if(nodeWidth > maxWidth)
1007 maxWidth = nodeWidth;
1008 }
1009
1010 return maxWidth;
1011 }
1012 /**
1013 * Responsible for creating a TreeStateNode that will be used
1014 * to track display information about value.
1015 */
1016 private TreeStateNode createNodeForValue(Object value) {
1017 return new TreeStateNode(value);
1018 }
1019
1020
1021 /**
1022 * TreeStateNode is used to keep track of each of
1023 * the nodes that have been expanded. This will also cache the preferred
1024 * size of the value it represents.
1025 */
1026 private class TreeStateNode extends DefaultMutableTreeNode {
1027 /** Preferred size needed to draw the user object. */
1028 protected int preferredWidth;
1029 protected int preferredHeight;
1030
1031 /** X location that the user object will be drawn at. */
1343
1344 /**
1345 * Updates the receivers preferredSize by invoking
1346 * <code>updatePreferredSize</code> with an argument of -1.
1347 */
1348 protected void updatePreferredSize() {
1349 updatePreferredSize(getRow());
1350 }
1351
1352 /**
1353 * Updates the preferred size by asking the current renderer
1354 * for the Dimension needed to draw the user object this
1355 * instance represents.
1356 */
1357 protected void updatePreferredSize(int index) {
1358 Rectangle bounds = getNodeDimensions(this.getUserObject(),
1359 index, getLevel(),
1360 isExpanded(),
1361 boundsBuffer);
1362
1363 if(bounds == null || bounds.height == 0) {
1364 xOrigin = 0;
1365 preferredWidth = preferredHeight = 0;
1366 updateNodeSizes = true;
1367 } else {
1368 xOrigin = bounds.x;
1369 preferredWidth = bounds.width;
1370 if(isFixedRowHeight())
1371 preferredHeight = getRowHeight();
1372 else
1373 preferredHeight = bounds.height;
1374 }
1375 }
1376
1377 /**
1378 * Marks the receivers size as invalid. Next time the size, location
1379 * is asked for it will be obtained.
1380 */
1381 protected void markSizeInvalid() {
1382 preferredHeight = 0;
1383 }
1384
1385 /**
1386 * Marks the receivers size, and all its descendants sizes, as invalid.
1387 */
1452 /**
1453 * Expands this node in the tree. This will load the children
1454 * from the treeModel if this node has not previously been
1455 * expanded. If <I>adjustTree</I> is true the tree and selection
1456 * are updated accordingly.
1457 */
1458 protected void expand(boolean adjustTree) {
1459 if (!isExpanded() && !isLeaf()) {
1460 boolean isFixed = isFixedRowHeight();
1461 int startHeight = getPreferredHeight();
1462 int originalRow = getRow();
1463
1464 expanded = true;
1465 updatePreferredSize(originalRow);
1466
1467 if (!hasBeenExpanded) {
1468 TreeStateNode newNode;
1469 Object realNode = getValue();
1470 TreeModel treeModel = getModel();
1471 int count = treeModel.getChildCount(realNode);
1472 int offset = originalRow == -1 ? -1 : originalRow + 1;
1473 hasBeenExpanded = true;
1474
1475 for (int i = 0; i < count; i++) {
1476 newNode = createNodeForValue(treeModel.getChild
1477 (realNode, i));
1478 this.add(newNode);
1479 newNode.updatePreferredSize(offset);
1480 }
1481 }
1482
1483 int i = originalRow;
1484 Enumeration<TreeNode> cursor = preorderEnumeration();
1485 cursor.nextElement(); // don't add me, I'm already in
1486
1487 int newYOrigin = isFixed || (this == root && !isRootVisible()) ?
1488 0 : getYOrigin() + this.getPreferredHeight();
1489
1490 TreeStateNode aNode;
1491 if(!isFixed) {
1492 while (cursor.hasMoreElements()) {
1493 aNode = (TreeStateNode) cursor.nextElement();
1494 if(!updateNodeSizes && !aNode.hasValidSize())
1495 aNode.updatePreferredSize(i + 1);
1496 aNode.setYOrigin(newYOrigin);
1497 newYOrigin += aNode.getPreferredHeight();
1498 visibleNodes.insertElementAt(aNode, ++i);
1499 }
1500 }
1501 else {
1502 while (cursor.hasMoreElements()) {
1503 aNode = (TreeStateNode) cursor.nextElement();
1504 visibleNodes.insertElementAt(aNode, ++i);
1505 }
1506 }
1507
1508 if(adjustTree && (originalRow != i ||
1509 getPreferredHeight() != startHeight)) {
1704 if(newParent != null) {
1705 nextIndex = newParent.getIndex(parent);
1706 parent = newParent;
1707 childCount = parent.getChildCount();
1708 if(updateNextIndex())
1709 return true;
1710 }
1711 else
1712 parent = null;
1713 }
1714 return false;
1715 }
1716
1717 /**
1718 * Updates <code>nextIndex</code> returning false if it is beyond
1719 * the number of children of parent.
1720 */
1721 protected boolean updateNextIndex() {
1722 // nextIndex == -1 identifies receiver, make sure is expanded
1723 // before descend.
1724 if((nextIndex == -1 && !parent.isExpanded()) ||
1725 childCount == 0 || // Check that it can have kids
1726 ++nextIndex >= childCount) // Make sure next index not beyond
1727 // child count.
1728 return false;
1729
1730 TreeStateNode child = (TreeStateNode)parent.
1731 getChildAt(nextIndex);
1732
1733 if(child != null && child.isExpanded()) {
1734 parent = child;
1735 nextIndex = -1;
1736 childCount = child.getChildCount();
1737 }
1738 return true;
1739 }
1740 } // VariableHeightLayoutCache.VisibleTreeStateNodeEnumeration
1741 }
|