FileDocCategorySizeDatePackage
DefaultTreeSelectionModel.javaAPI DocJava SE 5 API38269Fri Aug 26 14:58:20 BST 2005javax.swing.tree

DefaultTreeSelectionModel

public class DefaultTreeSelectionModel extends Object implements Serializable, Cloneable, TreeSelectionModel
Default implementation of TreeSelectionModel. Listeners are notified whenever the paths in the selection change, not the rows. In order to be able to track row changes you may wish to become a listener for expansion events on the tree and test for changes from there.

resetRowSelection is called from any of the methods that update the selected paths. If you subclass any of these methods to filter what is allowed to be selected, be sure and message resetRowSelection if you do not message super.

Warning: Serialized objects of this class will not be compatible with future Swing releases. The current serialization support is appropriate for short term storage or RMI between applications running the same version of Swing. As of 1.4, support for long term storage of all JavaBeansTM has been added to the java.beans package. Please see {@link java.beans.XMLEncoder}.

see
javax.swing.JTree
version
1.50 05/05/04
author
Scott Violet

Fields Summary
public static final String
SELECTION_MODE_PROPERTY
Property name for selectionMode.
protected SwingPropertyChangeSupport
changeSupport
Used to messaged registered listeners.
protected TreePath[]
selection
Paths that are currently selected. Will be null if nothing is currently selected.
protected EventListenerList
listenerList
Event listener list.
protected transient RowMapper
rowMapper
Provides a row for a given path.
protected DefaultListSelectionModel
listSelectionModel
Handles maintaining the list selection model. The RowMapper is used to map from a TreePath to a row, and the value is then placed here.
protected int
selectionMode
Mode for the selection, will be either SINGLE_TREE_SELECTION, CONTIGUOUS_TREE_SELECTION or DISCONTIGUOUS_TREE_SELECTION.
protected TreePath
leadPath
Last path that was added.
protected int
leadIndex
Index of the lead path in selection.
protected int
leadRow
Lead row.
private Hashtable
uniquePaths
Used to make sure the paths are unique, will contain all the paths in selection.
private Hashtable
lastPaths
private TreePath[]
tempPaths
Constructors Summary
public DefaultTreeSelectionModel()
Creates a new instance of DefaultTreeSelectionModel that is empty, with a selection mode of DISCONTIGUOUS_TREE_SELECTION.



                        
      
	listSelectionModel = new DefaultListSelectionModel();
	selectionMode = DISCONTIGUOUS_TREE_SELECTION;
	leadIndex = leadRow = -1;
	uniquePaths = new Hashtable();
	lastPaths = new Hashtable();
	tempPaths = new TreePath[1];
    
Methods Summary
public synchronized voidaddPropertyChangeListener(java.beans.PropertyChangeListener listener)
Adds a PropertyChangeListener to the listener list. The listener is registered for all properties.

A PropertyChangeEvent will get fired when the selection mode changes.

param
listener the PropertyChangeListener to be added

        if (changeSupport == null) {
            changeSupport = new SwingPropertyChangeSupport(this);
        }
        changeSupport.addPropertyChangeListener(listener);
    
public voidaddSelectionPath(javax.swing.tree.TreePath path)
Adds path to the current selection. If path is not currently in the selection the TreeSelectionListeners are notified. This has no effect if path is null.

param
path the new path to add to the current selection

	if(path != null) {
	    TreePath[]            toAdd = new TreePath[1];

	    toAdd[0] = path;
	    addSelectionPaths(toAdd);
	}
    
public voidaddSelectionPaths(javax.swing.tree.TreePath[] paths)
Adds paths to the current selection. If any of the paths in paths are not currently in the selection the TreeSelectionListeners are notified. This has no effect if paths is null.

The lead path is set to the last element in paths.

If the selection mode is CONTIGUOUS_TREE_SELECTION, and adding the new paths would make the selection discontiguous. Then two things can result: if the TreePaths in paths are contiguous, then the selection becomes these TreePaths, otherwise the TreePaths aren't contiguous and the selection becomes the first TreePath in paths.

