package javax.swing;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Vector;
import javax.accessibility.Accessible;
import javax.accessibility.AccessibleContext;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeExpansionListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.event.TreeWillExpandListener;
import javax.swing.plaf.TreeUI;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.ExpandVetoException;
import javax.swing.tree.TreeCellEditor;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
public class JTree extends JComponent
implements Scrollable, Accessible
{
private static final long serialVersionUID = 7559816092864483649L;
public static final String CELL_EDITOR_PROPERTY = "cellEditor";
public static final String CELL_RENDERER_PROPERTY = "cellRenderer";
public static final String EDITABLE_PROPERTY = "editable";
public static final String INVOKES_STOP_CELL_EDITING_PROPERTY = "invokesStopCellEditing";
public static final String LARGE_MODEL_PROPERTY = "largeModel";
public static final String ROOT_VISIBLE_PROPERTY = "rootVisible";
public static final String ROW_HEIGHT_PROPERTY = "rowHeight";
public static final String SCROLLS_ON_EXPAND_PROPERTY = "scrollsOnExpand";
public static final String SELECTION_MODEL_PROPERTY = "selectionModel";
public static final String SHOWS_ROOT_HANDLES_PROPERTY = "showsRootHandles";
public static final String TOGGLE_CLICK_COUNT_PROPERTY = "toggleClickCount";
public static final String TREE_MODEL_PROPERTY = "model";
public static final String VISIBLE_ROW_COUNT_PROPERTY = "visibleRowCount";
public static final String ANCHOR_SELECTION_PATH_PROPERTY = "anchorSelectionPath";
public static final String LEAD_SELECTION_PATH_PROPERTY = "leadSelectionPath";
public static final String EXPANDS_SELECTED_PATHS_PROPERTY = "expandsSelectedPaths";
private static final Object EXPANDED = new Object();
private static final Object COLLAPSED = new Object();
private boolean dragEnabled;
private boolean expandsSelectedPaths;
private TreePath anchorSelectionPath;
private TreePath leadSelectionPath;
private Hashtable nodeStates;
protected transient TreeCellEditor cellEditor;
protected transient TreeCellRenderer cellRenderer;
protected boolean editable;
protected boolean invokesStopCellEditing;
protected boolean largeModel;
protected boolean rootVisible;
protected int rowHeight;
protected boolean scrollsOnExpand;
protected transient TreeSelectionModel selectionModel;
protected boolean showsRootHandles;
protected int toggleClickCount;
protected transient TreeModel treeModel;
protected int visibleRowCount;
public JTree()
{
this(createTreeModel(null));
}
public JTree(Hashtable value)
{
this(createTreeModel(value));
}
public JTree(Object[] value)
{
this(createTreeModel(value));
}
public JTree(TreeModel model)
{
treeModel = model;
setCellRenderer(new DefaultTreeCellRenderer());
updateUI();
}
public JTree(TreeNode root)
{
this(root, false);
}
public JTree(TreeNode root, boolean asksAllowChildren)
{
this(new DefaultTreeModel(root, asksAllowChildren));
}
public JTree(Vector value)
{
this(createTreeModel(value));
}
public static class DynamicUtilTreeNode
extends DefaultMutableTreeNode
{
protected Object childValue;
protected boolean loadedChildren;
protected boolean hasChildren;
public DynamicUtilTreeNode(Object value,
Object children)
{
super(value);
childValue = children;
loadedChildren = false;
}
public int getChildCount()
{
loadChildren();
return super.getChildCount();
}
protected void loadChildren()
{
if (!loadedChildren)
{
createChildren(this, childValue);
loadedChildren = true;
}
}
public Enumeration children()
{
loadChildren();
return super.children();
}
public boolean isLeaf()
{
return (childValue == null ||
!(childValue instanceof Hashtable
|| childValue instanceof Vector
|| childValue.getClass().isArray()));
}
public static void createChildren(DefaultMutableTreeNode parent,
Object children)
{
if (children instanceof Hashtable)
{
Hashtable tab = (Hashtable) children;
Enumeration e = tab.keys();
while (e.hasMoreElements())
{
Object key = e.nextElement();
Object val = tab.get(key);
parent.add(new DynamicUtilTreeNode(key, val));
}
}
else if (children instanceof Vector)
{
Iterator i = ((Vector)children).iterator();
while (i.hasNext())
{
Object n = i.next();
parent.add(new DynamicUtilTreeNode(n,n));
}
}
else if (children.getClass().isArray())
{
Object[] arr = (Object[]) children;
for (int i = 0; i < arr.length; ++i)
parent.add(new DynamicUtilTreeNode(arr[i], arr[i]));
}
}
}
public int getRowForPath(TreePath path)
{
TreeUI ui = getUI();
if (ui != null)
return ui.getRowForPath(this, path);
return -1;
}
public TreePath getPathForRow(int row)
{
TreeUI ui = getUI();
return ui != null ? ui.getPathForRow(this, row) : null;
}
protected TreePath[] getPathBetweenRows(int index0, int index1)
{
TreeUI ui = getUI();
if (ui == null)
return null;
int minIndex = Math.min(index0, index1);
int maxIndex = Math.max(index0, index1);
TreePath[] paths = new TreePath[maxIndex - minIndex + 1];
for (int i = minIndex; i <= maxIndex; ++i)
paths[i - minIndex] = ui.getPathForRow(this, i);
return paths;
}
protected static TreeModel createTreeModel(Object value)
{
return new DefaultTreeModel(new DynamicUtilTreeNode(value, value));
}
public TreeUI getUI()
{
return (TreeUI) ui;
}
public void setUI(TreeUI ui)
{
super.setUI(ui);
}
public void updateUI()
{
setUI((TreeUI) UIManager.getUI(this));
revalidate();
repaint();
}
public String getUIClassID()
{
return "TreeUI";
}
public AccessibleContext getAccessibleContext()
{
return null;
}
public Dimension getPreferredScrollableViewportSize()
{
return null;
}
public int getScrollableUnitIncrement(Rectangle visibleRect,
int orientation, int direction)
{
return 1;
}
public int getScrollableBlockIncrement(Rectangle visibleRect,
int orientation, int direction)
{
return 1;
}
public boolean getScrollableTracksViewportWidth()
{
return false;
}
public boolean getScrollableTracksViewportHeight()
{
return false;
}
public void addTreeExpansionListener(TreeExpansionListener listener)
{
listenerList.add(TreeExpansionListener.class, listener);
}
public void removeTreeExpansionListener(TreeExpansionListener listener)
{
listenerList.remove(TreeExpansionListener.class, listener);
}
public TreeExpansionListener[] getTreeExpansionListeners()
{
return (TreeExpansionListener[]) getListeners(TreeExpansionListener.class);
}
public void fireTreeCollapsed(TreePath path)
{
TreeExpansionEvent event = new TreeExpansionEvent(this, path);
TreeExpansionListener[] listeners = getTreeExpansionListeners();
for (int index = 0; index < listeners.length; ++index)
listeners[index].treeCollapsed(event);
}
public void fireTreeExpanded(TreePath path)
{
TreeExpansionEvent event = new TreeExpansionEvent(this, path);
TreeExpansionListener[] listeners = getTreeExpansionListeners();
for (int index = 0; index < listeners.length; ++index)
listeners[index].treeExpanded(event);
}
public void addTreeSelectionListener(TreeSelectionListener listener)
{
listenerList.add(TreeSelectionListener.class, listener);
}
public void removeTreeSelectionListener(TreeSelectionListener listener)
{
listenerList.remove(TreeSelectionListener.class, listener);
}
public TreeSelectionListener[] getTreeSelectionListeners()
{
return (TreeSelectionListener[]) getListeners(TreeSelectionListener.class);
}
protected void fireValueChanged(TreeSelectionEvent event)
{
TreeSelectionListener[] listeners = getTreeSelectionListeners();
for (int index = 0; index < listeners.length; ++index)
listeners[index].valueChanged(event);
}
public void addTreeWillExpandListener(TreeWillExpandListener listener)
{
listenerList.add(TreeWillExpandListener.class, listener);
}
public void removeTreeWillExpandListener(TreeWillExpandListener listener)
{
listenerList.remove(TreeWillExpandListener.class, listener);
}
public TreeWillExpandListener[] getTreeWillExpandListeners()
{
return (TreeWillExpandListener[]) getListeners(TreeWillExpandListener.class);
}
public void fireTreeWillCollapse(TreePath path)
throws ExpandVetoException
{
TreeExpansionEvent event = new TreeExpansionEvent(this, path);
TreeWillExpandListener[] listeners = getTreeWillExpandListeners();
for (int index = 0; index < listeners.length; ++index)
listeners[index].treeWillCollapse(event);
}
public void fireTreeWillExpand(TreePath path)
throws ExpandVetoException
{
TreeExpansionEvent event = new TreeExpansionEvent(this, path);
TreeWillExpandListener[] listeners = getTreeWillExpandListeners();
for (int index = 0; index < listeners.length; ++index)
listeners[index].treeWillExpand(event);
}
public TreeModel getModel()
{
return treeModel;
}
public void setModel(TreeModel model)
{
if (treeModel == model)
return;
TreeModel oldValue = treeModel;
treeModel = model;
firePropertyChange(TREE_MODEL_PROPERTY, oldValue, model);
}
public boolean isEditable()
{
return editable;
}
public void setEditable(boolean flag)
{
if (editable == flag)
return;
boolean oldValue = editable;
editable = flag;
firePropertyChange(EDITABLE_PROPERTY, oldValue, editable);
}
public boolean isRootVisible()
{
return rootVisible;
}
public void setRootVisible(boolean flag)
{
if (rootVisible == flag)
return;
boolean oldValue = rootVisible;
rootVisible = flag;
firePropertyChange(ROOT_VISIBLE_PROPERTY, oldValue, flag);
}
public boolean getShowsRootHandles()
{
return showsRootHandles;
}
public void setShowsRootHandles(boolean flag)
{
if (showsRootHandles == flag)
return;
boolean oldValue = showsRootHandles;
showsRootHandles = flag;
firePropertyChange(SHOWS_ROOT_HANDLES_PROPERTY, oldValue, flag);
}
public TreeCellEditor getCellEditor()
{
return cellEditor;
}
public void setCellEditor(TreeCellEditor editor)
{
if (cellEditor == editor)
return;
TreeCellEditor oldValue = cellEditor;
cellEditor = editor;
firePropertyChange(CELL_EDITOR_PROPERTY, oldValue, editor);
}
public TreeCellRenderer getCellRenderer()
{
return cellRenderer;
}
public void setCellRenderer(TreeCellRenderer newRenderer)
{
if (cellRenderer == newRenderer)
return;
TreeCellRenderer oldValue = cellRenderer;
cellRenderer = newRenderer;
firePropertyChange(CELL_RENDERER_PROPERTY, oldValue, newRenderer);
}
public TreeSelectionModel getSelectionModel()
{
return selectionModel;
}
public void setSelectionModel(TreeSelectionModel model)
{
if (selectionModel == model)
return;
TreeSelectionModel oldValue = selectionModel;
selectionModel = model;
firePropertyChange(SELECTION_MODEL_PROPERTY, oldValue, model);
}
public int getVisibleRowCount()
{
return visibleRowCount;
}
public void setVisibleRowCount(int rows)
{
if (visibleRowCount == rows)
return;
int oldValue = visibleRowCount;
visibleRowCount = rows;
firePropertyChange(VISIBLE_ROW_COUNT_PROPERTY, oldValue, rows);
}
public boolean isLargeModel()
{
return largeModel;
}
public void setLargeModel(boolean large)
{
if (largeModel == large)
return;
boolean oldValue = largeModel;
largeModel = large;
firePropertyChange(LARGE_MODEL_PROPERTY, oldValue, large);
}
public int getRowHeight()
{
return rowHeight;
}
public void setRowHeight(int height)
{
if (rowHeight == height)
return;
int oldValue = rowHeight;
rowHeight = height;
firePropertyChange(ROW_HEIGHT_PROPERTY, oldValue, height);
}
public boolean isFixedRowHeight()
{
return rowHeight > 0;
}
public boolean getInvokesStopCellEditing()
{
return invokesStopCellEditing;
}
public void setInvokesStopCellEditing(boolean invoke)
{
if (invokesStopCellEditing == invoke)
return;
boolean oldValue = invokesStopCellEditing;
invokesStopCellEditing = invoke;
firePropertyChange(INVOKES_STOP_CELL_EDITING_PROPERTY, oldValue, invoke);
}
public int getToggleClickCount()
{
return toggleClickCount;
}
public void setToggleClickCount(int count)
{
if (toggleClickCount == count)
return;
int oldValue = toggleClickCount;
toggleClickCount = count;
firePropertyChange(TOGGLE_CLICK_COUNT_PROPERTY, oldValue, count);
}
public void scrollPathToVisible(TreePath path)
{
if (path == null)
return;
Rectangle rect = getPathBounds(path);
if (rect == null)
return;
scrollRectToVisible(rect);
}
public void scrollRowToVisible(int row)
{
scrollPathToVisible(getPathForRow(row));
}
public boolean getScrollsOnExpand()
{
return scrollsOnExpand;
}
public void setScrollsOnExpand(boolean scroll)
{
if (scrollsOnExpand == scroll)
return;
boolean oldValue = scrollsOnExpand;
scrollsOnExpand = scroll;
firePropertyChange(SCROLLS_ON_EXPAND_PROPERTY, oldValue, scroll);
}
public void setSelectionPath(TreePath path)
{
selectionModel.setSelectionPath(path);
}
public void setSelectionPaths(TreePath[] paths)
{
selectionModel.setSelectionPaths(paths);
}
public void setSelectionRow(int row)
{
TreePath path = getPathForRow(row);
if (path != null)
selectionModel.setSelectionPath(path);
}
public void setSelectionRows(int[] rows)
{
if (rows == null || getUI() == null)
return;
TreePath[] paths = new TreePath[rows.length];
for (int i = rows.length - 1; i >= 0; --i)
paths[i] = getPathForRow(rows[i]);
setSelectionPaths(paths);
}
public void setSelectionInterval(int index0, int index1)
{
TreePath[] paths = getPathBetweenRows(index0, index1);
if (paths != null)
setSelectionPaths(paths);
}
public void addSelectionPath(TreePath path)
{
selectionModel.addSelectionPath(path);
}
public void addSelectionPaths(TreePath[] paths)
{
selectionModel.addSelectionPaths(paths);
}
public void addSelectionRow(int row)
{
TreePath path = getPathForRow(row);
if (path != null)
selectionModel.addSelectionPath(path);
}
public void addSelectionRows(int[] rows)
{
if (rows == null || getUI() == null)
return;
TreePath[] paths = new TreePath[rows.length];
for (int i = rows.length - 1; i >= 0; --i)
paths[i] = getPathForRow(rows[i]);
addSelectionPaths(paths);
}
public void addSelectionInterval(int index0, int index1)
{
TreePath[] paths = getPathBetweenRows(index0, index1);
if (paths != null)
addSelectionPaths(paths);
}
public void removeSelectionPath(TreePath path)
{
selectionModel.removeSelectionPath(path);
}
public void removeSelectionPaths(TreePath[] paths)
{
selectionModel.removeSelectionPaths(paths);
}
public void removeSelectionRow(int row)
{
TreePath path = getPathForRow(row);
if (path != null)
selectionModel.removeSelectionPath(path);
}
public void removeSelectionRows(int[] rows)
{
if (rows == null || getUI() == null)
return;
TreePath[] paths = new TreePath[rows.length];
for (int i = rows.length - 1; i >= 0; --i)
paths[i] = getPathForRow(rows[i]);
removeSelectionPaths(paths);
}
public void removeSelectionInterval(int index0, int index1)
{
TreePath[] paths = getPathBetweenRows(index0, index1);
if (paths != null)
removeSelectionPaths(paths);
}
public void clearSelection()
{
selectionModel.clearSelection();
}
public TreePath getLeadSelectionPath()
{
return leadSelectionPath;
}
public void setLeadSelectionPath(TreePath path)
{
if (leadSelectionPath == path)
return;
TreePath oldValue = leadSelectionPath;
leadSelectionPath = path;
firePropertyChange(LEAD_SELECTION_PATH_PROPERTY, oldValue, path);
}
public TreePath getAnchorSelectionPath()
{
return anchorSelectionPath;
}
public void setAnchorSelectionPath(TreePath path)
{
if (anchorSelectionPath == path)
return;
TreePath oldValue = anchorSelectionPath;
anchorSelectionPath = path;
firePropertyChange(ANCHOR_SELECTION_PATH_PROPERTY, oldValue, path);
}
public int getLeadSelectionRow()
{
return selectionModel.getLeadSelectionRow();
}
public int getMaxSelectionRow()
{
return selectionModel.getMaxSelectionRow();
}
public int getMinSelectionRow()
{
return selectionModel.getMinSelectionRow();
}
public int getSelectionCount()
{
return selectionModel.getSelectionCount();
}
public TreePath getSelectionPath()
{
return selectionModel.getSelectionPath();
}
public TreePath[] getSelectionPaths()
{
return selectionModel.getSelectionPaths();
}
public int[] getSelectionRows()
{
return selectionModel.getSelectionRows();
}
public boolean isPathSelected(TreePath path)
{
return selectionModel.isPathSelected(path);
}
public boolean isRowSelected(int row)
{
return selectionModel.isRowSelected(row);
}
public boolean isSelectionEmpty()
{
return selectionModel.isSelectionEmpty();
}
public boolean getDragEnabled()
{
return dragEnabled;
}
public void setDragEnabled(boolean enabled)
{
dragEnabled = enabled;
}
public int getRowCount()
{
TreeUI ui = getUI();
if (ui != null)
return ui.getRowCount(this);
return 0;
}
public void collapsePath(TreePath path)
{
setExpandedState(path, false);
}
public void collapseRow(int row)
{
if (row < 0 || row >= getRowCount())
return;
TreePath path = getPathForRow(row);
if (path != null)
collapsePath(path);
}
public void expandPath(TreePath path)
{
if ((path == null)
|| (treeModel.isLeaf(path.getLastPathComponent())))
return;
setExpandedState(path, true);
}
public void expandRow(int row)
{
if (row < 0 || row >= getRowCount())
return;
TreePath path = getPathForRow(row);
if (path != null)
expandPath(path);
}
public boolean isCollapsed(TreePath path)
{
return ! isExpanded(path);
}
public boolean isCollapsed(int row)
{
if (row < 0 || row >= getRowCount())
return false;
TreePath path = getPathForRow(row);
if (path != null)
return isCollapsed(path);
return false;
}
public boolean isExpanded(TreePath path)
{
if (path == null)
return false;
Object state = nodeStates.get(path);
if ((state == null) || (state != EXPANDED))
return false;
TreePath parent = path.getParentPath();
if (parent != null)
return isExpanded(parent);
return true;
}
public boolean isExpanded(int row)
{
if (row < 0 || row >= getRowCount())
return false;
TreePath path = getPathForRow(row);
if (path != null)
return isExpanded(path);
return false;
}
public boolean getExpandsSelectedPaths()
{
return expandsSelectedPaths;
}
public void setExpandsSelectedPaths(boolean flag)
{
if (expandsSelectedPaths == flag)
return;
boolean oldValue = expandsSelectedPaths;
expandsSelectedPaths = flag;
firePropertyChange(EXPANDS_SELECTED_PATHS_PROPERTY, oldValue, flag);
}
public Rectangle getPathBounds(TreePath path)
{
TreeUI ui = getUI();
if (ui == null)
return null;
return ui.getPathBounds(this, path);
}
public Rectangle getRowBounds(int row)
{
TreePath path = getPathForRow(row);
if (path != null)
return getPathBounds(path);
return null;
}
public boolean isEditing()
{
TreeUI ui = getUI();
if (ui != null)
return ui.isEditing(this);
return false;
}
public boolean stopEditing()
{
TreeUI ui = getUI();
if (ui != null)
return ui.stopEditing(this);
return false;
}
public void cancelEditing()
{
TreeUI ui = getUI();
if (ui != null)
ui.cancelEditing(this);
}
public void startEditingAtPath(TreePath path)
{
TreeUI ui = getUI();
if (ui != null)
ui.startEditingAtPath(this, path);
}
public TreePath getEditingPath()
{
TreeUI ui = getUI();
if (ui != null)
return ui.getEditingPath(this);
return null;
}
public TreePath getPathForLocation(int x, int y)
{
TreePath path = getClosestPathForLocation(x, y);
if (path != null)
{
Rectangle rect = getPathBounds(path);
if ((rect != null) && rect.contains(x, y))
return path;
}
return null;
}
public int getRowForLocation(int x, int y)
{
TreePath path = getPathForLocation(x, y);
if (path != null)
return getRowForPath(path);
return -1;
}
public TreePath getClosestPathForLocation(int x, int y)
{
TreeUI ui = getUI();
if (ui != null)
return ui.getClosestPathForLocation(this, x, y);
return null;
}
public int getClosestRowForLocation(int x, int y)
{
TreePath path = getClosestPathForLocation(x, y);
if (path != null)
return getRowForPath(path);
return -1;
}
public Object getLastSelectedPathComponent()
{
TreePath path = getSelectionPath();
if (path != null)
return path.getLastPathComponent();
return null;
}
private void checkExpandParents(TreePath path)
throws ExpandVetoException
{
TreePath parent = path.getParentPath();
if (parent != null)
checkExpandParents(parent);
fireTreeWillExpand(path);
}
private void doExpandParents(TreePath path, boolean state)
{
TreePath parent = path.getParentPath();
if (isExpanded(parent))
return;
if (parent != null)
doExpandParents(parent, false);
nodeStates.put(path, state ? EXPANDED : COLLAPSED);
}
protected void setExpandedState(TreePath path, boolean state)
{
if (path == null)
return;
TreePath parent = path.getParentPath();
try
{
while (parent != null)
checkExpandParents(parent);
}
catch (ExpandVetoException e)
{
return;
}
doExpandParents(path, state);
}
protected void clearToggledPaths()
{
nodeStates.clear();
}
protected Enumeration getDescendantToggledPaths(TreePath parent)
{
if (parent == null)
return null;
Enumeration nodes = nodeStates.keys();
Vector result = new Vector();
while (nodes.hasMoreElements())
{
TreePath path = (TreePath) nodes.nextElement();
if (path.isDescendant(parent))
result.addElement(path);
}
return result.elements();
}
public boolean hasBeenExpanded(TreePath path)
{
if (path == null)
return false;
return nodeStates.get(path) != null;
}
public boolean isVisible(TreePath path)
{
if (path == null)
return false;
TreePath parent = path.getParentPath();
if (parent == null)
return true;
return isExpanded(parent);
}
public void makeVisible(TreePath path)
{
if (path == null)
return;
expandPath(path.getParentPath());
}
public boolean isPathEditable(TreePath path)
{
return isEditable();
}
}