diff options
Diffstat (limited to 'libjava/classpath/javax/swing/plaf/basic/BasicTreeUI.java')
-rw-r--r-- | libjava/classpath/javax/swing/plaf/basic/BasicTreeUI.java | 1327 |
1 files changed, 819 insertions, 508 deletions
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicTreeUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTreeUI.java index 6f714a39cb2..e967cd424fc 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicTreeUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicTreeUI.java @@ -44,6 +44,7 @@ import java.awt.Dimension; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; +import java.awt.Insets; import java.awt.Point; import java.awt.Rectangle; import java.awt.event.ActionEvent; @@ -62,6 +63,7 @@ import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.util.Enumeration; import java.util.Hashtable; import javax.swing.AbstractAction; @@ -76,6 +78,7 @@ import javax.swing.JScrollPane; import javax.swing.JTextField; import javax.swing.JTree; import javax.swing.KeyStroke; +import javax.swing.LookAndFeel; import javax.swing.SwingUtilities; import javax.swing.Timer; import javax.swing.UIDefaults; @@ -89,6 +92,7 @@ import javax.swing.event.TreeModelEvent; import javax.swing.event.TreeModelListener; import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; +import javax.swing.plaf.ActionMapUIResource; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.InputMapUIResource; import javax.swing.plaf.TreeUI; @@ -96,7 +100,6 @@ import javax.swing.text.Caret; import javax.swing.tree.AbstractLayoutCache; import javax.swing.tree.DefaultTreeCellEditor; import javax.swing.tree.DefaultTreeCellRenderer; -import javax.swing.tree.ExpandVetoException; import javax.swing.tree.FixedHeightLayoutCache; import javax.swing.tree.TreeCellEditor; import javax.swing.tree.TreeCellRenderer; @@ -110,11 +113,11 @@ import javax.swing.tree.TreeSelectionModel; * the Basic look and feel. * * @see javax.swing.JTree - * @author Sascha Brawer (brawer@dandelis.ch) + * * @author Lillian Angel (langel@redhat.com) + * @author Sascha Brawer (brawer@dandelis.ch) */ -public class BasicTreeUI - extends TreeUI +public class BasicTreeUI extends TreeUI { /** Collapse Icon for the tree. */ protected transient Icon collapsedIcon; @@ -136,9 +139,6 @@ public class BasicTreeUI */ protected int totalChildIndent; - /** Minimum preferred size. */ - protected Dimension preferredMinsize; - /** Index of the row that was last selected. */ protected int lastSelectedRow; @@ -174,6 +174,9 @@ public class BasicTreeUI /** Size needed to completely display all the nodes. */ protected Dimension preferredSize; + + /** Minimum size needed to completely display all the nodes. */ + protected Dimension preferredMinSize; /** Is the preferredSize valid? */ protected boolean validCachedPreferredSize; @@ -223,38 +226,38 @@ public class BasicTreeUI /** Set to true if the editor has a different size than the renderer. */ protected boolean editorHasDifferentSize; - + /** The action listener for the editor's Timer. */ - private Timer editorTimer = new EditorUpdateTimer(); + Timer editorTimer = new EditorUpdateTimer(); /** The new value of the node after editing. */ - private Object newVal; + Object newVal; /** The action bound to KeyStrokes. */ - private TreeAction action; + TreeAction action; /** Boolean to keep track of editing. */ - private boolean isEditing; + boolean isEditing; + + /** The bounds of the current cell. */ + Rectangle bounds; + + /** The current path of the visible nodes in the tree. */ + TreePath currentVisiblePath; + + /** The gap between the icon and text. */ + int gap = 4; /** Listeners */ private PropertyChangeListener propertyChangeListener; - private FocusListener focusListener; - private TreeSelectionListener treeSelectionListener; - - private MouseInputListener mouseInputListener; - + private MouseListener mouseListener; private KeyListener keyListener; - private PropertyChangeListener selectionModelPropertyChangeListener; - private ComponentListener componentListener; - - private CellEditorListener cellEditorListener; - + CellEditorListener cellEditorListener; private TreeExpansionListener treeExpansionListener; - private TreeModelListener treeModelListener; /** @@ -262,6 +265,7 @@ public class BasicTreeUI */ public BasicTreeUI() { + validCachedPreferredSize = false; drawingCache = new Hashtable(); nodeDimensions = createNodeDimensions(); configureLayoutCache(); @@ -269,7 +273,7 @@ public class BasicTreeUI propertyChangeListener = createPropertyChangeListener(); focusListener = createFocusListener(); treeSelectionListener = createTreeSelectionListener(); - mouseInputListener = new MouseInputHandler(null, null, null); + mouseListener = createMouseListener(); keyListener = createKeyListener(); selectionModelPropertyChangeListener = createSelectionModelPropertyChangeListener(); componentListener = createComponentListener(); @@ -331,7 +335,7 @@ public class BasicTreeUI * * @return the indent value for the left child. */ - public int getLeftChildIndent(int newAmount) + public int getLeftChildIndent() { return leftChildIndent; } @@ -456,7 +460,6 @@ public class BasicTreeUI protected void setCellRenderer(TreeCellRenderer tcr) { currentCellRenderer = tcr; - tree.setCellRenderer(tcr); updateRenderer(); } @@ -625,14 +628,13 @@ public class BasicTreeUI { Object cell = path.getLastPathComponent(); - TreeModel mod = tree.getModel(); - if (mod != null) + if (treeModel != null) { - Object root = mod.getRoot(); + Object root = treeModel.getRoot(); + if (!tree.isRootVisible() && tree.isExpanded(new TreePath(root))) root = getNextNode(root); - - Point loc = getCellLocation(0, 0, tree, mod, cell, root); + Point loc = getCellLocation(0, 0, tree, treeModel, cell, root); return getCellBounds(loc.x, loc.y, cell); } } @@ -650,21 +652,11 @@ public class BasicTreeUI */ public TreePath getPathForRow(JTree tree, int row) { - TreeModel mod = tree.getModel(); - if (mod != null) + if (treeModel != null && currentVisiblePath != null) { - Object node = mod.getRoot(); - if (!tree.isRootVisible() - && tree.isExpanded(new TreePath(getPathToRoot(node, 0)))) - node = getNextNode(node); - - for (int i = 0; i < row; i++) - node = getNextVisibleNode(node); - - if (node == null) - return null; - - return new TreePath(getPathToRoot(node, 0)); + Object[] nodes = currentVisiblePath.getPath(); + if (row < nodes.length) + return new TreePath(getPathToRoot(nodes[row], 0)); } return null; } @@ -683,17 +675,20 @@ public class BasicTreeUI */ public int getRowForPath(JTree tree, TreePath path) { - int row = path.getPathCount(); - if (tree.isVisible(path)) - return row; - - path = path.getParentPath(); - while (row > 0 && !tree.isVisible(path)) + int row = 0; + Object dest = path.getLastPathComponent(); + int rowCount = getRowCount(tree); + if (currentVisiblePath != null) { - path = path.getParentPath(); - row--; + Object[] nodes = currentVisiblePath.getPath(); + while (row < rowCount) + { + if (dest.equals(nodes[row])) + return row; + row++; + } } - return row; + return -1; } /** @@ -705,22 +700,10 @@ public class BasicTreeUI */ public int getRowCount(JTree tree) { - TreeModel mod = tree.getModel(); - int count = 0; - if (mod != null) - { - Object node = mod.getRoot(); - if (!tree.isRootVisible() - && tree.isExpanded(new TreePath((getPathToRoot(node, 0))))) - node = getNextNode(node); - - while (node != null) - { - count++; - node = getNextVisibleNode(node); - } - } - return count; + updateCurrentVisiblePath(); + if (currentVisiblePath != null) + return currentVisiblePath.getPathCount(); + return 0; } /** @@ -739,9 +722,6 @@ public class BasicTreeUI */ public TreePath getClosestPathForLocation(JTree tree, int x, int y) { - // FIXME: what if root is hidden? should not depend on (0,0) - // should start counting rows from where root is. - int row = Math.round(y / getRowHeight()); TreePath path = getPathForRow(tree, row); @@ -828,7 +808,7 @@ public class BasicTreeUI */ protected void prepareForUIInstall() { - // FIXME: not implemented + // TODO: Implement this properly. } /** @@ -837,7 +817,7 @@ public class BasicTreeUI */ protected void completeUIInstall() { - // FIXME: not implemented + // TODO: Implement this properly. } /** @@ -846,7 +826,7 @@ public class BasicTreeUI */ protected void completeUIUninstall() { - // FIXME: not implemented + // TODO: Implement this properly. } /** @@ -854,7 +834,10 @@ public class BasicTreeUI */ protected void installComponents() { - // FIXME: not implemented + currentCellRenderer = createDefaultCellRenderer(); + rendererPane = createCellRendererPane(); + createdRenderer = true; + setCellRenderer(currentCellRenderer); } /** @@ -865,8 +848,7 @@ public class BasicTreeUI */ protected AbstractLayoutCache.NodeDimensions createNodeDimensions() { - // FIXME: not implemented - return null; + return new NodeDimensionsHandler(); } /** @@ -1035,7 +1017,7 @@ public class BasicTreeUI tree.removePropertyChangeListener(propertyChangeListener); tree.removeFocusListener(focusListener); tree.removeTreeSelectionListener(treeSelectionListener); - tree.removeMouseListener(mouseInputListener); + tree.removeMouseListener(mouseListener); tree.removeKeyListener(keyListener); tree.removePropertyChangeListener(selectionModelPropertyChangeListener); tree.removeComponentListener(componentListener); @@ -1044,9 +1026,8 @@ public class BasicTreeUI TreeCellEditor tce = tree.getCellEditor(); if (tce != null) tce.removeCellEditorListener(cellEditorListener); - TreeModel tm = tree.getModel(); - if (tm != null) - tm.removeTreeModelListener(treeModelListener); + if (treeModel != null) + treeModel.removeTreeModelListener(treeModelListener); } /** @@ -1054,6 +1035,7 @@ public class BasicTreeUI */ protected void uninstallKeyboardActions() { + // TODO: Implement this properly. } /** @@ -1061,7 +1043,10 @@ public class BasicTreeUI */ protected void uninstallComponents() { - // FIXME: not implemented + currentCellRenderer = null; + rendererPane = null; + createdRenderer = false; + setCellRenderer(currentCellRenderer); } /** @@ -1072,8 +1057,7 @@ public class BasicTreeUI */ protected int getVerticalLegBuffer() { - // FIXME: not implemented - return 0; + return getRowHeight() / 2; } /** @@ -1085,17 +1069,17 @@ public class BasicTreeUI */ protected int getHorizontalLegBuffer() { - // FIXME: not implemented - return 0; + return rightChildIndent / 2; } /** * Make all the nodes that are expanded in JTree expanded in LayoutCache. This - * invokes update ExpandedDescendants with the root path. + * invokes updateExpandedDescendants with the root path. */ protected void updateLayoutCacheExpandedNodes() { - // FIXME: not implemented + if (treeModel != null) + updateExpandedDescendants(new TreePath(treeModel.getRoot())); } /** @@ -1108,7 +1092,9 @@ public class BasicTreeUI */ protected void updateExpandedDescendants(TreePath path) { - // FIXME: not implemented + Enumeration expanded = tree.getExpandedDescendants(path); + while (expanded.hasMoreElements()) + treeState.setExpandedState(((TreePath) expanded.nextElement()), true); } /** @@ -1128,7 +1114,7 @@ public class BasicTreeUI */ protected void updateDepthOffset() { - // FIXME: not implemented + depthOffset += getVerticalLegBuffer(); } /** @@ -1148,7 +1134,15 @@ public class BasicTreeUI */ protected void updateRenderer() { - // FIXME: not implemented + if (tree != null) + { + if(tree.getCellRenderer() == null) + { + if(currentCellRenderer == null) + currentCellRenderer = createDefaultCellRenderer(); + tree.setCellRenderer(currentCellRenderer); + } + } } /** @@ -1166,19 +1160,36 @@ public class BasicTreeUI */ protected void updateSize() { - // FIXME: not implemented + preferredSize = null; + updateCachedPreferredSize(); + tree.treeDidChange(); } /** * Updates the <code>preferredSize</code> instance variable, which is - * returned from <code>getPreferredSize()</code>. For left to right - * orientations, the size is determined from the current AbstractLayoutCache. - * For RTL orientations, the preferred size becomes the width minus the - * minimum x position. + * returned from <code>getPreferredSize()</code>. */ protected void updateCachedPreferredSize() { - // FIXME: not implemented + int maxWidth = 0; + boolean isLeaf = false; + if (currentVisiblePath != null) + { + Object[] path = currentVisiblePath.getPath(); + for (int i = 0; i < path.length; i++) + { + TreePath curr = new TreePath(getPathToRoot(path[i], 0)); + Rectangle bounds = getPathBounds(tree, curr); + if (treeModel != null) + isLeaf = treeModel.isLeaf(path[i]); + if (!isLeaf && hasControlIcons()) + bounds.width += getCurrentControlIcon(curr).getIconWidth(); + maxWidth = Math.max(maxWidth, bounds.x + bounds.width); + } + preferredSize = new Dimension(maxWidth, (getRowHeight() * path.length)); + } + else preferredSize = new Dimension(0, 0); + validCachedPreferredSize = true; } /** @@ -1189,7 +1200,9 @@ public class BasicTreeUI */ protected void pathWasExpanded(TreePath path) { - // FIXME: not implemented + validCachedPreferredSize = false; + tree.revalidate(); + tree.repaint(); } /** @@ -1197,28 +1210,28 @@ public class BasicTreeUI */ protected void pathWasCollapsed(TreePath path) { - // FIXME: not implemented + validCachedPreferredSize = false; + tree.revalidate(); + tree.repaint(); } /** * Install all defaults for the tree. - * - * @param tree - * is the JTree to install defaults for */ - protected void installDefaults(JTree tree) + protected void installDefaults() { - UIDefaults defaults = UIManager.getLookAndFeelDefaults(); - - tree.setFont(defaults.getFont("Tree.font")); - tree.setForeground(defaults.getColor("Tree.foreground")); - tree.setBackground(defaults.getColor("Tree.background")); + LookAndFeel.installColorsAndFont(tree, "Tree.background", + "Tree.foreground", "Tree.font"); tree.setOpaque(true); - rightChildIndent = defaults.getInt("Tree.rightChildIndent"); - leftChildIndent = defaults.getInt("Tree.leftChildIndent"); - setRowHeight(defaults.getInt("Tree.rowHeight")); + rightChildIndent = UIManager.getInt("Tree.rightChildIndent"); + leftChildIndent = UIManager.getInt("Tree.leftChildIndent"); + setRowHeight(UIManager.getInt("Tree.rowHeight")); + tree.setRowHeight(UIManager.getInt("Tree.rowHeight")); tree.requestFocusInWindow(false); + tree.setScrollsOnExpand(UIManager.getBoolean("Tree.scrollsOnExpand")); + setExpandedIcon(UIManager.getIcon("Tree.expandedIcon")); + setCollapsedIcon(UIManager.getIcon("Tree.collapsedIcon")); } /** @@ -1229,7 +1242,7 @@ public class BasicTreeUI UIDefaults defaults = UIManager.getLookAndFeelDefaults(); InputMap focusInputMap = (InputMap) defaults.get("Tree.focusInputMap"); InputMapUIResource parentInputMap = new InputMapUIResource(); - ActionMap parentActionMap = new ActionMap(); + ActionMap parentActionMap = new ActionMapUIResource(); action = new TreeAction(); Object keys[] = focusInputMap.allKeys(); @@ -1308,7 +1321,7 @@ public class BasicTreeUI tree.addPropertyChangeListener(propertyChangeListener); tree.addFocusListener(focusListener); tree.addTreeSelectionListener(treeSelectionListener); - tree.addMouseListener(mouseInputListener); + tree.addMouseListener(mouseListener); tree.addKeyListener(keyListener); tree.addPropertyChangeListener(selectionModelPropertyChangeListener); tree.addComponentListener(componentListener); @@ -1325,37 +1338,36 @@ public class BasicTreeUI */ public void installUI(JComponent c) { - super.installUI(c); - installDefaults((JTree) c); tree = (JTree) c; + prepareForUIInstall(); + super.installUI(c); + installDefaults(); - currentCellRenderer = createDefaultCellRenderer(); - rendererPane = createCellRendererPane(); - createdRenderer = true; - + installComponents(); + installKeyboardActions(); + installListeners(); + setCellEditor(createDefaultCellEditor()); createdCellEditor = true; isEditing = false; - + TreeModel mod = tree.getModel(); setModel(mod); - tree.setRootVisible(true); if (mod != null) - tree.expandPath(new TreePath(mod.getRoot())); + { + TreePath path = new TreePath(mod.getRoot()); + if (!tree.isExpanded(path)) + toggleExpandState(path); + } treeSelectionModel = tree.getSelectionModel(); - installKeyboardActions(); - installListeners(); completeUIInstall(); } /** * Uninstall the defaults for the tree - * - * @param tree - * to uninstall defaults for */ - protected void uninstallDefaults(JTree tree) + protected void uninstallDefaults() { tree.setFont(null); tree.setForeground(null); @@ -1370,10 +1382,12 @@ public class BasicTreeUI */ public void uninstallUI(JComponent c) { - uninstallDefaults((JTree) c); + prepareForUIUninstall(); + uninstallDefaults(); uninstallKeyboardActions(); uninstallListeners(); tree = null; + uninstallComponents(); completeUIUninstall(); } @@ -1393,20 +1407,16 @@ public class BasicTreeUI public void paint(Graphics g, JComponent c) { JTree tree = (JTree) c; - - TreeModel mod = tree.getModel(); - - if (mod != null) + if (currentVisiblePath == null) + updateCurrentVisiblePath(); + + if (currentVisiblePath != null && treeModel != null) { - Object root = mod.getRoot(); - - if (!tree.isRootVisible()) - tree.expandPath(new TreePath(root)); - - paintRecursive(g, 0, 0, 0, 0, tree, mod, root); - + Object root = treeModel.getRoot(); + paintRecursive(g, 0, 0, 0, tree, treeModel, root); + if (hasControlIcons()) - paintControlIcons(g, 0, 0, 0, 0, tree, mod, root); + paintControlIcons(g, 0, 0, 0, tree, treeModel, root); } } @@ -1420,7 +1430,19 @@ public class BasicTreeUI */ protected void ensureRowsAreVisible(int beginRow, int endRow) { - // FIXME: not implemented + if (beginRow < endRow) + { + int temp = endRow; + endRow = beginRow; + beginRow = temp; + } + + for (int i = beginRow; i < endRow; i++) + { + TreePath path = getPathForRow(tree, i); + if (!tree.isVisible(path)) + tree.makeVisible(path); + } } /** @@ -1431,7 +1453,7 @@ public class BasicTreeUI */ public void setPreferredMinSize(Dimension newSize) { - // FIXME: not implemented + preferredMinSize = newSize; } /** @@ -1441,8 +1463,7 @@ public class BasicTreeUI */ public Dimension getPreferredMinSize() { - // FIXME: not implemented - return null; + return preferredMinSize; } /** @@ -1472,28 +1493,10 @@ public class BasicTreeUI */ public Dimension getPreferredSize(JComponent c, boolean checkConsistancy) { - // FIXME: checkConsistancy not implemented, c not used - TreeModel model = tree.getModel(); - int maxWidth = 0; - int count = 0; - if (model != null) - { - Object node = model.getRoot(); - if (node != null) - { - maxWidth = (int) (getCellBounds(0, 0, node).getWidth()); - while (node != null) - { - count++; - Object nextNode = getNextVisibleNode(node); - if (nextNode != null) - maxWidth = Math.max(maxWidth, - (int) (getCellBounds(0, 0, nextNode).getWidth())); - node = nextNode; - } - } - } - return new Dimension(maxWidth, (getRowHeight() * count)); + // FIXME: checkConsistancy not implemented, c not used + if(!validCachedPreferredSize) + updateCachedPreferredSize(); + return preferredSize; } /** @@ -1506,8 +1509,10 @@ public class BasicTreeUI */ public Dimension getMinimumSize(JComponent c) { - // FIXME: not implemented - return getPreferredSize(c); + Dimension min = getPreferredMinSize(); + if (min == null) + return new Dimension(); + return min; } /** @@ -1520,8 +1525,9 @@ public class BasicTreeUI */ public Dimension getMaximumSize(JComponent c) { - // FIXME: not implemented - return getPreferredSize(c); + if (c instanceof JTree) + return ((JTree) c).getPreferredSize(); + return new Dimension(); } /** @@ -1565,7 +1571,7 @@ public class BasicTreeUI } if (messageTree) - tree.getModel().valueForPathChanged(tree.getLeadSelectionPath(), newVal); + treeModel.valueForPathChanged(tree.getLeadSelectionPath(), newVal); } /** @@ -1584,7 +1590,7 @@ public class BasicTreeUI int y; if (event == null) { - Rectangle bounds = getPathBounds(tree, path); + bounds = getPathBounds(tree, path); x = bounds.x; y = bounds.y; } @@ -1600,6 +1606,7 @@ public class BasicTreeUI { editingPath = path; editingRow = tree.getRowForPath(editingPath); + Object val = editingPath.getLastPathComponent(); cellEditor.addCellEditorListener(cellEditorListener); stopEditingInCompleteEditing = false; @@ -1613,6 +1620,8 @@ public class BasicTreeUI editingComponent.getParent().validate(); tree.add(editingComponent.getParent()); editingComponent.getParent().validate(); + validCachedPreferredSize = false; + tree.revalidate(); ((JTextField) editingComponent).requestFocusInWindow(false); editorTimer.start(); return true; @@ -1634,7 +1643,8 @@ public class BasicTreeUI protected void checkForClickInExpandControl(TreePath path, int mouseX, int mouseY) { - // FIXME: not implemented + if (isLocationInExpandControl(path, mouseX, mouseY)) + toggleExpandState(path); } /** @@ -1655,8 +1665,18 @@ public class BasicTreeUI protected boolean isLocationInExpandControl(TreePath path, int mouseX, int mouseY) { - // FIXME: not implemented - return false; + boolean cntlClick = false; + int row = getRowForPath(tree, path); + + if (!isLeaf(row)) + { + bounds = getPathBounds(tree, path); + + if (hasControlIcons() && (mouseX < bounds.x) + && (mouseX > (bounds.x - getCurrentControlIcon(path).getIconWidth() - gap))) + cntlClick = true; + } + return cntlClick; } /** @@ -1672,7 +1692,7 @@ public class BasicTreeUI */ protected void handleExpandControlClick(TreePath path, int mouseX, int mouseY) { - // FIXME: not implemented + toggleExpandState(path); } /** @@ -1686,7 +1706,11 @@ public class BasicTreeUI */ protected void toggleExpandState(TreePath path) { - // FIXME: not implemented + if (tree.isExpanded(path)) + tree.collapsePath(path); + else + tree.expandPath(path); + updateCurrentVisiblePath(); } /** @@ -1700,8 +1724,8 @@ public class BasicTreeUI */ protected boolean isToggleSelectionEvent(MouseEvent event) { - // FIXME: not implemented - return false; + return (tree.getSelectionModel().getSelectionMode() == + TreeSelectionModel.SINGLE_TREE_SELECTION); } /** @@ -1715,8 +1739,8 @@ public class BasicTreeUI */ protected boolean isMultiSelectEvent(MouseEvent event) { - // FIXME: not implemented - return false; + return (tree.getSelectionModel().getSelectionMode() == + TreeSelectionModel.CONTIGUOUS_TREE_SELECTION); } /** @@ -1731,8 +1755,7 @@ public class BasicTreeUI */ protected boolean isToggleEvent(MouseEvent event) { - // FIXME: not implemented - return false; + return true; } /** @@ -1749,7 +1772,29 @@ public class BasicTreeUI */ protected void selectPathForEvent(TreePath path, MouseEvent event) { - // FIXME: not implemented + if (isToggleSelectionEvent(event)) + { + if (tree.isPathSelected(path)) + tree.removeSelectionPath(path); + else + { + tree.addSelectionPath(path); + tree.setAnchorSelectionPath(path); + } + } + else if (isMultiSelectEvent(event)) + { + TreePath anchor = tree.getAnchorSelectionPath(); + if (anchor != null) + { + int aRow = getRowForPath(tree, anchor); + tree.addSelectionInterval(aRow, getRowForPath(tree, path)); + } + else + tree.addSelectionPath(path); + } + else + tree.addSelectionPath(path); } /** @@ -1766,7 +1811,7 @@ public class BasicTreeUI return true; Object node = pathForRow.getLastPathComponent(); - return tree.getModel().isLeaf(node); + return treeModel.isLeaf(node); } /** @@ -1800,9 +1845,9 @@ public class BasicTreeUI (new TreeTraverseAction(0, "")).actionPerformed(e); else if (e.getActionCommand().equals("selectAll")) { - TreePath[] paths = new TreePath[tree.getRowCount()]; + TreePath[] paths = new TreePath[tree.getVisibleRowCount()]; - Object curr = getNextVisibleNode(tree.getModel().getRoot()); + Object curr = getNextVisibleNode(treeModel.getRoot()); int i = 0; while (curr != null && i < paths.length) { @@ -1822,13 +1867,8 @@ public class BasicTreeUI { Object last = lead.getLastPathComponent(); TreePath path = new TreePath(getPathToRoot(last, 0)); - if (!tree.getModel().isLeaf(last)) - { - if (tree.isExpanded(path)) - tree.collapsePath(path); - else - tree.expandPath(path); - } + if (!treeModel.isLeaf(last)) + toggleExpandState(path); } } else if (e.getActionCommand().equals("clearSelection")) @@ -1920,8 +1960,7 @@ public class BasicTreeUI /** * Updates the preferred size when scrolling, if necessary. */ - public class ComponentHandler - extends ComponentAdapter + public class ComponentHandler extends ComponentAdapter implements ActionListener { /** @@ -1937,6 +1976,7 @@ public class BasicTreeUI */ public ComponentHandler() { + // Nothing to do here. } /** @@ -1947,6 +1987,7 @@ public class BasicTreeUI */ public void componentMoved(ComponentEvent e) { + // TODO: What should be done here, if anything? } /** @@ -1955,6 +1996,7 @@ public class BasicTreeUI */ protected void startTimer() { + // TODO: Implement this properly. } /** @@ -1976,21 +2018,22 @@ public class BasicTreeUI */ public void actionPerformed(ActionEvent ae) { + // TODO: Implement this properly. } - }// ComponentHandler + } /** * Listener responsible for getting cell editing events and updating the tree * accordingly. */ - public class CellEditorHandler - implements CellEditorListener + public class CellEditorHandler implements CellEditorListener { /** * Constructor */ public CellEditorHandler() { + // Nothing to do here. } /** @@ -2023,6 +2066,9 @@ public class BasicTreeUI isEditing = false; tree.requestFocusInWindow(false); editorTimer.stop(); + validCachedPreferredSize = false; + tree.revalidate(); + tree.repaint(); } /** @@ -2051,6 +2097,8 @@ public class BasicTreeUI tree.requestFocusInWindow(false); editorTimer.stop(); isEditing = false; + validCachedPreferredSize = false; + tree.revalidate(); tree.repaint(); } }// CellEditorHandler @@ -2066,6 +2114,7 @@ public class BasicTreeUI */ public FocusHandler() { + // Nothing to do here. } /** @@ -2077,6 +2126,7 @@ public class BasicTreeUI */ public void focusGained(FocusEvent e) { + // TODO: Implement this properly. } /** @@ -2088,8 +2138,9 @@ public class BasicTreeUI */ public void focusLost(FocusEvent e) { + // TODO: Implement this properly. } - }// FocusHandler + } /** * This is used to get multiple key down events to appropriately genereate @@ -2109,6 +2160,7 @@ public class BasicTreeUI */ public KeyHandler() { + // Nothing to do here. } /** @@ -2122,6 +2174,7 @@ public class BasicTreeUI */ public void keyTyped(KeyEvent e) { + // TODO: What should be done here, if anything? } /** @@ -2132,6 +2185,7 @@ public class BasicTreeUI */ public void keyPressed(KeyEvent e) { + // TODO: What should be done here, if anything? } /** @@ -2142,22 +2196,22 @@ public class BasicTreeUI */ public void keyReleased(KeyEvent e) { + // TODO: What should be done here, if anything? } - }// KeyHandler + } /** * MouseListener is responsible for updating the selection based on mouse * events. */ - public class MouseHandler - extends MouseAdapter - implements MouseMotionListener + public class MouseHandler extends MouseAdapter implements MouseMotionListener { /** * Constructor */ public MouseHandler() { + // Nothing to do here. } /** @@ -2168,6 +2222,57 @@ public class BasicTreeUI */ public void mousePressed(MouseEvent e) { + Point click = e.getPoint(); + TreePath path = getClosestPathForLocation(tree, click.x, click.y); + + if (path != null) + { + bounds = getPathBounds(tree, path); + int row = getRowForPath(tree, path); + boolean cntlClick = isLocationInExpandControl(path, click.x, click.y); + + boolean isLeaf = isLeaf(row); + + TreeCellRenderer tcr = getCellRenderer(); + Icon icon; + if (isLeaf) + icon = UIManager.getIcon("Tree.leafIcon"); + else if (tree.isExpanded(path)) + icon = UIManager.getIcon("Tree.openIcon"); + else + icon = UIManager.getIcon("Tree.closedIcon"); + + if (tcr instanceof DefaultTreeCellRenderer) + { + Icon tmp = ((DefaultTreeCellRenderer) tcr).getIcon(); + if (tmp != null) + icon = tmp; + } + + // add gap*2 for the space before and after the text + if (icon != null) + bounds.width += icon.getIconWidth() + gap*2; + + boolean inBounds = bounds.contains(click.x, click.y); + if ((inBounds || cntlClick) && tree.isVisible(path)) + { + if (inBounds) + { + selectPath(tree, path); + if (e.getClickCount() == 2 && !isLeaf(row)) + toggleExpandState(path); + } + + if (cntlClick) + { + handleExpandControlClick(path, click.x, click.y); + if (cellEditor != null) + cellEditor.cancelCellEditing(); + } + else if (tree.isEditable()) + startEditing(path, e); + } + } } /** @@ -2181,6 +2286,7 @@ public class BasicTreeUI */ public void mouseDragged(MouseEvent e) { + // TODO: What should be done here, if anything? } /** @@ -2192,6 +2298,7 @@ public class BasicTreeUI */ public void mouseMoved(MouseEvent e) { + // TODO: What should be done here, if anything? } /** @@ -2202,16 +2309,16 @@ public class BasicTreeUI */ public void mouseReleased(MouseEvent e) { + // TODO: What should be done here, if anything? } - }// MouseHandler + } /** * MouseInputHandler handles passing all mouse events, including mouse motion * events, until the mouse is released to the destination it is constructed * with. */ - public class MouseInputHandler - implements MouseInputListener + public class MouseInputHandler implements MouseInputListener { /** Source that events are coming from */ protected Component source; @@ -2232,6 +2339,8 @@ public class BasicTreeUI public MouseInputHandler(Component source, Component destination, MouseEvent e) { + this.source = source; + this.destination = destination; } /** @@ -2243,6 +2352,7 @@ public class BasicTreeUI */ public void mouseClicked(MouseEvent e) { + // TODO: What should be done here, if anything? } /** @@ -2253,42 +2363,7 @@ public class BasicTreeUI */ public void mousePressed(MouseEvent e) { - Point click = e.getPoint(); - int row = Math.round(click.y / getRowHeight()); - TreePath path = getClosestPathForLocation(tree, click.x, click.y); - - if (path != null) - { - boolean inBounds = false; - boolean cntlClick = false; - Rectangle bounds = getPathBounds(tree, path); - - bounds.x -= rightChildIndent - 4; - bounds.width += rightChildIndent + 4; - - if (bounds.contains(click.x, click.y)) - inBounds = true; - else if (hasControlIcons() - && (click.x < (bounds.x - rightChildIndent + 5) && - click.x > (bounds.x - rightChildIndent - 5))) - cntlClick = true; - - if ((inBounds || cntlClick) && tree.isVisible(path)) - { - selectPath(tree, path); - - if ((e.getClickCount() == 2 || cntlClick) && !isLeaf(row)) - { - if (tree.isExpanded(path)) - tree.collapsePath(path); - else - tree.expandPath(path); - } - - if (!cntlClick && tree.isEditable()) - startEditing(path, e); - } - } + // TODO: What should be done here, if anything? } /** @@ -2299,6 +2374,7 @@ public class BasicTreeUI */ public void mouseReleased(MouseEvent e) { + // TODO: What should be done here, if anything? } /** @@ -2309,6 +2385,7 @@ public class BasicTreeUI */ public void mouseEntered(MouseEvent e) { + // TODO: What should be done here, if anything? } /** @@ -2319,6 +2396,7 @@ public class BasicTreeUI */ public void mouseExited(MouseEvent e) { + // TODO: What should be done here, if anything? } /** @@ -2332,6 +2410,7 @@ public class BasicTreeUI */ public void mouseDragged(MouseEvent e) { + // TODO: What should be done here, if anything? } /** @@ -2343,6 +2422,7 @@ public class BasicTreeUI */ public void mouseMoved(MouseEvent e) { + // TODO: What should be done here, if anything? } /** @@ -2350,8 +2430,9 @@ public class BasicTreeUI */ protected void removeFromSource() { + // TODO: Implement this properly. } - }// MouseInputHandler + } /** * Class responsible for getting size of node, method is forwarded to @@ -2366,6 +2447,7 @@ public class BasicTreeUI */ public NodeDimensionsHandler() { + // Nothing to do here. } /** @@ -2413,6 +2495,7 @@ public class BasicTreeUI */ public PropertyChangeHandler() { + // Nothing to do here. } /** @@ -2424,8 +2507,15 @@ public class BasicTreeUI */ public void propertyChange(PropertyChangeEvent event) { + if ((event.getPropertyName()).equals("rootVisible")) + { + validCachedPreferredSize = false; + updateCurrentVisiblePath(); + tree.revalidate(); + tree.repaint(); + } } - }// PropertyChangeHandler + } /** * Listener on the TreeSelectionModel, resets the row selection if any of the @@ -2440,6 +2530,7 @@ public class BasicTreeUI */ public SelectionModelPropertyChangeHandler() { + // Nothing to do here. } /** @@ -2451,8 +2542,9 @@ public class BasicTreeUI */ public void propertyChange(PropertyChangeEvent event) { + // TODO: What should be done here, if anything? } - }// SelectionModelPropertyChangeHandler + } /** * ActionListener that invokes cancelEditing when action performed. @@ -2464,8 +2556,9 @@ public class BasicTreeUI /** * Constructor */ - public TreeCancelEditingAction() + public TreeCancelEditingAction(String name) { + // TODO: Implement this properly. } /** @@ -2476,6 +2569,7 @@ public class BasicTreeUI */ public void actionPerformed(ActionEvent e) { + // TODO: Implement this properly. } /** @@ -2485,9 +2579,10 @@ public class BasicTreeUI */ public boolean isEnabled() { + // TODO: Implement this properly. return false; } - }// TreeCancelEditingAction + } /** * Updates the TreeState in response to nodes expanding/collapsing. @@ -2501,6 +2596,7 @@ public class BasicTreeUI */ public TreeExpansionHandler() { + // Nothing to do here. } /** @@ -2511,6 +2607,9 @@ public class BasicTreeUI */ public void treeExpanded(TreeExpansionEvent event) { + validCachedPreferredSize = false; + updateCurrentVisiblePath(); + tree.revalidate(); tree.repaint(); } @@ -2522,6 +2621,9 @@ public class BasicTreeUI */ public void treeCollapsed(TreeExpansionEvent event) { + validCachedPreferredSize = false; + updateCurrentVisiblePath(); + tree.revalidate(); tree.repaint(); } }// TreeExpansionHandler @@ -2547,6 +2649,7 @@ public class BasicTreeUI */ public TreeHomeAction(int direction, String name) { + // TODO: Implement this properly } /** @@ -2557,6 +2660,7 @@ public class BasicTreeUI */ public void actionPerformed(ActionEvent e) { + // TODO: Implement this properly } /** @@ -2566,9 +2670,10 @@ public class BasicTreeUI */ public boolean isEnabled() { + // TODO: Implement this properly return false; } - }// TreeHomeAction + } /** * TreeIncrementAction is used to handle up/down actions. Selection is moved @@ -2591,6 +2696,7 @@ public class BasicTreeUI */ public TreeIncrementAction(int direction, String name) { + // TODO: Implement this properly } /** @@ -2606,11 +2712,11 @@ public class BasicTreeUI if (e.getActionCommand().equals("selectPreviousChangeLead")) { Object prev = getPreviousVisibleNode(last); - + if (prev != null) { TreePath newPath = new TreePath(getPathToRoot(prev, 0)); - selectPath(tree, new TreePath(getPathToRoot(prev, 0))); + selectPath(tree, newPath); tree.setLeadSelectionPath(newPath); } } @@ -2627,15 +2733,17 @@ public class BasicTreeUI else if (e.getActionCommand().equals("selectPrevious")) { Object prev = getPreviousVisibleNode(last); + if (prev != null) { TreePath newPath = new TreePath(getPathToRoot(prev, 0)); - selectPath(tree, new TreePath(getPathToRoot(prev, 0))); + selectPath(tree, newPath); } } else if (e.getActionCommand().equals("selectNext")) { Object next = getNextVisibleNode(last); + if (next != null) { TreePath newPath = new TreePath(getPathToRoot(next, 0)); @@ -2671,21 +2779,22 @@ public class BasicTreeUI */ public boolean isEnabled() { + // TODO: Implement this properly return false; } - }// TreeIncrementAction + } /** * Forwards all TreeModel events to the TreeState. */ - public class TreeModelHandler - implements TreeModelListener + public class TreeModelHandler implements TreeModelListener { /** * Constructor */ public TreeModelHandler() { + // Nothing to do here. } /** @@ -2703,6 +2812,9 @@ public class BasicTreeUI */ public void treeNodesChanged(TreeModelEvent e) { + validCachedPreferredSize = false; + updateCurrentVisiblePath(); + tree.revalidate(); tree.repaint(); } @@ -2716,6 +2828,9 @@ public class BasicTreeUI */ public void treeNodesInserted(TreeModelEvent e) { + validCachedPreferredSize = false; + updateCurrentVisiblePath(); + tree.revalidate(); tree.repaint(); } @@ -2732,6 +2847,9 @@ public class BasicTreeUI */ public void treeNodesRemoved(TreeModelEvent e) { + validCachedPreferredSize = false; + updateCurrentVisiblePath(); + tree.revalidate(); tree.repaint(); } @@ -2747,6 +2865,12 @@ public class BasicTreeUI */ public void treeStructureChanged(TreeModelEvent e) { + if (e.getPath().length == 1 + && !e.getPath()[0].equals(treeModel.getRoot())) + tree.expandPath(new TreePath(treeModel.getRoot())); + updateCurrentVisiblePath(); + validCachedPreferredSize = false; + tree.revalidate(); tree.repaint(); } }// TreeModelHandler @@ -2754,8 +2878,7 @@ public class BasicTreeUI /** * TreePageAction handles page up and page down events. */ - public class TreePageAction - extends AbstractAction + public class TreePageAction extends AbstractAction { /** Specifies the direction to adjust the selection by. */ protected int direction; @@ -2770,6 +2893,7 @@ public class BasicTreeUI */ public TreePageAction(int direction, String name) { + this.direction = direction; } /** @@ -2780,6 +2904,7 @@ public class BasicTreeUI */ public void actionPerformed(ActionEvent e) { + // TODO: Implement this properly. } /** @@ -2797,14 +2922,14 @@ public class BasicTreeUI * Listens for changes in the selection model and updates the display * accordingly. */ - public class TreeSelectionHandler - implements TreeSelectionListener + public class TreeSelectionHandler implements TreeSelectionListener { /** * Constructor */ public TreeSelectionHandler() { + // Nothing to do here. } /** @@ -2824,8 +2949,7 @@ public class BasicTreeUI /** * For the first selected row expandedness will be toggled. */ - public class TreeToggleAction - extends AbstractAction + public class TreeToggleAction extends AbstractAction { /** * Constructor @@ -2835,6 +2959,7 @@ public class BasicTreeUI */ public TreeToggleAction(String name) { + // Nothing to do here. } /** @@ -2845,6 +2970,7 @@ public class BasicTreeUI */ public void actionPerformed(ActionEvent e) { + // TODO: Implement this properly. } /** @@ -2862,8 +2988,7 @@ public class BasicTreeUI * TreeTraverseAction is the action used for left/right keys. Will toggle the * expandedness of a node, as well as potentially incrementing the selection. */ - public class TreeTraverseAction - extends AbstractAction + public class TreeTraverseAction extends AbstractAction { /** * Determines direction to traverse, 1 means expand, -1 means collapse. @@ -2880,6 +3005,7 @@ public class BasicTreeUI */ public TreeTraverseAction(int direction, String name) { + this.direction = direction; } /** @@ -2890,16 +3016,15 @@ public class BasicTreeUI */ public void actionPerformed(ActionEvent e) { - TreeModel mod = tree.getModel(); Object last = tree.getLeadSelectionPath().getLastPathComponent(); if (e.getActionCommand().equals("selectParent")) { TreePath path = new TreePath(getPathToRoot(last, 0)); - Object p = getParent(mod.getRoot(), last); + Object p = getParent(treeModel.getRoot(), last); - if (!mod.isLeaf(last) && tree.isExpanded(path)) - tree.collapsePath(path); + if (!treeModel.isLeaf(last)) + toggleExpandState(path); else if (p != null) selectPath(tree, new TreePath(getPathToRoot(p, 0))); } @@ -2907,8 +3032,8 @@ public class BasicTreeUI { TreePath path = new TreePath(getPathToRoot(last, 0)); - if (!mod.isLeaf(last) && tree.isCollapsed(path)) - tree.expandPath(path); + if (!treeModel.isLeaf(last)) + toggleExpandState(path); else { Object next = getNextVisibleNode(last); @@ -2926,9 +3051,10 @@ public class BasicTreeUI */ public boolean isEnabled() { + // TODO: Implement this properly return false; } - } // TreeTraverseAction + } /** * Returns the cell bounds for painting selected cells Package private for use @@ -2951,8 +3077,7 @@ public class BasicTreeUI FontMetrics fm = tree.getToolkit().getFontMetrics(f); if (s != null) - return new Rectangle(x, y, - SwingUtilities.computeStringWidth(fm, s) + 4, + return new Rectangle(x, y, SwingUtilities.computeStringWidth(fm, s), fm.getHeight()); } return new Rectangle(x, y, 0, 0); @@ -2982,80 +3107,19 @@ public class BasicTreeUI int rowHeight = getRowHeight(); if (startNode == null || startNode.equals(node)) { - if (!tree.isRootVisible() - && tree.isExpanded(new TreePath(mod.getRoot()))) - return new Point(x + ((getLevel(node)) * rightChildIndent), y); - - return new Point(x + ((getLevel(node) + 1) * rightChildIndent), y); - } - - if (!mod.isLeaf(startNode) - && tree.isExpanded(new TreePath(getPathToRoot(startNode, 0))) - && !mod.isLeaf(startNode) && mod.getChildCount(startNode) > 0) - { - Object child = mod.getChild(startNode, 0); - if (child != null) - return getCellLocation(x, y + rowHeight, tree, mod, node, child); + 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)); } /** - * Paints a node in the tree Package private for use in inner classes. - * - * @param g - * the Graphics context in which to paint - * @param x - * the x location of the node - * @param y - * the y location of the node - * @param tree - * the tree to draw on - * @param node - * the object to draw - */ - void paintNode(Graphics g, int x, int y, JTree tree, Object node, - boolean isLeaf) - { - TreePath curr = new TreePath(getPathToRoot(node, 0)); - boolean selected = tree.isPathSelected(curr); - boolean expanded = false; - boolean hasIcons = false; - - if (tree.isVisible(curr)) - { - if (!isLeaf) - expanded = tree.isExpanded(curr); - - if (editingComponent != null && editingPath != null && isEditing(tree) - && node.equals(editingPath.getLastPathComponent())) - { - Rectangle bounds = getPathBounds(tree, editingPath); - rendererPane.paintComponent(g, editingComponent.getParent(), null, - new Rectangle(0, 0, bounds.width, - bounds.height)); - } - else - { - TreeCellRenderer dtcr = tree.getCellRenderer(); - if (dtcr == null) - dtcr = createDefaultCellRenderer(); - - int row = getRowForPath(tree, curr); - - Component c = dtcr.getTreeCellRendererComponent(tree, node, - selected, expanded, - isLeaf, row, false); - - rendererPane.paintComponent(g, c, c.getParent(), - getCellBounds(x, y, node)); - } - } - } - - /** * Recursively paints all elements of the tree Package private for use in * inner classes. * @@ -3065,8 +3129,6 @@ public class BasicTreeUI * of the current object * @param descent * is the number of elements drawn - * @param childNumber - * is the index of the current child in the tree * @param depth * is the depth of the current object in the tree * @param tree @@ -3077,71 +3139,79 @@ public class BasicTreeUI * is the current object to draw * @return int - current descent of the tree */ - int paintRecursive(Graphics g, int indentation, int descent, int childNumber, + int paintRecursive(Graphics g, int indentation, int descent, int depth, JTree tree, TreeModel mod, Object curr) { - Rectangle clip = g.getClipBounds(); + 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(); - - if (mod.isLeaf(curr)) + boolean isExpanded = tree.isExpanded(path); + boolean isLeaf = mod.isLeaf(curr); + Rectangle bounds = getPathBounds(tree, path); + Object root = mod.getRoot(); + + if (isLeaf) { - paintNode(g, indentation + 4, descent, tree, curr, true); + paintRow(g, clip, null, bounds, path, row, true, false, true); descent += getRowHeight(); } else { if (depth > 0 || isRootVisible) { - paintNode(g, indentation + 4, descent, tree, curr, false); + paintRow(g, clip, null, bounds, path, row, isExpanded, false, false); descent += getRowHeight(); y0 += halfHeight; } - - int max = 0; - if (!mod.isLeaf(curr)) - max = mod.getChildCount(curr); - if (tree.isExpanded(new TreePath(getPathToRoot(curr, 0)))) + + 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 && !curr.equals(mod.getRoot())) - || isRootVisible) + else if (isRootVisible || + (!isRootVisible && !curr.equals(root)) && childVis) { g.setColor(getHashColor()); heightOfLine = descent + halfHeight; - g.drawLine(indentation + halfWidth, heightOfLine, - indentation + rightChildIndent, heightOfLine); + paintHorizontalLine(g, (JComponent) tree, heightOfLine, + indentation + halfWidth, indentation + rightChildIndent); } - descent = paintRecursive(g, indent, descent, i, depth + 1, - tree, mod, mod.getChild(curr, i)); + descent = paintRecursive(g, indent, descent, depth + 1, + tree, mod, child); } } } - if (tree.isExpanded(new TreePath(getPathToRoot(curr, 0)))) - if (y0 != heightOfLine && !mod.isLeaf(curr) - && mod.getChildCount(curr) > 0) + if (isExpanded) + if (y0 != heightOfLine + && (mod.getChildCount(curr) > 0 && + tree.isVisible(new TreePath(getPathToRoot(mod.getChild + (curr, 0), 0))))) { g.setColor(getHashColor()); - g.drawLine(indentation + halfWidth, y0, indentation + halfWidth, - heightOfLine); + 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. @@ -3152,76 +3222,99 @@ public class BasicTreeUI * of the current object * @param descent * is the number of elements drawn - * @param childNumber - * is the index of the current child in the tree * @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 + * @param node * is the current object to draw - * @return int - current descent of the tree + * @return int current descent of the tree */ int paintControlIcons(Graphics g, int indentation, int descent, - int childNumber, int depth, JTree tree, TreeModel mod, + int depth, JTree tree, TreeModel mod, Object node) { - int h = descent; int rowHeight = getRowHeight(); - Icon ei = UIManager.getLookAndFeelDefaults().getIcon("Tree.expandedIcon"); - Icon ci = UIManager.getLookAndFeelDefaults().getIcon("Tree.collapsedIcon"); - Rectangle clip = g.getClipBounds(); + 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; - - int max = 0; - if (!mod.isLeaf(node)) - max = mod.getChildCount(node); - if (tree.isExpanded(new TreePath(getPathToRoot(node, 0)))) + + if (tree.isExpanded(path)) { - if (!node.equals(mod.getRoot())) - ei.paintIcon(tree, g, indentation - rightChildIndent - 3, h); - + 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; - - descent = paintControlIcons(g, indent, descent, i, depth + 1, - tree, mod, mod.getChild(node, i)); + indent = 1; + if (tree.isVisible(new TreePath(getPathToRoot(child, 0)))) + descent = paintControlIcons(g, indent, descent, depth + 1, + tree, mod, child); } } - else if (!node.equals(mod.getRoot())) - ci.paintIcon(tree, g, indentation - rightChildIndent - 3, - descent - getRowHeight()); } - + return descent; } /** - * Returns true if the LookAndFeel implements the control icons Package + * Returns true if the LookAndFeel implements the control icons. Package * private for use in inner classes. * - * @return true if control icons are visible + * @returns true if there are control icons */ boolean hasControlIcons() { - if (UIManager.getLookAndFeelDefaults().getIcon("Tree.expandedIcon") == null - || UIManager.getLookAndFeelDefaults().getIcon("Tree.collapsedIcon") == null) - return false; - return true; + if (expandedIcon != null || collapsedIcon != null) + return true; + return false; + } + + /** + * Returns control icon. It is null if the LookAndFeel does not implements the + * control icons. Package private for use in inner classes. + * + * @return control icon if it exists. + */ + Icon getCurrentControlIcon(TreePath path) + { + if (tree.isExpanded(path)) + return expandedIcon; + return collapsedIcon; } /** @@ -3235,8 +3328,10 @@ public class BasicTreeUI */ Object getParent(Object root, Object node) { - if (root == null || node == null) + if (root == null || node == null || + root.equals(node)) return null; + if (node instanceof TreeNode) return ((TreeNode) node).getParent(); return findNode(root, node); @@ -3253,113 +3348,69 @@ public class BasicTreeUI */ private Object findNode(Object root, Object node) { - TreeModel mod = tree.getModel(); - int size = 0; - if (!mod.isLeaf(root)) - size = mod.getChildCount(root); - for (int i = 0; i < size; i++) - { - if (mod.getIndexOfChild(root, node) != -1) - return root; - - Object n = findNode(mod.getChild(root, i), node); - if (n != null) - return n; - } - return null; - } - - /** - * Get next visible node in the tree. Package private for use in inner - * classes. - * - * @param the - * current node - * @return the next visible node in the JTree. Return null if there are no - * more. - */ - Object getNextVisibleNode(Object node) - { - Object next = null; - TreePath current = null; - - if (node != null) - next = getNextNode(node); - - if (next != null) + if (!treeModel.isLeaf(root) && !root.equals(node)) { - current = new TreePath(getPathToRoot(next, 0)); - if (tree.isVisible(current)) - return next; - - while (next != null && !tree.isVisible(current)) + int size = treeModel.getChildCount(root); + for (int j = 0; j < size; j++) { - next = getNextNode(next); + Object child = treeModel.getChild(root, j); + if (node.equals(child)) + return root; - if (next != null) - current = new TreePath(getPathToRoot(next, 0)); + Object n = findNode(child, node); + if (n != null) + return n; } } - return next; + return null; } - + /** * Get previous visible node in the tree. Package private for use in inner * classes. * - * @param the + * @param node - * current node * @return the next visible node in the JTree. Return null if there are no * more. */ Object getPreviousVisibleNode(Object node) { - Object prev = null; - TreePath current = null; - - if (node != null) - prev = getPreviousNode(node); - - if (prev != null) + updateCurrentVisiblePath(); + if (currentVisiblePath != null) { - current = new TreePath(getPathToRoot(prev, 0)); - if (tree.isVisible(current)) - return prev; - - while (prev != null && !tree.isVisible(current)) - { - prev = getPreviousNode(prev); - - if (prev != null) - current = new TreePath(getPathToRoot(prev, 0)); - } + Object[] nodes = currentVisiblePath.getPath(); + int i = 0; + while (i < nodes.length && !node.equals(nodes[i])) + i++; + // return the next node + if (i-1 >= 0) + return nodes[i-1]; } - return prev; + return null; } /** * Returns the next node in the tree Package private for use in inner classes. * - * @param the + * @param curr - * current node * @return the next node in the tree */ Object getNextNode(Object curr) { - TreeModel mod = tree.getModel(); - if (!mod.isLeaf(curr) && mod.getChildCount(curr) > 0) - return mod.getChild(curr, 0); + if (!treeModel.isLeaf(curr) && treeModel.getChildCount(curr) > 0) + return treeModel.getChild(curr, 0); Object node = curr; Object sibling = null; - do { sibling = getNextSibling(node); - node = getParent(mod.getRoot(), node); + node = getParent(treeModel.getRoot(), node); } while (sibling == null && node != null); - + return sibling; } @@ -3367,14 +3418,13 @@ public class BasicTreeUI * Returns the previous node in the tree Package private for use in inner * classes. * - * @param the + * @param node * current node * @return the previous node in the tree */ Object getPreviousNode(Object node) { - TreeModel mod = tree.getModel(); - Object parent = getParent(mod.getRoot(), node); + Object parent = getParent(treeModel.getRoot(), node); if (parent == null) return null; @@ -3384,13 +3434,13 @@ public class BasicTreeUI return parent; int size = 0; - if (!mod.isLeaf(sibling)) - size = mod.getChildCount(sibling); + if (!treeModel.isLeaf(sibling)) + size = treeModel.getChildCount(sibling); while (size > 0) { - sibling = mod.getChild(sibling, size - 1); - if (!mod.isLeaf(sibling)) - size = mod.getChildCount(sibling); + sibling = treeModel.getChild(sibling, size - 1); + if (!treeModel.isLeaf(sibling)) + size = treeModel.getChildCount(sibling); else size = 0; } @@ -3402,52 +3452,50 @@ public class BasicTreeUI * Returns the next sibling in the tree Package private for use in inner * classes. * - * @param the + * @param node - * current node * @return the next sibling in the tree */ Object getNextSibling(Object node) { - TreeModel mod = tree.getModel(); - Object parent = getParent(mod.getRoot(), node); + Object parent = getParent(treeModel.getRoot(), node); if (parent == null) return null; - int index = mod.getIndexOfChild(parent, node) + 1; + int index = treeModel.getIndexOfChild(parent, node) + 1; int size = 0; - if (!mod.isLeaf(parent)) - size = mod.getChildCount(parent); + if (!treeModel.isLeaf(parent)) + size = treeModel.getChildCount(parent); if (index == 0 || index >= size) return null; - return mod.getChild(parent, index); + return treeModel.getChild(parent, index); } - + /** * Returns the previous sibling in the tree Package private for use in inner * classes. * - * @param the + * @param node - * current node * @return the previous sibling in the tree */ Object getPreviousSibling(Object node) { - TreeModel mod = tree.getModel(); - Object parent = getParent(mod.getRoot(), node); + Object parent = getParent(treeModel.getRoot(), node); if (parent == null) return null; - int index = mod.getIndexOfChild(parent, node) - 1; + int index = treeModel.getIndexOfChild(parent, node) - 1; int size = 0; - if (!mod.isLeaf(parent)) - size = mod.getChildCount(parent); + if (!treeModel.isLeaf(parent)) + size = treeModel.getChildCount(parent); if (index < 0 || index >= size) return null; - return mod.getChild(parent, index); + return treeModel.getChild(parent, index); } /** @@ -3463,22 +3511,24 @@ public class BasicTreeUI { if (path != null) { - if (tree.getSelectionModel().getSelectionMode() == TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION) + if (tree.getSelectionModel().getSelectionMode() == + TreeSelectionModel.SINGLE_TREE_SELECTION) { + tree.getSelectionModel().clearSelection(); tree.addSelectionPath(path); tree.setLeadSelectionPath(path); } - else if (tree.getSelectionModel().getSelectionMode() == TreeSelectionModel.CONTIGUOUS_TREE_SELECTION) + else if (tree.getSelectionModel().getSelectionMode() == + TreeSelectionModel.CONTIGUOUS_TREE_SELECTION) { // TODO } else { - tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); - - tree.getSelectionModel().clearSelection(); tree.addSelectionPath(path); tree.setLeadSelectionPath(path); + tree.getSelectionModel().setSelectionMode + (TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION); } } } @@ -3495,7 +3545,6 @@ public class BasicTreeUI */ Object[] getPathToRoot(Object node, int depth) { - TreeModel mod = tree.getModel(); if (node == null) { if (depth == 0) @@ -3504,7 +3553,7 @@ public class BasicTreeUI return new Object[depth]; } - Object[] path = getPathToRoot(getParent(mod.getRoot(), node), depth + 1); + Object[] path = getPathToRoot(getParent(treeModel.getRoot(), node), depth + 1); path[path.length - depth - 1] = node; return path; } @@ -3512,22 +3561,23 @@ public class BasicTreeUI /** * Returns the level of the node in the tree. * - * @param the + * @param node - * current node * @return the number of the level */ int getLevel(Object node) { int count = -1; + Object current = node; do { - current = getParent(tree.getModel().getRoot(), current); + current = getParent(treeModel.getRoot(), current); count++; } while (current != null); - + return count; } @@ -3586,10 +3636,271 @@ public class BasicTreeUI * is the center position in y-direction FIXME what to do if x < * (icon.width / 2). Same with y */ - protected void drawCentered(JComponent c, Graphics g, Icon icon, int x, int y) + 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); } + + /** + * Draws a dashed horizontal line. + * + * @param g - the graphics configuration. + * @param y - the y location to start drawing at + * @param x1 - the x location to start drawing at + * @param x2 - the x location to finish drawing at + */ + protected void drawDashedHorizontalLine(Graphics g, int y, int x1, int x2) + { + for (int i = x1; i < x2; i += 2) + g.drawLine(i, y, i + 1, y); + } + + /** + * Draws a dashed vertical line. + * + * @param g - the graphics configuration. + * @param x - the x location to start drawing at + * @param y1 - the y location to start drawing at + * @param y2 - the y location to finish drawing at + */ + protected void drawDashedVerticalLine(Graphics g, int x, int y1, int y2) + { + for (int i = y1; i < y2; i += 2) + g.drawLine(x, i, x, i + 1); + } + + /** + * Paints the expand (toggle) part of a row. The receiver should NOT modify + * clipBounds, or insets. + * + * @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 isExpanded - is the row expanded + * @param hasBeenExpanded - has the row already been expanded + * @param isLeaf - is the path a leaf + */ + protected void paintExpandControl(Graphics g, Rectangle clipBounds, + Insets insets, Rectangle bounds, + TreePath path, int row, + boolean isExpanded, boolean hasBeenExpanded, + boolean isLeaf) + { + if (treeModel != null && hasControlIcons()) + paintControlIcons(g, 0, 0, 0, tree, treeModel, path.getLastPathComponent()); + } + + /** + * Paints the horizontal part of the leg. The receiver should NOT modify + * clipBounds, or insets. + * NOTE: parentRow can be -1 if the root is not visible. + * + * @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 isExpanded - is the row expanded + * @param hasBeenExpanded - has the row already been expanded + * @param isLeaf - is the path a leaf + */ + protected void paintHorizontalPartOfLeg(Graphics g, Rectangle clipBounds, + Insets insets, Rectangle bounds, + TreePath path, int row, + boolean isExpanded, boolean hasBeenExpanded, + boolean isLeaf) + { + // FIXME: not implemented + } + + /** + * Paints the vertical part of the leg. The receiver should NOT modify + * clipBounds, insets. + * + * @param g - the graphics configuration. + * @param clipBounds - + * @param insets - + * @param path - the path to draw the vertical part for. + */ + protected void paintVerticalPartOfLeg(Graphics g, Rectangle clipBounds, + Insets insets, TreePath path) + { + // FIXME: not implemented + } + + /** + * Paints the renderer part of a row. The receiver should NOT modify clipBounds, + * or insets. + * + * @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 isExpanded - is the row expanded + * @param hasBeenExpanded - has the row already been expanded + * @param isLeaf - is the path a leaf + */ + protected void paintRow(Graphics g, Rectangle clipBounds, + Insets insets, Rectangle bounds, + TreePath path, int row, + boolean isExpanded, boolean hasBeenExpanded, + boolean isLeaf) + { + boolean selected = tree.isPathSelected(path); + boolean hasIcons = false; + Object node = path.getLastPathComponent(); + + if (tree.isVisible(path)) + { + if (!validCachedPreferredSize) + updateCachedPreferredSize(); + bounds.x += gap; + bounds.width = preferredSize.width + bounds.x; + + if (editingComponent != null && editingPath != null && isEditing(tree) + && node.equals(editingPath.getLastPathComponent())) + { + rendererPane.paintComponent(g, editingComponent.getParent(), null, + bounds); + } + else + { + TreeCellRenderer dtcr = tree.getCellRenderer(); + if (dtcr == null) + dtcr = createDefaultCellRenderer(); + + Component c = dtcr.getTreeCellRendererComponent(tree, node, + selected, isExpanded, isLeaf, row, tree.hasFocus()); + rendererPane.paintComponent(g, c, c.getParent(), bounds); + } + } + } + + /** + * Prepares for the UI to uninstall. + */ + protected void prepareForUIUninstall() + { + // TODO: Implement this properly. + } + + /** + * Returns true if the expand (toggle) control should be drawn for the + * specified row. + * + * @param path - current path to check for. + * @param row - current row to check for. + * @param isExpanded - true if the path is expanded + * @param hasBeenExpanded - true if the path has been expanded already + * @param isLeaf - true if the row is a lead + */ + protected boolean shouldPaintExpandControl(TreePath path, int row, + boolean isExpanded, + boolean hasBeenExpanded, + boolean isLeaf) + { + Object node = path.getLastPathComponent(); + if (treeModel != null && (!isLeaf && !node.equals(treeModel.getRoot())) && + (tree.isRootVisible() || getLevel(node) != 1)) + return true; + return false; + } + + /** + * Updates the cached current TreePath of all visible + * nodes in the tree. + */ + void updateCurrentVisiblePath() + { + if (treeModel == null) + return; + + Object next = treeModel.getRoot(); + Rectangle bounds = getCellBounds(0, 0, next); + boolean rootVisible = isRootVisible(); + + // 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 + && tree.isExpanded(new TreePath(next)))) + next = getNextNode(next); + + Object root = next; + TreePath current = null; + while (next != null) + { + if (current == null) + current = new TreePath(next); + else + current = current.pathByAddingChild(next); + do + { + TreePath path = new TreePath(getPathToRoot(next, 0)); + if ((tree.isVisible(path) && tree.isExpanded(path)) + || treeModel.isLeaf(next)) + next = getNextNode(next); + else + { + Object pNext = next; + next = getNextSibling(pNext); + // if no next sibling, check parent's next sibling. + if (next == null) + { + Object parent = getParent(root, pNext); + while (next == null && parent != null) + { + next = getNextSibling(parent); + if (next == null) + parent = getParent(treeModel.getRoot(), next); + } + } + } + } + while (next != null && + !tree.isVisible(new TreePath(getPathToRoot(next, 0)))); + } + + currentVisiblePath = current; + if (currentVisiblePath != null) + tree.setVisibleRowCount(currentVisiblePath.getPathCount()); + else tree.setVisibleRowCount(0); + + if (tree.getSelectionModel() != null && tree.getSelectionCount() == 0 && + currentVisiblePath != null) + selectPath(tree, new TreePath(getPathToRoot(currentVisiblePath. + getPathComponent(0), 0))); + } + + /** + * Get next visible node in the currentVisiblePath. Package private for use in + * inner classes. + * + * @param node + * current node + * @return the next visible node in the JTree. Return null if there are no + * more. + */ + Object getNextVisibleNode(Object node) + { + if (currentVisiblePath != null) + { + Object[] nodes = currentVisiblePath.getPath(); + int i = 0; + while (i < nodes.length && !node.equals(nodes[i])) + i++; + // return the next node + if (i+1 < nodes.length) + return nodes[i+1]; + } + return null; + } } // BasicTreeUI |