param
paths the new path to add to the current selection

	int       newPathLength = ((paths == null) ? 0 : paths.length);

	if(newPathLength > 0) {
	    if(selectionMode == TreeSelectionModel.SINGLE_TREE_SELECTION) {
		setSelectionPaths(paths);
	    }
	    else if(selectionMode == TreeSelectionModel.
		    CONTIGUOUS_TREE_SELECTION && !canPathsBeAdded(paths)) {
		if(arePathsContiguous(paths)) {
		    setSelectionPaths(paths);
		}
		else {
		    TreePath[]          newPaths = new TreePath[1];

		    newPaths[0] = paths[0];
		    setSelectionPaths(newPaths);
		}
	    }
	    else {
		int               counter, validCount;
		int               oldCount;
		TreePath          beginLeadPath = leadPath;
		Vector            cPaths = null;

		if(selection == null)
		    oldCount = 0;
		else
		    oldCount = selection.length;
		/* Determine the paths that aren't currently in the
		   selection. */
		lastPaths.clear();
		for(counter = 0, validCount = 0; counter < newPathLength;
		    counter++) {
		    if(paths[counter] != null) {
			if (uniquePaths.get(paths[counter]) == null) {
			    validCount++;
			    if(cPaths == null)
				cPaths = new Vector();
			    cPaths.addElement(new PathPlaceHolder
					      (paths[counter], true));
			    uniquePaths.put(paths[counter], Boolean.TRUE);
			    lastPaths.put(paths[counter], Boolean.TRUE);
			}
			leadPath = paths[counter];
		    }
		}

		if(leadPath == null) {
		    leadPath = beginLeadPath;
		}

		if(validCount > 0) {
		    TreePath         newSelection[] = new TreePath[oldCount +
								  validCount];

		    /* And build the new selection. */
		    if(oldCount > 0) 
			System.arraycopy(selection, 0, newSelection, 0,
					 oldCount);
		    if(validCount != paths.length) {
			/* Some of the paths in paths are already in
			   the selection. */
			Enumeration   newPaths = lastPaths.keys();

			counter = oldCount;
			while (newPaths.hasMoreElements()) {
			    newSelection[counter++] = (TreePath)newPaths.
				                      nextElement();
			}
		    }
		    else {
			System.arraycopy(paths, 0, newSelection, oldCount,
					 validCount);
		    }

		    selection = newSelection;

		    insureUniqueness();

		    updateLeadIndex();

		    resetRowSelection();

		    notifyPathChange(cPaths, beginLeadPath);
		}
		else
		    leadPath = beginLeadPath;
		lastPaths.clear();
	    }
	}
    
public voidaddTreeSelectionListener(javax.swing.event.TreeSelectionListener x)
Adds x to the list of listeners that are notified each time the set of selected TreePaths changes.

param
x the new listener to be added

	listenerList.add(TreeSelectionListener.class, x);
    
protected booleanarePathsContiguous(javax.swing.tree.TreePath[] paths)
Returns true if the paths are contiguous, or this object has no RowMapper.

	if(rowMapper == null || paths.length < 2)
	    return true;
	else {
	    BitSet                             bitSet = new BitSet(32);
	    int                                anIndex, counter, min;
	    int                                pathCount = paths.length;
	    int                                validCount = 0;
	    TreePath[]                         tempPath = new TreePath[1];

	    tempPath[0] = paths[0];
	    min = rowMapper.getRowsForPaths(tempPath)[0];
	    for(counter = 0; counter < pathCount; counter++) {
		if(paths[counter] != null) {
		    tempPath[0] = paths[counter];
		    int[] rows = rowMapper.getRowsForPaths(tempPath);
		    if (rows == null) {
			return false;
		    }
		    anIndex = rows[0];
		    if(anIndex == -1 || anIndex < (min - pathCount) ||
		       anIndex > (min + pathCount))
			return false;
		    if(anIndex < min)
			min = anIndex;
		    if(!bitSet.get(anIndex)) {
			bitSet.set(anIndex);
			validCount++;
		    }
		}
	    }
	    int          maxCounter = validCount + min;

	    for(counter = min; counter < maxCounter; counter++)
		if(!bitSet.get(counter))
		    return false;
	}
	return true;
    
