Index: javax/swing/plaf/basic/BasicTreeUI.java =================================================================== RCS file: /cvsroot/classpath/classpath/javax/swing/plaf/basic/BasicTreeUI.java,v retrieving revision 1.110 diff -u -r1.110 BasicTreeUI.java --- javax/swing/plaf/basic/BasicTreeUI.java 14 Nov 2005 20:40:41 -0000 1.110 +++ javax/swing/plaf/basic/BasicTreeUI.java 15 Nov 2005 19:37:03 -0000 @@ -239,9 +239,6 @@ /** Boolean to keep track of editing. */ boolean isEditing; - /** The bounds of the current cell. */ - Rectangle bounds; - /** The current path of the visible nodes in the tree. */ TreePath currentVisiblePath; @@ -624,21 +621,19 @@ */ public Rectangle getPathBounds(JTree tree, TreePath path) { + Rectangle bounds = null; + int row = -1; + Object cell = null; if (path != null) { - Object cell = path.getLastPathComponent(); - - if (treeModel != null) - { - Object root = treeModel.getRoot(); - - if (!tree.isRootVisible() && tree.isExpanded(new TreePath(root))) - root = getNextNode(root); - Point loc = getCellLocation(0, 0, tree, treeModel, cell, root); - return getCellBounds(loc.x, loc.y, cell); - } - } - return null; + row = getRowForPath(tree, path); + cell = path.getLastPathComponent(); + bounds = new Rectangle(0, row * getRowHeight(), 0, 0); + } + return nodeDimensions.getNodeDimensions(cell, row, + getLevel(cell), + tree.isExpanded(path), + bounds); } /** @@ -700,7 +695,6 @@ */ public int getRowCount(JTree tree) { - updateCurrentVisiblePath(); if (currentVisiblePath != null) return currentVisiblePath.getPathCount(); return 0; @@ -1035,7 +1029,9 @@ */ protected void uninstallKeyboardActions() { - // TODO: Implement this properly. + action = null; + tree.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).setParent(null); + tree.getActionMap().setParent(null); } /** @@ -1409,14 +1405,30 @@ JTree tree = (JTree) c; if (currentVisiblePath == null) updateCurrentVisiblePath(); - - if (currentVisiblePath != null && treeModel != null) + + Rectangle clip = g.getClipBounds(); + Insets insets = tree.getInsets(); + + if (clip != null && treeModel != null) { - Object root = treeModel.getRoot(); - paintRecursive(g, 0, 0, 0, tree, treeModel, root); - - if (hasControlIcons()) - paintControlIcons(g, 0, 0, 0, tree, treeModel, root); + int startIndex = tree.getClosestRowForLocation(clip.x, clip.y); + int endIndex = tree.getClosestRowForLocation(clip.x + clip.width, + clip.y + clip.height); + + paintVerticalPartOfLeg(g, clip, insets, currentVisiblePath); + for (int i = startIndex; i <= endIndex; i++) + { + Object curr = currentVisiblePath.getPathComponent(i); + boolean isLeaf = treeModel.isLeaf(curr); + TreePath path = new TreePath(getPathToRoot(curr, 0)); + + boolean isExpanded = tree.isExpanded(path); + Rectangle bounds = getPathBounds(tree, path); + paintHorizontalPartOfLeg(g, clip, insets, bounds, path, i, + isExpanded, false, isLeaf); + paintRow(g, clip, insets, bounds, path, i, isExpanded, false, + isLeaf); + } } } @@ -2268,6 +2280,7 @@ handleExpandControlClick(path, click.x, click.y); if (cellEditor != null) cellEditor.cancelCellEditing(); + tree.scrollPathToVisible(path); } else if (tree.isEditable()) startEditing(path, e); @@ -2451,9 +2464,12 @@ } /** - * Responsible for getting the size of a particular node. + * Returns, by reference in bounds, the size and x origin to place value at. + * The calling method is responsible for determining the Y location. + * If bounds is null, a newly created Rectangle should be returned, + * otherwise the value should be placed in bounds and returned. * - * @param value + * @param cell * the value to be represented * @param row * row being queried @@ -2465,10 +2481,23 @@ * a Rectangle containing the size needed to represent value * @return containing the node dimensions, or null if node has no dimension */ - public Rectangle getNodeDimensions(Object value, int row, int depth, + public Rectangle getNodeDimensions(Object cell, int row, int depth, boolean expanded, Rectangle size) { - return null; + if (size == null || cell == null) + return null; + + String s = cell.toString(); + Font f = tree.getFont(); + FontMetrics fm = tree.getToolkit().getFontMetrics(f); + + if (s != null) + { + size.x = getRowX(row, depth); + size.width = SwingUtilities.computeStringWidth(fm, s); + size.height = fm.getHeight(); + } + return size; } /** @@ -2478,7 +2507,9 @@ */ protected int getRowX(int row, int depth) { - return 0; + if (row == 0) + return 0; + return depth * rightChildIndent; } }// NodeDimensionsHandler @@ -3057,241 +3088,6 @@ } /** - * Returns the cell bounds for painting selected cells Package private for use - * in inner classes. - * - * @param x - * is the x location of the cell - * @param y - * is the y location of the cell - * @param cell - * is the Object to get the bounds for - * @returns Rectangle that represents the cell bounds - */ - Rectangle getCellBounds(int x, int y, Object cell) - { - if (cell != null) - { - String s = cell.toString(); - Font f = tree.getFont(); - FontMetrics fm = tree.getToolkit().getFontMetrics(f); - - if (s != null) - return new Rectangle(x, y, SwingUtilities.computeStringWidth(fm, s), - fm.getHeight()); - } - return new Rectangle(x, y, 0, 0); - } - - /** - * Retrieves the location of some node, recursively starting at from some - * node. Package private for use in inner classes. - * - * @param x - * is the starting x position, offset - * @param y - * is the starting y position, offset - * @param tree - * is the tree to traverse - * @param mod - * is the TreeModel to use - * @param node - * is the node to get the location for - * @param startNode - * is the node to start searching from - * @return Point - the location of node - */ - Point getCellLocation(int x, int y, JTree tree, TreeModel mod, Object node, - Object startNode) - { - int rowHeight = getRowHeight(); - if (startNode == null || startNode.equals(node)) - { - int level = getLevel(node); - if (level == 0) - return new Point(x, y); - if (!tree.isRootVisible() && - tree.isExpanded(new TreePath(mod.getRoot()))) - return new Point(x + ((level - 1) * rightChildIndent), y); - return new Point(x + (level * rightChildIndent), y); - } - return getCellLocation(x, y + rowHeight, tree, mod, node, - getNextVisibleNode(startNode)); - } - - /** - * Recursively paints all elements of the tree Package private for use in - * inner classes. - * - * @param g - * the Graphics context in which to paint - * @param indentation - * of the current object - * @param descent - * is the number of elements drawn - * @param depth - * is the depth of the current object in the tree - * @param tree - * is the tree to draw to - * @param mod - * is the TreeModel we are using to draw - * @param curr - * is the current object to draw - * @return int - current descent of the tree - */ - int paintRecursive(Graphics g, int indentation, int descent, - int depth, JTree tree, TreeModel mod, Object curr) - { - Rectangle clip = tree.getVisibleRect(); - if (indentation > clip.x + clip.width + rightChildIndent - || descent > clip.y + clip.height + getRowHeight()) - return descent; - - TreePath path = new TreePath(getPathToRoot(curr, 0)); - int halfHeight = getRowHeight() / 2; - int halfWidth = rightChildIndent / 2; - int y0 = descent + halfHeight; - int heightOfLine = descent + halfHeight; - int row = getRowForPath(tree, path); - boolean isRootVisible = tree.isRootVisible(); - boolean isExpanded = tree.isExpanded(path); - boolean isLeaf = mod.isLeaf(curr); - Rectangle bounds = getPathBounds(tree, path); - Object root = mod.getRoot(); - - if (isLeaf) - { - paintRow(g, clip, null, bounds, path, row, true, false, true); - descent += getRowHeight(); - } - else - { - if (depth > 0 || isRootVisible) - { - paintRow(g, clip, null, bounds, path, row, isExpanded, false, false); - descent += getRowHeight(); - y0 += halfHeight; - } - - if (isExpanded) - { - int max = mod.getChildCount(curr); - for (int i = 0; i < max; i++) - { - Object child = mod.getChild(curr, i); - boolean childVis = tree.isVisible(new TreePath - (getPathToRoot(child, 0))); - int indent = indentation + rightChildIndent; - if (!isRootVisible && depth == 0) - indent = 0; - else if (isRootVisible || - (!isRootVisible && !curr.equals(root)) && childVis) - { - g.setColor(getHashColor()); - heightOfLine = descent + halfHeight; - paintHorizontalLine(g, (JComponent) tree, heightOfLine, - indentation + halfWidth, indentation + rightChildIndent); - } - - descent = paintRecursive(g, indent, descent, depth + 1, - tree, mod, child); - } - } - } - - if (isExpanded) - if (y0 != heightOfLine - && (mod.getChildCount(curr) > 0 && - tree.isVisible(new TreePath(getPathToRoot(mod.getChild - (curr, 0), 0))))) - { - g.setColor(getHashColor()); - paintVerticalLine(g, (JComponent) tree, indentation + halfWidth, y0, - heightOfLine); - } - return descent; - } - - /** - * Recursively paints all the control icons on the tree. Package private for - * use in inner classes. - * - * @param g - * the Graphics context in which to paint - * @param indentation - * of the current object - * @param descent - * is the number of elements drawn - * @param depth - * is the depth of the current object in the tree - * @param tree - * is the tree to draw to - * @param mod - * is the TreeModel we are using to draw - * @param node - * is the current object to draw - * @return int current descent of the tree - */ - int paintControlIcons(Graphics g, int indentation, int descent, - int depth, JTree tree, TreeModel mod, - Object node) - { - int rowHeight = getRowHeight(); - TreePath path = new TreePath(getPathToRoot(node, 0)); - Icon icon = getCurrentControlIcon(path); - - Rectangle clip = tree.getVisibleRect(); - if (indentation > clip.x + clip.width + rightChildIndent - || descent > clip.y + clip.height + getRowHeight()) - return descent; - - if (mod.isLeaf(node)) - descent += rowHeight; - else - { - if (!node.equals(mod.getRoot()) && - (tree.isRootVisible() || getLevel(node) != 1)) - { - int width = icon.getIconWidth(); - int height = icon.getIconHeight() + 2; - int posX = indentation - rightChildIndent; - int posY = descent; - if (width > rightChildIndent) - posX -= gap; - else posX += width/2; - - if (height < rowHeight) - posY += height/2; - - icon.paintIcon(tree, g, posX, posY); - } - - if (depth > 0 || tree.isRootVisible()) - descent += rowHeight; - - if (tree.isExpanded(path)) - { - int max = 0; - if (!mod.isLeaf(node)) - max = mod.getChildCount(node); - - for (int i = 0; i < max; i++) - { - int indent = indentation + rightChildIndent; - Object child = mod.getChild(node, i); - if (depth == 0 && !tree.isRootVisible()) - indent = 1; - if (tree.isVisible(new TreePath(getPathToRoot(child, 0)))) - descent = paintControlIcons(g, indent, descent, depth + 1, - tree, mod, child); - } - } - } - - return descent; - } - - /** * Returns true if the LookAndFeel implements the control icons. Package * private for use in inner classes. * @@ -3376,7 +3172,6 @@ */ Object getPreviousVisibleNode(Object node) { - updateCurrentVisiblePath(); if (currentVisiblePath != null) { Object[] nodes = currentVisiblePath.getPath(); @@ -3568,16 +3363,22 @@ int getLevel(Object node) { int count = -1; - + Object current = node; - do + if (treeModel != null) { - current = getParent(treeModel.getRoot(), current); - count++; + Object root = treeModel.getRoot(); + if (!tree.isRootVisible() && tree.isExpanded(new TreePath(root))) + count--; + + do + { + current = getParent(root, current); + count++; + } + while (current != null); } - while (current != null); - return count; } @@ -3598,6 +3399,8 @@ protected void paintVerticalLine(Graphics g, JComponent c, int x, int top, int bottom) { + // FIXME: Check if drawing a dashed line or not. + g.setColor(getHashColor()); g.drawLine(x, top, x, bottom); } @@ -3618,6 +3421,8 @@ protected void paintHorizontalLine(Graphics g, JComponent c, int y, int left, int right) { + // FIXME: Check if drawing a dashed line or not. + g.setColor(getHashColor()); g.drawLine(left, y, right, y); } @@ -3633,14 +3438,19 @@ * @param x * is the center position in x-direction * @param y - * is the center position in y-direction FIXME what to do if x < - * (icon.width / 2). Same with y + * is the center position in y-direction */ protected void drawCentered(Component c, Graphics g, Icon icon, int x, int y) { - int beginPositionX = x - icon.getIconWidth() / 2; - int beginPositionY = y - icon.getIconHeight() / 2; - icon.paintIcon(c, g, beginPositionX, beginPositionY); + x -= icon.getIconWidth() / 2; + y -= icon.getIconHeight() / 2; + + if (x < 0) + x = 0; + if (y < 0) + y = 0; + + icon.paintIcon(c, g, x, y); } /** @@ -3653,6 +3463,7 @@ */ protected void drawDashedHorizontalLine(Graphics g, int y, int x1, int x2) { + g.setColor(getHashColor()); for (int i = x1; i < x2; i += 2) g.drawLine(i, y, i + 1, y); } @@ -3667,6 +3478,7 @@ */ protected void drawDashedVerticalLine(Graphics g, int x, int y1, int y2) { + g.setColor(getHashColor()); for (int i = y1; i < y2; i += 2) g.drawLine(x, i, x, i + 1); } @@ -3691,8 +3503,15 @@ boolean isExpanded, boolean hasBeenExpanded, boolean isLeaf) { - if (treeModel != null && hasControlIcons()) - paintControlIcons(g, 0, 0, 0, tree, treeModel, path.getLastPathComponent()); + if (shouldPaintExpandControl(path, row, isExpanded, hasBeenExpanded, isLeaf)) + { + Icon icon = getCurrentControlIcon(path); + int iconW = icon.getIconWidth(); + int x = bounds.x - rightChildIndent + iconW/2; + if (x + iconW > bounds.x) + x = bounds.x - rightChildIndent - gap; + icon.paintIcon(tree, g, x, bounds.y + bounds.height/2 - icon.getIconHeight()/2); + } } /** @@ -3703,9 +3522,9 @@ * @param g - the graphics configuration * @param clipBounds - * @param insets - - * @param bounds - bounds of expand control - * @param path - path to draw control for - * @param row - row to draw control for + * @param bounds - bounds of the cell + * @param path - path to draw leg for + * @param row - row to start drawing at * @param isExpanded - is the row expanded * @param hasBeenExpanded - has the row already been expanded * @param isLeaf - is the path a leaf @@ -3716,7 +3535,9 @@ boolean isExpanded, boolean hasBeenExpanded, boolean isLeaf) { - // FIXME: not implemented + if (row != 0) + paintHorizontalLine(g, tree, bounds.y + bounds.height/2, bounds.x - gap - 2, + bounds.x); } /** @@ -3731,7 +3552,24 @@ protected void paintVerticalPartOfLeg(Graphics g, Rectangle clipBounds, Insets insets, TreePath path) { - // FIXME: not implemented + int max = tree.getVisibleRowCount(); + for (int i = 0; i < max; i++) + { + Object curr = path.getPathComponent(i); + TreePath currPath = new TreePath(getPathToRoot(curr, 0)); + if (!treeModel.isLeaf(curr) && tree.isExpanded(currPath)) + { + Rectangle bounds = getPathBounds(tree, currPath); + Rectangle lastChildBounds = getPathBounds(tree, + new TreePath(getPathToRoot( + treeModel.getChild(curr, + treeModel.getChildCount(curr) - 1), + 0))); + paintVerticalLine(g, tree, bounds.x + gap + 2, bounds.y + + bounds.height - 2, lastChildBounds.y + + lastChildBounds.height/2); + } + } } /** @@ -3762,7 +3600,12 @@ { if (!validCachedPreferredSize) updateCachedPreferredSize(); - bounds.x += gap; + + + paintExpandControl(g, clipBounds, insets, bounds, path, row, isExpanded, hasBeenExpanded, isLeaf); + + if (row != 0) + bounds.x += gap; bounds.width = preferredSize.width + bounds.x; if (editingComponent != null && editingPath != null && isEditing(tree) @@ -3808,10 +3651,7 @@ boolean isLeaf) { Object node = path.getLastPathComponent(); - if (treeModel != null && (!isLeaf && !node.equals(treeModel.getRoot())) && - (tree.isRootVisible() || getLevel(node) != 1)) - return true; - return false; + return (!isLeaf && getLevel(node) != 0); } /** @@ -3824,24 +3664,28 @@ return; Object next = treeModel.getRoot(); - Rectangle bounds = getCellBounds(0, 0, next); - boolean rootVisible = isRootVisible(); + TreePath rootPath = new TreePath(next); + Rectangle bounds = getPathBounds(tree, rootPath); // If root is not a valid size to be visible, or is // not visible and the tree is expanded, then the next node acts // as the root - if ((bounds.width == 0 && bounds.height == 0) || (!rootVisible + if ((bounds.width == 0 && bounds.height == 0) || (!isRootVisible() && tree.isExpanded(new TreePath(next)))) + { next = getNextNode(next); + rootPath = new TreePath(next); + } Object root = next; TreePath current = null; while (next != null) { if (current == null) - current = new TreePath(next); - else - current = current.pathByAddingChild(next); + current = rootPath; + else + current = current.pathByAddingChild(next); + do { TreePath path = new TreePath(getPathToRoot(next, 0)); @@ -3860,7 +3704,7 @@ { next = getNextSibling(parent); if (next == null) - parent = getParent(treeModel.getRoot(), next); + parent = getParent(root, parent); } } } @@ -3870,9 +3714,7 @@ } currentVisiblePath = current; - if (currentVisiblePath != null) - tree.setVisibleRowCount(currentVisiblePath.getPathCount()); - else tree.setVisibleRowCount(0); + tree.setVisibleRowCount(getRowCount(tree)); if (tree.getSelectionModel() != null && tree.getSelectionCount() == 0 && currentVisiblePath != null)