diff options
Diffstat (limited to 'libjava/classpath/javax/swing/tree/DefaultTreeSelectionModel.java')
-rw-r--r-- | libjava/classpath/javax/swing/tree/DefaultTreeSelectionModel.java | 1202 |
1 files changed, 0 insertions, 1202 deletions
diff --git a/libjava/classpath/javax/swing/tree/DefaultTreeSelectionModel.java b/libjava/classpath/javax/swing/tree/DefaultTreeSelectionModel.java deleted file mode 100644 index 29add0e..0000000 --- a/libjava/classpath/javax/swing/tree/DefaultTreeSelectionModel.java +++ /dev/null @@ -1,1202 +0,0 @@ -/* DefaultTreeSelectionModel.java - Copyright (C) 2002, 2004, 2005, 2006 Free Software Foundation, Inc. - -This file is part of GNU Classpath. - -GNU Classpath is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU Classpath is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU Classpath; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. */ - - -package javax.swing.tree; - -import gnu.java.lang.CPStringBuilder; - -import java.beans.PropertyChangeListener; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.Serializable; -import java.util.Arrays; -import java.util.BitSet; -import java.util.EventListener; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Vector; - -import javax.swing.DefaultListSelectionModel; -import javax.swing.event.EventListenerList; -import javax.swing.event.SwingPropertyChangeSupport; -import javax.swing.event.TreeSelectionEvent; -import javax.swing.event.TreeSelectionListener; - -/** - * The implementation of the default tree selection model. The installed - * listeners are notified about the path and not the row changes. If you - * specifically need to track the row changes, register the listener for the - * expansion events. - * - * @author Andrew Selkirk - * @author Audrius Meskauskas - */ -public class DefaultTreeSelectionModel - implements Cloneable, Serializable, TreeSelectionModel -{ - - /** - * According to the API docs, the method - * {@link DefaultTreeSelectionModel#notifyPathChange} should - * expect instances of a class PathPlaceHolder in the Vector parameter. - * This seems to be a non-public class, so I can only make guesses about the - * use of it. - */ - private static class PathPlaceHolder - { - /** - * The path that we wrap. - */ - TreePath path; - - /** - * Indicates if the path is new or already in the selection. - */ - boolean isNew; - - /** - * Creates a new instance. - * - * @param p the path to wrap - * @param n if the path is new or already in the selection - */ - PathPlaceHolder(TreePath p, boolean n) - { - path = p; - isNew = n; - } - } - - /** - * Use serialVersionUID for interoperability. - */ - static final long serialVersionUID = 3288129636638950196L; - - /** - * The name of the selection mode property. - */ - public static final String SELECTION_MODE_PROPERTY = "selectionMode"; - - /** - * Our Swing property change support. - */ - protected SwingPropertyChangeSupport changeSupport; - - /** - * The current selection. - */ - protected TreePath[] selection; - - /** - * Our TreeSelectionListeners. - */ - protected EventListenerList listenerList; - - /** - * The current RowMapper. - */ - protected transient RowMapper rowMapper; - - /** - * The current listSelectionModel. - */ - protected DefaultListSelectionModel listSelectionModel; - - /** - * The current selection mode. - */ - protected int selectionMode; - - /** - * The path that has been added last. - */ - protected TreePath leadPath; - - /** - * The index of the last added path. - */ - protected int leadIndex; - - /** - * The row of the last added path according to the RowMapper. - */ - protected int leadRow = -1; - - /** - * A supporting datastructure that is used in addSelectionPaths() and - * removeSelectionPaths(). It contains currently selected paths. - * - * @see #addSelectionPaths(TreePath[]) - * @see #removeSelectionPaths(TreePath[]) - * @see #setSelectionPaths(TreePath[]) - */ - private transient HashSet<TreePath> selectedPaths; - - /** - * A supporting datastructure that is used in addSelectionPaths() and - * removeSelectionPaths(). It contains the paths that are added or removed. - * - * @see #addSelectionPaths(TreePath[]) - * @see #removeSelectionPaths(TreePath[]) - * @see #setSelectionPaths(TreePath[]) - */ - private transient HashSet<TreePath> tmpPaths; - - /** - * Constructs a new DefaultTreeSelectionModel. - */ - public DefaultTreeSelectionModel() - { - setSelectionMode(DISCONTIGUOUS_TREE_SELECTION); - listSelectionModel = new DefaultListSelectionModel(); - listenerList = new EventListenerList(); - leadIndex = -1; - tmpPaths = new HashSet<TreePath>(); - selectedPaths = new HashSet<TreePath>(); - } - - /** - * Creates a clone of this DefaultTreeSelectionModel with the same selection. - * The cloned instance will have the same registered listeners, the listeners - * themselves will not be cloned. The selection will be cloned. - * - * @exception CloneNotSupportedException should not be thrown here - * @return a copy of this DefaultTreeSelectionModel - */ - public Object clone() throws CloneNotSupportedException - { - DefaultTreeSelectionModel cloned = - (DefaultTreeSelectionModel) super.clone(); - cloned.changeSupport = null; - cloned.selection = (TreePath[]) selection.clone(); - cloned.listenerList = new EventListenerList(); - cloned.listSelectionModel = - (DefaultListSelectionModel) listSelectionModel.clone(); - cloned.selectedPaths = new HashSet<TreePath>(); - cloned.tmpPaths = new HashSet<TreePath>(); - - return cloned; - } - - /** - * Returns a string that shows this object's properties. - * The returned string lists the selected tree rows, if any. - * - * @return a string that shows this object's properties - */ - public String toString() - { - if (isSelectionEmpty()) - return "[selection empty]"; - else - { - CPStringBuilder b = new CPStringBuilder("selected rows: ["); - for (int i = 0; i < selection.length; i++) - { - b.append(getRow(selection[i])); - b.append(' '); - } - b.append(", lead " + getLeadSelectionRow()); - return b.toString(); - } - } - - /** - * writeObject - * - * @param value0 TODO - * @exception IOException TODO - */ - private void writeObject(ObjectOutputStream value0) throws IOException - { - // TODO - } - - /** - * readObject - * - * @param value0 TODO - * @exception IOException TODO - * @exception ClassNotFoundException TODO - */ - private void readObject(ObjectInputStream value0) throws IOException, - ClassNotFoundException - { - // TODO - } - - /** - * Sets the RowMapper that should be used to map between paths and their rows. - * - * @param mapper the RowMapper to set - * @see RowMapper - */ - public void setRowMapper(RowMapper mapper) - { - rowMapper = mapper; - resetRowSelection(); - } - - /** - * Returns the RowMapper that is currently used to map between paths and their - * rows. - * - * @return the current RowMapper - * @see RowMapper - */ - public RowMapper getRowMapper() - { - return rowMapper; - } - - /** - * Sets the current selection mode. Possible values are - * {@link #SINGLE_TREE_SELECTION}, {@link #CONTIGUOUS_TREE_SELECTION} and - * {@link #DISCONTIGUOUS_TREE_SELECTION}. - * - * @param mode the selection mode to be set - * @see #getSelectionMode - * @see #SINGLE_TREE_SELECTION - * @see #CONTIGUOUS_TREE_SELECTION - * @see #DISCONTIGUOUS_TREE_SELECTION - */ - public void setSelectionMode(int mode) - { - int oldMode = selectionMode; - selectionMode = mode; - // Make sure we have a valid selection mode. - if (selectionMode != SINGLE_TREE_SELECTION - && selectionMode != CONTIGUOUS_TREE_SELECTION - && selectionMode != DISCONTIGUOUS_TREE_SELECTION) - selectionMode = DISCONTIGUOUS_TREE_SELECTION; - - // Fire property change event. - if (oldMode != selectionMode && changeSupport != null) - changeSupport.firePropertyChange(SELECTION_MODE_PROPERTY, oldMode, - selectionMode); - } - - /** - * Returns the current selection mode. - * - * @return the current selection mode - * @see #setSelectionMode - * @see #SINGLE_TREE_SELECTION - * @see #CONTIGUOUS_TREE_SELECTION - * @see #DISCONTIGUOUS_TREE_SELECTION - */ - public int getSelectionMode() - { - return selectionMode; - } - - /** - * Sets this path as the only selection. If this changes the selection the - * registered TreeSelectionListeners are notified. - * - * @param path the path to set as selection - */ - public void setSelectionPath(TreePath path) - { - TreePath[] paths = null; - if (path != null) - paths = new TreePath[]{ path }; - setSelectionPaths(paths); - } - - /** - * Get the number of the tree row for the given path. - * - * @param path the tree path - * @return the tree row for this path or -1 if the path is not visible. - */ - int getRow(TreePath path) - { - RowMapper mapper = getRowMapper(); - - if (mapper instanceof AbstractLayoutCache) - { - // The absolute majority of cases, unless the TreeUI is very - // seriously rewritten - AbstractLayoutCache ama = (AbstractLayoutCache) mapper; - return ama.getRowForPath(path); - } - else if (mapper != null) - { - // Generic non optimized implementation. - int[] rows = mapper.getRowsForPaths(new TreePath[] { path }); - if (rows.length == 0) - return - 1; - else - return rows[0]; - } - return -1; - } - - /** - * Sets the paths as selection. This method checks for duplicates and removes - * them. If this changes the selection the registered TreeSelectionListeners - * are notified. - * - * @param paths the paths to set as selection - */ - public void setSelectionPaths(TreePath[] paths) - { - int oldLength = 0; - if (selection != null) - oldLength = selection.length; - int newLength = 0; - if (paths != null) - newLength = paths.length; - if (newLength > 0 || oldLength > 0) - { - // For SINGLE_TREE_SELECTION and for CONTIGUOUS_TREE_SELECTION with - // a non-contiguous path, we only allow the first path element. - if ((selectionMode == SINGLE_TREE_SELECTION && newLength > 1) - || (selectionMode == CONTIGUOUS_TREE_SELECTION && newLength > 0 - && ! arePathsContiguous(paths))) - { - paths = new TreePath[] { paths[0] }; - newLength = 1; - } - // Find new paths. - Vector<PathPlaceHolder> changedPaths = null; - tmpPaths.clear(); - int validPaths = 0; - TreePath oldLeadPath = leadPath; - for (int i = 0; i < newLength; i++) - { - if (paths[i] != null && ! tmpPaths.contains(paths[i])) - { - validPaths++; - tmpPaths.add(paths[i]); - if (! selectedPaths.contains(paths[i])) - { - if (changedPaths == null) - changedPaths = new Vector<PathPlaceHolder>(); - changedPaths.add(new PathPlaceHolder(paths[i], true)); - } - leadPath = paths[i]; - } - } - // Put together the new selection. - TreePath[] newSelection = null; - if (validPaths != 0) - { - if (validPaths != newLength) - { - // Some of the paths are already selected, put together - // the new selection carefully. - newSelection = new TreePath[validPaths]; - Iterator<TreePath> newPaths = tmpPaths.iterator(); - validPaths = 0; - for (int i = 0; newPaths.hasNext(); i++) - newSelection[i] = newPaths.next(); - } - else - { - newSelection = new TreePath[paths.length]; - System.arraycopy(paths, 0, newSelection, 0, paths.length); - } - } - - // Find paths that have been selected, but are no more. - for (int i = 0; i < oldLength; i++) - { - if (selection[i] != null && ! tmpPaths.contains(selection[i])) - { - if (changedPaths == null) - changedPaths = new Vector<PathPlaceHolder>(); - changedPaths.add(new PathPlaceHolder(selection[i], false)); - } - } - - // Perform changes and notification. - selection = newSelection; - HashSet<TreePath> tmp = selectedPaths; - selectedPaths = tmpPaths; - tmpPaths = tmp; - tmpPaths.clear(); - - // Not necessary, but required according to the specs and to tests. - if (selection != null) - insureUniqueness(); - updateLeadIndex(); - resetRowSelection(); - if (changedPaths != null && changedPaths.size() > 0) - notifyPathChange(changedPaths, oldLeadPath); - } - } - - /** - * Adds a path to the list of selected paths. This method checks if the path - * is already selected and doesn't add the same path twice. If this changes - * the selection the registered TreeSelectionListeners are notified. - * - * The lead path is changed to the added path. This also happen if the - * passed path was already selected before. - * - * @param path the path to add to the selection - */ - public void addSelectionPath(TreePath path) - { - if (path != null) - { - TreePath[] add = new TreePath[]{ path }; - addSelectionPaths(add); - } - } - - /** - * Adds the paths to the list of selected paths. This method checks if the - * paths are already selected and doesn't add the same path twice. If this - * changes the selection the registered TreeSelectionListeners are notified. - * - * @param paths the paths to add to the selection - */ - public void addSelectionPaths(TreePath[] paths) - { - int length = paths != null ? paths.length : 0; - if (length > 0) - { - if (selectionMode == SINGLE_TREE_SELECTION) - setSelectionPaths(paths); - else if (selectionMode == CONTIGUOUS_TREE_SELECTION - && ! canPathsBeAdded(paths)) - { - if (arePathsContiguous(paths)) - setSelectionPaths(paths); - else - setSelectionPaths(new TreePath[] { paths[0] }); - } - else - { - Vector<PathPlaceHolder> changedPaths = null; - tmpPaths.clear(); - int validPaths = 0; - TreePath oldLeadPath = leadPath; - int oldPaths = 0; - if (selection != null) - oldPaths = selection.length; - int i; - for (i = 0; i < length; i++) - { - if (paths[i] != null) - { - if (! selectedPaths.contains(paths[i])) - { - validPaths++; - if (changedPaths == null) - changedPaths = new Vector<PathPlaceHolder>(); - changedPaths.add(new PathPlaceHolder(paths[i], true)); - selectedPaths.add(paths[i]); - tmpPaths.add(paths[i]); - } - leadPath = paths[i]; - } - } - if (validPaths > 0) - { - TreePath[] newSelection = new TreePath[oldPaths + validPaths]; - if (oldPaths > 0) - System.arraycopy(selection, 0, newSelection, 0, oldPaths); - if (validPaths != paths.length) - { - // Some of the paths are already selected, put together - // the new selection carefully. - Iterator<TreePath> newPaths = tmpPaths.iterator(); - i = oldPaths; - while (newPaths.hasNext()) - { - newSelection[i] = newPaths.next(); - i++; - } - } - else - System.arraycopy(paths, 0, newSelection, oldPaths, - validPaths); - selection = newSelection; - insureUniqueness(); - updateLeadIndex(); - resetRowSelection(); - if (changedPaths != null && changedPaths.size() > 0) - notifyPathChange(changedPaths, oldLeadPath); - } - else - leadPath = oldLeadPath; - tmpPaths.clear(); - } - } - } - - /** - * Removes the path from the selection. If this changes the selection the - * registered TreeSelectionListeners are notified. - * - * @param path the path to remove - */ - public void removeSelectionPath(TreePath path) - { - if (path != null) - removeSelectionPaths(new TreePath[]{ path }); - } - - /** - * Removes the paths from the selection. If this changes the selection the - * registered TreeSelectionListeners are notified. - * - * @param paths the paths to remove - */ - public void removeSelectionPaths(TreePath[] paths) - { - if (paths != null && selection != null && paths.length > 0) - { - if (! canPathsBeRemoved(paths)) - clearSelection(); - else - { - Vector<PathPlaceHolder> pathsToRemove = null; - for (int i = paths.length - 1; i >= 0; i--) - { - if (paths[i] != null && selectedPaths.contains(paths[i])) - { - if (pathsToRemove == null) - pathsToRemove = new Vector<PathPlaceHolder>(); - selectedPaths.remove(paths[i]); - pathsToRemove.add(new PathPlaceHolder(paths[i], - false)); - } - } - if (pathsToRemove != null) - { - int numRemove = pathsToRemove.size(); - TreePath oldLead = leadPath; - if (numRemove == selection.length) - selection = null; - else - { - selection = new TreePath[selection.length - numRemove]; - Iterator<TreePath> keep = selectedPaths.iterator(); - for (int valid = 0; keep.hasNext(); valid++) - selection[valid] = keep.next(); - } - // Update lead path. - if (leadPath != null && ! selectedPaths.contains(leadPath)) - { - 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, oldLead); - } - } - } - } - - /** - * Returns the first path in the selection. This is especially useful when the - * selectionMode is {@link #SINGLE_TREE_SELECTION}. - * - * @return the first path in the selection - */ - public TreePath getSelectionPath() - { - if ((selection == null) || (selection.length == 0)) - return null; - else - return selection[0]; - } - - /** - * Returns the complete selection. - * - * @return the complete selection - */ - public TreePath[] getSelectionPaths() - { - return selection; - } - - /** - * Returns the number of paths in the selection. - * - * @return the number of paths in the selection - */ - public int getSelectionCount() - { - if (selection == null) - return 0; - else - return selection.length; - } - - /** - * Checks if a given path is in the selection. - * - * @param path the path to check - * @return <code>true</code> if the path is in the selection, - * <code>false</code> otherwise - */ - public boolean isPathSelected(TreePath path) - { - if (selection == null) - return false; - - for (int i = 0; i < selection.length; i++) - { - if (selection[i].equals(path)) - return true; - } - return false; - } - - /** - * Checks if the selection is empty. - * - * @return <code>true</code> if the selection is empty, <code>false</code> - * otherwise - */ - public boolean isSelectionEmpty() - { - return (selection == null) || (selection.length == 0); - } - - /** - * Removes all paths from the selection. Fire the unselection event. - */ - public void clearSelection() - { - if (selection != null) - { - int selectionLength = selection.length; - boolean[] news = new boolean[selectionLength]; - Arrays.fill(news, false); - TreeSelectionEvent event = new TreeSelectionEvent(this, selection, - news, leadPath, - null); - leadPath = null; - leadIndex = 0; - leadRow = 0; - selectedPaths.clear(); - selection = null; - resetRowSelection(); - fireValueChanged(event); - } - } - - /** - * Adds a <code>TreeSelectionListener</code> object to this model. - * - * @param listener the listener to add - */ - public void addTreeSelectionListener(TreeSelectionListener listener) - { - listenerList.add(TreeSelectionListener.class, listener); - } - - /** - * Removes a <code>TreeSelectionListener</code> object from this model. - * - * @param listener the listener to remove - */ - public void removeTreeSelectionListener(TreeSelectionListener listener) - { - listenerList.remove(TreeSelectionListener.class, listener); - } - - /** - * Returns all <code>TreeSelectionListener</code> added to this model. - * - * @return an array of listeners - * @since 1.4 - */ - public TreeSelectionListener[] getTreeSelectionListeners() - { - return (TreeSelectionListener[]) getListeners(TreeSelectionListener.class); - } - - /** - * fireValueChanged - * - * @param event the event to fire. - */ - protected void fireValueChanged(TreeSelectionEvent event) - { - TreeSelectionListener[] listeners = getTreeSelectionListeners(); - - for (int i = 0; i < listeners.length; ++i) - listeners[i].valueChanged(event); - } - - /** - * Returns all added listeners of a special type. - * - * @param listenerType the listener type - * @return an array of listeners - * @since 1.3 - */ - public <T extends EventListener> T[] getListeners(Class<T> listenerType) - { - return listenerList.getListeners(listenerType); - } - - /** - * Returns the currently selected rows. - * - * @return the currently selected rows - */ - public int[] getSelectionRows() - { - int[] rows = null; - if (rowMapper != null && selection != null) - { - rows = rowMapper.getRowsForPaths(selection); - if (rows != null) - { - // Find invisible rows. - int invisible = 0; - for (int i = rows.length - 1; i >= 0; i--) - { - if (rows[i] == -1) - invisible++; - - } - // Clean up invisible rows. - if (invisible > 0) - { - if (invisible == rows.length) - rows = null; - else - { - int[] newRows = new int[rows.length - invisible]; - int visCount = 0; - for (int i = rows.length - 1; i >= 0; i--) - { - if (rows[i] != -1) - { - newRows[visCount] = rows[i]; - visCount++; - } - } - rows = newRows; - } - } - } - } - return rows; - } - - /** - * Returns the smallest row index from the selection. - * - * @return the smallest row index from the selection - */ - public int getMinSelectionRow() - { - return listSelectionModel.getMinSelectionIndex(); - } - - /** - * Returns the largest row index from the selection. - * - * @return the largest row index from the selection - */ - public int getMaxSelectionRow() - { - return listSelectionModel.getMaxSelectionIndex(); - } - - /** - * Checks if a particular row is selected. - * - * @param row the index of the row to check - * @return <code>true</code> if the row is in this selection, - * <code>false</code> otherwise - * @throws NullPointerException if the row mapper is not set (can only happen - * if the user has plugged in the custom incorrect TreeUI - * implementation. - */ - public boolean isRowSelected(int row) - { - return listSelectionModel.isSelectedIndex(row); - } - - /** - * Updates the mappings from TreePaths to row indices. - */ - public void resetRowSelection() - { - listSelectionModel.clearSelection(); - if (selection != null && rowMapper != null) - { - int[] rows = rowMapper.getRowsForPaths(selection); - // Update list selection model. - for (int i = 0; i < rows.length; i++) - { - int row = rows[i]; - if (row != -1) - listSelectionModel.addSelectionInterval(row, row); - } - // Update lead selection. - if (leadIndex != -1 && rows != null) - leadRow = rows[leadIndex]; - else if (leadPath != null) - { - TreePath[] tmp = new TreePath[]{ leadPath }; - rows = rowMapper.getRowsForPaths(tmp); - leadRow = rows != null ? rows[0] : -1; - } - else - leadRow = -1; - insureRowContinuity(); - } - else - leadRow = -1; - } - - /** - * getLeadSelectionRow - * - * @return int - */ - public int getLeadSelectionRow() - { - return leadRow; - } - - /** - * getLeadSelectionPath - * - * @return TreePath - */ - public TreePath getLeadSelectionPath() - { - return leadPath; - } - - /** - * Adds a <code>PropertyChangeListener</code> object to this model. - * - * @param listener the listener to add. - */ - public void addPropertyChangeListener(PropertyChangeListener listener) - { - if (changeSupport == null) - changeSupport = new SwingPropertyChangeSupport(this); - changeSupport.addPropertyChangeListener(listener); - } - - /** - * Removes a <code>PropertyChangeListener</code> object from this model. - * - * @param listener the listener to remove. - */ - public void removePropertyChangeListener(PropertyChangeListener listener) - { - if (changeSupport != null) - changeSupport.removePropertyChangeListener(listener); - } - - /** - * Returns all added <code>PropertyChangeListener</code> objects. - * - * @return an array of listeners. - * @since 1.4 - */ - public PropertyChangeListener[] getPropertyChangeListeners() - { - PropertyChangeListener[] listeners = null; - if (changeSupport != null) - listeners = changeSupport.getPropertyChangeListeners(); - else - listeners = new PropertyChangeListener[0]; - return listeners; - } - - /** - * Makes sure the currently selected paths are valid according to the current - * selectionMode. If the selectionMode is set to - * {@link #CONTIGUOUS_TREE_SELECTION} and the selection isn't contiguous then - * the selection is reset to the first set of contguous paths. If the - * selectionMode is set to {@link #SINGLE_TREE_SELECTION} and the selection - * has more than one path, the selection is reset to the contain only the - * first path. - */ - protected void insureRowContinuity() - { - if (selectionMode == CONTIGUOUS_TREE_SELECTION && selection != null - && rowMapper != null) - { - int min = listSelectionModel.getMinSelectionIndex(); - if (min != -1) - { - int max = listSelectionModel.getMaxSelectionIndex(); - for (int i = min; i <= max; i++) - { - if (! listSelectionModel.isSelectedIndex(i)) - { - if (i == min) - clearSelection(); - else - { - TreePath[] newSelection = new TreePath[i - min]; - int[] rows = rowMapper.getRowsForPaths(selection); - for (int j = 0; j < rows.length; j++) - { - if (rows[j] < i) - newSelection[rows[j] - min] = selection[j]; - } - setSelectionPaths(newSelection); - break; - } - } - } - } - } - else if (selectionMode == SINGLE_TREE_SELECTION && selection != null - && selection.length > 1) - setSelectionPath(selection[0]); - } - - /** - * Returns <code>true</code> if the paths are contiguous (take subsequent - * rows in the diplayed tree view. The method returns <code>true</code> if - * we have no RowMapper assigned. - * - * @param paths the paths to check for continuity - * @return <code>true</code> if the paths are contiguous or we have no - * RowMapper assigned - */ - protected boolean arePathsContiguous(TreePath[] paths) - { - if (rowMapper == null || paths.length < 2) - return true; - - int length = paths.length; - TreePath[] tmp = new TreePath[1]; - tmp[0] = paths[0]; - int min = rowMapper.getRowsForPaths(tmp)[0]; - BitSet selected = new BitSet(); - int valid = 0; - for (int i = 0; i < length; i++) - { - if (paths[i] != null) - { - tmp[0] = paths[i]; - int[] rows = rowMapper.getRowsForPaths(tmp); - if (rows == null) - return false; // No row mapping yet, can't be selected. - int row = rows[0]; - if (row == -1 || row < (min - length) || row > (min + length)) - return false; // Not contiguous. - min = Math.min(min, row); - if (! selected.get(row)) - { - selected.set(row); - valid++; - } - - } - } - int max = valid + min; - for (int i = min; i < max; i++) - if (! selected.get(i)) - return false; // Not contiguous. - return true; - } - - /** - * Checks if the paths can be added. This returns <code>true</code> if: - * <ul> - * <li><code>paths</code> is <code>null</code> or empty</li> - * <li>we have no RowMapper assigned</li> - * <li>nothing is currently selected</li> - * <li>selectionMode is {@link #DISCONTIGUOUS_TREE_SELECTION}</li> - * <li>adding the paths to the selection still results in a contiguous set of - * paths</li> - * - * @param paths the paths to check - * @return <code>true</code> if the paths can be added with respect to the - * selectionMode - */ - protected boolean canPathsBeAdded(TreePath[] paths) - { - if (paths == null || paths.length == 0 || rowMapper == null - || selection == null || selectionMode == DISCONTIGUOUS_TREE_SELECTION) - return true; - - BitSet selected = new BitSet(); - int min = listSelectionModel.getMinSelectionIndex(); - int max = listSelectionModel.getMaxSelectionIndex(); - TreePath[] tmp = new TreePath[1]; - if (min != -1) - { - // Set the bitmask of selected elements. - for (int i = min; i <= max; i++) - selected.set(i); - } - else - { - tmp[0] = paths[0]; - min = rowMapper.getRowsForPaths(tmp)[0]; - max = min; - } - // Mark new paths as selected. - for (int i = paths.length - 1; i >= 0; i--) - { - if (paths[i] != null) - { - tmp[0] = paths[i]; - int[] rows = rowMapper.getRowsForPaths(tmp); - if (rows == null) - return false; // Now row mapping yet, can't be selected. - int row = rows[0]; - if (row == -1) - return false; // Now row mapping yet, can't be selected. - min = Math.min(min, row); - max = Math.max(max, row); - selected.set(row); - } - } - // Now look if the new selection would be contiguous. - for (int i = min; i <= max; i++) - if (! selected.get(i)) - return false; - return true; - } - - /** - * Checks if the paths can be removed without breaking the continuity of the - * selection according to selectionMode. - * - * @param paths the paths to check - * @return <code>true</code> if the paths can be removed with respect to the - * selectionMode - */ - protected boolean canPathsBeRemoved(TreePath[] paths) - { - if (rowMapper == null || isSelectionEmpty() - || selectionMode == DISCONTIGUOUS_TREE_SELECTION) - return true; - - HashSet<TreePath> set = new HashSet<TreePath>(); - for (int i = 0; i < selection.length; i++) - set.add(selection[i]); - - for (int i = 0; i < paths.length; i++) - set.remove(paths[i]); - - TreePath[] remaining = new TreePath[set.size()]; - Iterator<TreePath> iter = set.iterator(); - - for (int i = 0; i < remaining.length; i++) - remaining[i] = iter.next(); - - return arePathsContiguous(remaining); - } - - /** - * Notify the installed listeners that the given patches have changed. This - * method will call listeners if invoked, but it is not called from the - * implementation of this class. - * - * @param vPaths the vector of the changed patches - * @param oldLeadSelection the old selection index - */ - protected void notifyPathChange(Vector<PathPlaceHolder> vPaths, - TreePath oldLeadSelection) - { - - int numChangedPaths = vPaths.size(); - boolean[] news = new boolean[numChangedPaths]; - TreePath[] paths = new TreePath[numChangedPaths]; - for (int i = 0; i < numChangedPaths; i++) - { - PathPlaceHolder p = vPaths.get(i); - news[i] = p.isNew; - paths[i] = p.path; - } - - TreeSelectionEvent event = new TreeSelectionEvent(this, paths, news, - oldLeadSelection, - leadPath); - fireValueChanged(event); - } - - /** - * Updates the lead selection row number after changing the lead selection - * path. - */ - protected void updateLeadIndex() - { - leadIndex = -1; - if (leadPath != null) - { - leadRow = -1; - if (selection == null) - leadPath = null; - else - { - for (int i = selection.length - 1; i >= 0 && leadIndex == -1; i--) - { - if (selection[i] == leadPath) - leadIndex = i; - } - } - } - } - - /** - * This method exists due historical reasons and returns without action - * (unless overridden). For compatibility with the applications that override - * it, it is still called from the {@link #setSelectionPaths(TreePath[])} and - * {@link #addSelectionPaths(TreePath[])}. - */ - protected void insureUniqueness() - { - // Following the API 1.4, the method should return without action. - } -} |