protected booleancanPathsBeAdded(javax.swing.tree.TreePath[] paths)
Used to test if a particular set of TreePaths can be added. This will return true if paths is null (or empty), or this object has no RowMapper, or nothing is currently selected, or the selection mode is DISCONTIGUOUS_TREE_SELECTION, or adding the paths to the current selection still results in a contiguous set of TreePaths.

	if(paths == null || paths.length == 0 || rowMapper == null ||
	   selection == null || selectionMode ==
	   TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION)
	    return true;
	else {
	    BitSet                       bitSet = new BitSet();
	    DefaultListSelectionModel    lModel = listSelectionModel;
	    int                          anIndex;
	    int                          counter;
	    int                          min = lModel.getMinSelectionIndex();
	    int	                         max = lModel.getMaxSelectionIndex();
	    TreePath[]                   tempPath = new TreePath[1];

	    if(min != -1) {
		for(counter = min; counter <= max; counter++) {
		    if(lModel.isSelectedIndex(counter))
			bitSet.set(counter);
		}
	    }
	    else {
		tempPath[0] = paths[0];
		min = max = rowMapper.getRowsForPaths(tempPath)[0];
	    }
	    for(counter = paths.length - 1; counter >= 0; counter--) {
		if(paths[counter] != null) {
		    tempPath[0] = paths[counter];
		    int[]   rows = rowMapper.getRowsForPaths(tempPath);
		    if (rows == null) {
			return false;
		    }
		    anIndex = rows[0];
		    min = Math.min(anIndex, min);
		    max = Math.max(anIndex, max);
		    if(anIndex == -1)
			return false;
		    bitSet.set(anIndex);
		}
	    }
	    for(counter = min; counter <= max; counter++)
		if(!bitSet.get(counter))
		    return false;
	}
	return true;
    
protected booleancanPathsBeRemoved(javax.swing.tree.TreePath[] paths)
Returns true if the paths can be removed without breaking the continuity of the model. This is rather expensive.

	if(rowMapper == null || selection == null ||
	   selectionMode == TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION)
	    return true;
	else {
	    BitSet               bitSet = new BitSet();
	    int                  counter;
	    int                  pathCount = paths.length;
	    int                  anIndex;
	    int                  min = -1;
	    int                  validCount = 0;
	    TreePath[]           tempPath = new TreePath[1];
	    int[]                rows;

	    /* Determine the rows for the removed entries. */
	    lastPaths.clear();
	    for (counter = 0; counter < pathCount; counter++) {
		if (paths[counter] != null) {
		    lastPaths.put(paths[counter], Boolean.TRUE);
		}
	    }
	    for(counter = selection.length - 1; counter >= 0; counter--) {
		if(lastPaths.get(selection[counter]) == null) {
		    tempPath[0] = selection[counter];
		    rows = rowMapper.getRowsForPaths(tempPath);
		    if(rows != null && rows[0] != -1 && !bitSet.get(rows[0])) {
			validCount++;
			if(min == -1)
			    min = rows[0];
			else
			    min = Math.min(min, rows[0]);
			bitSet.set(rows[0]);
		    }
		}
	    }
	    lastPaths.clear();
	    /* Make sure they are contiguous. */
	    if(validCount > 1) {
		for(counter = min + validCount - 1; counter >= min;
		    counter--)
		    if(!bitSet.get(counter))
			return false;
	    }
	}
	return true;
    
public voidclearSelection()
Empties the current selection. If this represents a change in the current selection, the selection listeners are notified.

	if(selection != null) {
	    int                    selSize = selection.length;
	    boolean[]              newness = new boolean[selSize];

	    for(int counter = 0; counter < selSize; counter++)
		newness[counter] = false;

	    TreeSelectionEvent     event = new TreeSelectionEvent
		(this, selection, newness, leadPath, null);

	    leadPath = null;
	    leadIndex = leadRow = -1;
	    uniquePaths.clear();
	    selection = null;
	    resetRowSelection();
	    fireValueChanged(event);
	}
    
public java.lang.Objectclone()
Returns a clone of this object with the same selection. This method does not duplicate selection listeners and property listeners.

exception
CloneNotSupportedException never thrown by instances of this class

	DefaultTreeSelectionModel        clone = (DefaultTreeSelectionModel)
	                    super.clone();

	clone.changeSupport = null;
	if(selection != null) {
	    int              selLength = selection.length;

	    clone.selection = new TreePath[selLength];
	    System.arraycopy(selection, 0, clone.selection, 0, selLength);
	}
	clone.listenerList = new EventListenerList();
	clone.listSelectionModel = (DefaultListSelectionModel)
	    listSelectionModel.clone();
	clone.uniquePaths = new Hashtable();
	clone.lastPaths = new Hashtable();
	clone.tempPaths = new TreePath[1];
	return clone;
    
protected voidfireValueChanged(javax.swing.event.TreeSelectionEvent e)
Notifies all listeners that are registered for tree selection events on this object.

see
#addTreeSelectionListener
see
EventListenerList

	// Guaranteed to return a non-null array
	Object[] listeners = listenerList.getListenerList();
	// TreeSelectionEvent e = null;
	// Process the listeners last to first, notifying
	// those that are interested in this event
	for (int i = listeners.length-2; i>=0; i-=2) {
	    if (listeners[i]==TreeSelectionListener.class) {
		// Lazily create the event:
		// if (e == null)
		// e = new ListSelectionEvent(this, firstIndex, lastIndex);
		((TreeSelectionListener)listeners[i+1]).valueChanged(e);
	    }	       
	}
    
public javax.swing.tree.TreePathgetLeadSelectionPath()
Returns the last path that was added. This may differ from the leadSelectionPath property maintained by the JTree.

	return leadPath;
    
public intgetLeadSelectionRow()
Returns the lead selection index. That is the last index that was added.

	return leadRow;
    
public T[]getListeners(java.lang.Class listenerType)
Returns an array of all the objects currently registered as FooListeners upon this model. FooListeners are registered using the addFooListener method.

You can specify the listenerType argument with a class literal, such as FooListener.class. For example, you can query a DefaultTreeSelectionModel m for its tree selection listeners with the following code:

TreeSelectionListener[] tsls = (TreeSelectionListener[])(m.getListeners(TreeSelectionListener.class));
If no such listeners exist, this method returns an empty array.

param
listenerType the type of listeners requested; this parameter should specify an interface that descends from java.util.EventListener
return
an array of all objects registered as FooListeners on this component, or an empty array if no such listeners have been added
exception
ClassCastException if listenerType doesn't specify a class or interface that implements java.util.EventListener
see
#getTreeSelectionListeners
see
#getPropertyChangeListeners
since
1.3

 
	return listenerList.getListeners(listenerType); 
    
public intgetMaxSelectionRow()
Returns the largest value obtained from the RowMapper for the current set of selected TreePaths. If nothing is selected, or there is no RowMapper, this will return -1.

	return listSelectionModel.getMaxSelectionIndex();
    
public intgetMinSelectionRow()
Returns the smallest value obtained from the RowMapper for the current set of selected TreePaths. If nothing is selected, or there is no RowMapper, this will return -1.

	return listSelectionModel.getMinSelectionIndex();
    
public java.beans.PropertyChangeListener[]getPropertyChangeListeners()
Returns an array of all the property change listeners registered on this DefaultTreeSelectionModel.

return
all of this model's PropertyChangeListeners or an empty array if no property change listeners are currently registered
see
#addPropertyChangeListener
see
#removePropertyChangeListener
since
1.4

        if (changeSupport == null) {
            return new PropertyChangeListener[0];
        }
        return changeSupport.getPropertyChangeListeners();
    
public javax.swing.tree.RowMappergetRowMapper()
Returns the RowMapper instance that is able to map a TreePath to a row.

	return rowMapper;
    
public intgetSelectionCount()
Returns the number of paths that are selected.

	return (selection == null) ? 0 : selection.length;
    
public intgetSelectionMode()
Returns the selection mode, one of SINGLE_TREE_SELECTION, DISCONTIGUOUS_TREE_SELECTION or CONTIGUOUS_TREE_SELECTION.

	return selectionMode;
    
public javax.swing.tree.TreePathgetSelectionPath()
Returns the first path in the selection. This is useful if there if only one item currently selected.

	if(selection != null)
	    return selection[0];
	return null;
    
public javax.swing.tree.TreePath[]getSelectionPaths()
Returns the paths in the selection. This will return null (or an empty array) if nothing is currently selected.

	if(selection != null) {
	    int                 pathSize = selection.length;
	    TreePath[]          result = new TreePath[pathSize];

	    System.arraycopy(selection, 0, result, 0, pathSize);
	    return result;
	}
	return null;
    
public int[]getSelectionRows()
Returns all of the currently selected rows. This will return null (or an empty array) if there are no selected TreePaths or a RowMapper has not been set. This may return an array of length less that than of the selected TreePaths if some of the rows are not visible (that is the RowMapper returned -1 for the row corresponding to the TreePath).

	// This is currently rather expensive.  Needs
	// to be better support from ListSelectionModel to speed this up.
	if(rowMapper != null && selection != null) {
	    int[]      rows = rowMapper.getRowsForPaths(selection);

	    if (rows != null) {
		int       invisCount = 0;

		for (int counter = rows.length - 1; counter >= 0; counter--) {
		    if (rows[counter] == -1) {
			invisCount++;
		    }
		}
		if (invisCount > 0) {
		    if (invisCount == rows.length) {
			rows = null;
		    }
		    else {
			int[]    tempRows = new int[rows.length - invisCount];

			for (int counter = rows.length - 1, visCounter = 0;
			     counter >= 0; counter--) {
			    if (rows[counter] != -1) {
				tempRows[visCounter++] = rows[counter];
			    }
			}
			rows = tempRows;
		    }
		}
	    }
	    return rows;
	}
	return null;
    
public javax.swing.event.TreeSelectionListener[]getTreeSelectionListeners()
Returns an array of all the tree selection listeners registered on this model.

return
all of this model's TreeSelectionListeners or an empty array if no tree selection listeners are currently registered
see
#addTreeSelectionListener
see
#removeTreeSelectionListener
since
1.4

        return (TreeSelectionListener[])listenerList.getListeners(
                TreeSelectionListener.class);
    
protected voidinsureRowContinuity()
Makes sure the currently selected TreePaths are valid for the current selection mode. If the selection mode is CONTIGUOUS_TREE_SELECTION and a RowMapper exists, this will make sure all the rows are contiguous, that is, when sorted all the rows are in order with no gaps. If the selection isn't contiguous, the selection is reset to contain the first set, when sorted, of contiguous rows.

If the selection mode is SINGLE_TREE_SELECTION and more than one TreePath is selected, the selection is reset to contain the first path currently selected.

	if(selectionMode == TreeSelectionModel.CONTIGUOUS_TREE_SELECTION &&
	   selection != null && rowMapper != null) {
	    DefaultListSelectionModel lModel = listSelectionModel;
	    int                       min = lModel.getMinSelectionIndex();

	    if(min != -1) {
		for(int counter = min,
			maxCounter = lModel.getMaxSelectionIndex();
		        counter <= maxCounter; counter++) {
		    if(!lModel.isSelectedIndex(counter)) {
			if(counter == min) {
			    clearSelection();
			}
			else {
			    TreePath[] newSel = new TreePath[counter - min];
			    int selectionIndex[] = rowMapper.getRowsForPaths(selection);
			    // find the actual selection pathes corresponded to the
			    // rows of the new selection
			    for (int i = 0; i < selectionIndex.length; i++) {
				if (selectionIndex[i]<counter) {
				    newSel[selectionIndex[i]-min] = selection[i];
				}
			    }
			    setSelectionPaths(newSel);
			    break;
			}
		    }
		}
	    }
	}
	else if(selectionMode == TreeSelectionModel.SINGLE_TREE_SELECTION &&
		selection != null && selection.length > 1) {
	    setSelectionPath(selection[0]);
	}
    
protected voidinsureUniqueness()
This method is obsolete and its implementation is now a noop. It's still called by setSelectionPaths and addSelectionPaths, but only for backwards compatability.

    
public booleanisPathSelected(javax.swing.tree.TreePath path)
Returns true if the path, path, is in the current selection.

	return (path != null) ? (uniquePaths.get(path) != null) : false;
    
public booleanisRowSelected(int row)
Returns true if the row identified by row is selected.

	return listSelectionModel.isSelectedIndex(row);
    
public booleanisSelectionEmpty()
Returns true if the selection is currently empty.

	return (selection == null);
    
protected voidnotifyPathChange(java.util.Vector changedPaths, javax.swing.tree.TreePath oldLeadSelection)
Notifies listeners of a change in path. changePaths should contain instances of PathPlaceHolder.

	int                    cPathCount = changedPaths.size();
	boolean[]              newness = new boolean[cPathCount];
	TreePath[]            paths = new TreePath[cPathCount];
	PathPlaceHolder        placeholder;
	
	for(int counter = 0; counter < cPathCount; counter++) {
	    placeholder = (PathPlaceHolder)changedPaths.elementAt(counter);
	    newness[counter] = placeholder.isNew;
	    paths[counter] = placeholder.path;
	}
	
	TreeSelectionEvent     event = new TreeSelectionEvent
	                  (this, paths, newness, oldLeadSelection, leadPath);
	
	fireValueChanged(event);
    
private voidreadObject(java.io.ObjectInputStream s)

	Object[]      tValues;

	s.defaultReadObject();

	tValues = (Object[])s.readObject();

	if(tValues.length > 0 && tValues[0].equals("rowMapper"))
	    rowMapper = (RowMapper)tValues[1];
    
public synchronized voidremovePropertyChangeListener(java.beans.PropertyChangeListener listener)
Removes a PropertyChangeListener from the listener list. This removes a PropertyChangeListener that was registered for all properties.

param
listener the PropertyChangeListener to be removed

        if (changeSupport == null) {
            return;
        }
        changeSupport.removePropertyChangeListener(listener);
    
public voidremoveSelectionPath(javax.swing.tree.TreePath path)
Removes path from the selection. If path is in the selection The TreeSelectionListeners are notified. This has no effect if path is null.

param
path the path to remove from the selection

	if(path != null) {
	    TreePath[]             rPath = new TreePath[1];

	    rPath[0] = path;
	    removeSelectionPaths(rPath);
	}
    
public voidremoveSelectionPaths(javax.swing.tree.TreePath[] paths)
Removes paths from the selection. If any of the paths in paths are in the selection the TreeSelectionListeners are notified. This has no effect if paths is null.

param
paths the paths to remove from the selection

	if (paths != null && selection != null && paths.length > 0) {
	    if(!canPathsBeRemoved(paths)) {
		/* Could probably do something more interesting here! */
		clearSelection();
	    }
	    else {
		Vector      pathsToRemove = null;

		/* Find the paths that can be removed. */
		for (int removeCounter = paths.length - 1; removeCounter >= 0;
		     removeCounter--) {
		    if(paths[removeCounter] != null) {
			if (uniquePaths.get(paths[removeCounter]) != null) {
			    if(pathsToRemove == null)
				pathsToRemove = new Vector(paths.length);
			    uniquePaths.remove(paths[removeCounter]);
			    pathsToRemove.addElement(new PathPlaceHolder
					 (paths[removeCounter], false));
			}
		    }
		}
		if(pathsToRemove != null) {
		    int         removeCount = pathsToRemove.size();
		    TreePath    beginLeadPath = leadPath;

		    if(removeCount == selection.length) {
			selection = null;
		    }
		    else {
			Enumeration          pEnum = uniquePaths.keys();
			int                  validCount = 0;

			selection = new TreePath[selection.length -
						removeCount];
			while (pEnum.hasMoreElements()) {
			    selection[validCount++] = (TreePath)pEnum.
				                          nextElement();
			}
		    }
		    if (leadPath != null &&
			uniquePaths.get(leadPath) == null) {
			if (selection != null) {
			    leadPath = selection[selection.length - 1];
			}
			else {
			    leadPath = null;
			}
		    }
		    else if (selection != null) {
			leadPath = selection[selection.length - 1];
		    }
		    else {
			leadPath = null;
		    }
		    updateLeadIndex();

		    resetRowSelection();

		    notifyPathChange(pathsToRemove, beginLeadPath);
		}
	    }
	}
    
public voidremoveTreeSelectionListener(javax.swing.event.TreeSelectionListener x)
Removes x from the list of listeners that are notified each time the set of selected TreePaths changes.

param
x the listener to remove

	listenerList.remove(TreeSelectionListener.class, x);
    
public voidresetRowSelection()
Updates this object's mapping from TreePath to rows. This should be invoked when the mapping from TreePaths to integers has changed (for example, a node has been expanded).

You do not normally have to call this, JTree and its associated Listeners will invoke this for you. If you are implementing your own View class, then you will have to invoke this.

This will invoke insureRowContinuity to make sure the currently selected TreePaths are still valid based on the selection mode.

	listSelectionModel.clearSelection();
	if(selection != null && rowMapper != null) {
	    int               aRow;
	    int               validCount = 0;
	    int[]             rows = rowMapper.getRowsForPaths(selection);

	    for(int counter = 0, maxCounter = selection.length;
		counter < maxCounter; counter++) {
		aRow = rows[counter];
		if(aRow != -1) {
		    listSelectionModel.addSelectionInterval(aRow, aRow);
		}
	    }
	    if(leadIndex != -1 && rows != null) {
		leadRow = rows[leadIndex];
	    }
	    else if (leadPath != null) {
		// Lead selection path doesn't have to be in the selection.
		tempPaths[0] = leadPath;
		rows = rowMapper.getRowsForPaths(tempPaths);
		leadRow = (rows != null) ? rows[0] : -1;
	    }
	    else {
		leadRow = -1;
	    }
	    insureRowContinuity();

	}
	else
	    leadRow = -1;
    
public voidsetRowMapper(javax.swing.tree.RowMapper newMapper)
Sets the RowMapper instance. This instance is used to determine the row for a particular TreePath.

	rowMapper = newMapper;
	resetRowSelection();
    
public voidsetSelectionMode(int mode)
Sets the selection model, which must be one of SINGLE_TREE_SELECTION, CONTIGUOUS_TREE_SELECTION or DISCONTIGUOUS_TREE_SELECTION. If mode is not one of the defined value, DISCONTIGUOUS_TREE_SELECTION is assumed.

This may change the selection if the current selection is not valid for the new mode. For example, if three TreePaths are selected when the mode is changed to SINGLE_TREE_SELECTION, only one TreePath will remain selected. It is up to the particular implementation to decide what TreePath remains selected.

Setting the mode to something other than the defined types will result in the mode becoming DISCONTIGUOUS_TREE_SELECTION.

	int            oldMode = selectionMode;

	selectionMode = mode;
	if(selectionMode != TreeSelectionModel.SINGLE_TREE_SELECTION &&
	   selectionMode != TreeSelectionModel.CONTIGUOUS_TREE_SELECTION &&
	   selectionMode != TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION)
	    selectionMode = TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION;
	if(oldMode != selectionMode && changeSupport != null)
	    changeSupport.firePropertyChange(SELECTION_MODE_PROPERTY,
					     new Integer(oldMode),
					     new Integer(selectionMode));
    
public voidsetSelectionPath(javax.swing.tree.TreePath path)
Sets the selection to path. If this represents a change, then the TreeSelectionListeners are notified. If path is null, this has the same effect as invoking clearSelection.

param
path new path to select

	if(path == null)
	    setSelectionPaths(null);
	else {
	    TreePath[]          newPaths = new TreePath[1];

	    newPaths[0] = path;
	    setSelectionPaths(newPaths);
	}
    
public voidsetSelectionPaths(javax.swing.tree.TreePath[] pPaths)
Sets the selection to the paths in paths. If this represents a change the TreeSelectionListeners are notified. Potentially paths will be held by this object; in other words don't change any of the objects in the array once passed in.

If paths is null, this has the same effect as invoking clearSelection.

The lead path is set to the last path in pPaths.

If the selection mode is CONTIGUOUS_TREE_SELECTION, and adding the new paths would make the selection discontiguous, the selection is reset to the first TreePath in paths.

param
pPaths new selection

	int            newCount, newCounter, oldCount, oldCounter;
	TreePath[]     paths = pPaths;

	if(paths == null)
	    newCount = 0;
	else
	    newCount = paths.length;
	if(selection == null)
	    oldCount = 0;
	else
	    oldCount = selection.length;
	if((newCount + oldCount) != 0) {
	    if(selectionMode == TreeSelectionModel.SINGLE_TREE_SELECTION) {
		/* If single selection and more than one path, only allow
		   first. */
		if(newCount > 1) {
		    paths = new TreePath[1];
		    paths[0] = pPaths[0];
		    newCount = 1;
		}
	    }
	    else if(selectionMode ==
		    TreeSelectionModel.CONTIGUOUS_TREE_SELECTION) {
		/* If contiguous selection and paths aren't contiguous,
		   only select the first path item. */
		if(newCount > 0 && !arePathsContiguous(paths)) {
		    paths = new TreePath[1];
		    paths[0] = pPaths[0];
		    newCount = 1;
		}
	    }

	    int              validCount = 0;
	    TreePath         beginLeadPath = leadPath;
	    Vector           cPaths = new Vector(newCount + oldCount);

	    lastPaths.clear();
	    leadPath = null;
	    /* Find the paths that are new. */
	    for(newCounter = 0; newCounter < newCount; newCounter++) {
		if(paths[newCounter] != null &&
		   lastPaths.get(paths[newCounter]) == null) {
		    validCount++;
		    lastPaths.put(paths[newCounter], Boolean.TRUE);
		    if (uniquePaths.get(paths[newCounter]) == null) {
			cPaths.addElement(new PathPlaceHolder
					  (paths[newCounter], true));
		    }
		    leadPath = paths[newCounter];
		}
	    }

	    /* If the validCount isn't equal to newCount it means there
	       are some null in paths, remove them and set selection to
	       the new path. */
	    TreePath[]     newSelection;

	    if(validCount == 0) {
		newSelection = null;
	    }
	    else if (validCount != newCount) {
		Enumeration keys = lastPaths.keys();

		newSelection = new TreePath[validCount];
		validCount = 0;
		while (keys.hasMoreElements()) {
		    newSelection[validCount++] = (TreePath)keys.nextElement();
		}
	    }
	    else {
		newSelection = new TreePath[paths.length];
		System.arraycopy(paths, 0, newSelection, 0, paths.length);
	    }

	    /* Get the paths that were selected but no longer selected. */
	    for(oldCounter = 0; oldCounter < oldCount; oldCounter++)
		if(selection[oldCounter] != null && 
		    lastPaths.get(selection[oldCounter]) == null)
		    cPaths.addElement(new PathPlaceHolder
				      (selection[oldCounter], false));

	    selection = newSelection;

	    Hashtable      tempHT = uniquePaths;

	    uniquePaths = lastPaths;
	    lastPaths = tempHT;
	    lastPaths.clear();

	    // No reason to do this now, but will still call it.
	    if(selection != null)
		insureUniqueness();

	    updateLeadIndex();

	    resetRowSelection();
	    /* Notify of the change. */
	    if(cPaths.size() > 0)
		notifyPathChange(cPaths, beginLeadPath);
	}
    
public java.lang.StringtoString()
Returns a string that displays and identifies this object's properties.

return
a String representation of this object

	int                selCount = getSelectionCount();
	StringBuffer       retBuffer = new StringBuffer();
	int[]              rows;

	if(rowMapper != null)
	    rows = rowMapper.getRowsForPaths(selection);
	else
	    rows = null;
	retBuffer.append(getClass().getName() + " " + hashCode() + " [ ");
	for(int counter = 0; counter < selCount; counter++) {
	    if(rows != null)
		retBuffer.append(selection[counter].toString() + "@" +
				 Integer.toString(rows[counter])+ " ");
	    else
		retBuffer.append(selection[counter].toString() + " ");
	}
	retBuffer.append("]");
	return retBuffer.toString();
    
protected voidupdateLeadIndex()
Updates the leadIndex instance variable.

	if(leadPath != null) {
	    if(selection == null) {
		leadPath = null;
		leadIndex = leadRow = -1;
	    }
	    else {
		leadRow = leadIndex = -1;
		for(int counter = selection.length - 1; counter >= 0;
		    counter--) {
		    // Can use == here since we know leadPath came from
		    // selection
		    if(selection[counter] == leadPath) {
			leadIndex = counter;
			break;
		    }
		}
	    }
	}
	else {
	    leadIndex = -1;
	}
    
private voidwriteObject(java.io.ObjectOutputStream s)

	Object[]             tValues;

	s.defaultWriteObject();
	// Save the rowMapper, if it implements Serializable
	if(rowMapper != null && rowMapper instanceof Serializable) {
	    tValues = new Object[2];
	    tValues[0] = "rowMapper";
	    tValues[1] = rowMapper;
	}
	else
	    tValues = new Object[0];
	s.writeObject(tValues);