diff options
author | Tom Tromey <tromey@gcc.gnu.org> | 2007-01-09 19:58:05 +0000 |
---|---|---|
committer | Tom Tromey <tromey@gcc.gnu.org> | 2007-01-09 19:58:05 +0000 |
commit | 97b8365cafc3a344a22d3980b8ed885f5c6d8357 (patch) | |
tree | 996a5f57d4a68c53473382e45cb22f574cb3e4db /libjava/classpath/javax/swing/tree/DefaultTreeSelectionModel.java | |
parent | c648dedbde727ca3f883bb5fd773aa4af70d3369 (diff) | |
download | gcc-97b8365cafc3a344a22d3980b8ed885f5c6d8357.zip gcc-97b8365cafc3a344a22d3980b8ed885f5c6d8357.tar.gz gcc-97b8365cafc3a344a22d3980b8ed885f5c6d8357.tar.bz2 |
Merged gcj-eclipse branch to trunk.
From-SVN: r120621
Diffstat (limited to 'libjava/classpath/javax/swing/tree/DefaultTreeSelectionModel.java')
-rw-r--r-- | libjava/classpath/javax/swing/tree/DefaultTreeSelectionModel.java | 780 |
1 files changed, 478 insertions, 302 deletions
diff --git a/libjava/classpath/javax/swing/tree/DefaultTreeSelectionModel.java b/libjava/classpath/javax/swing/tree/DefaultTreeSelectionModel.java index 0684ef7..3d9c677 100644 --- a/libjava/classpath/javax/swing/tree/DefaultTreeSelectionModel.java +++ b/libjava/classpath/javax/swing/tree/DefaultTreeSelectionModel.java @@ -44,6 +44,7 @@ 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; @@ -67,7 +68,39 @@ import javax.swing.event.TreeSelectionListener; 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. */ @@ -124,12 +157,36 @@ public class DefaultTreeSelectionModel 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 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 tmpPaths; + + /** * Constructs a new DefaultTreeSelectionModel. */ public DefaultTreeSelectionModel() { setSelectionMode(DISCONTIGUOUS_TREE_SELECTION); + listSelectionModel = new DefaultListSelectionModel(); listenerList = new EventListenerList(); + leadIndex = -1; + tmpPaths = new HashSet(); + selectedPaths = new HashSet(); } /** @@ -144,12 +201,14 @@ public class DefaultTreeSelectionModel { DefaultTreeSelectionModel cloned = (DefaultTreeSelectionModel) super.clone(); - - // Clone the selection and the list selection model. + cloned.changeSupport = null; cloned.selection = (TreePath[]) selection.clone(); - if (listSelectionModel != null) - cloned.listSelectionModel - = (DefaultListSelectionModel) listSelectionModel.clone(); + cloned.listenerList = new EventListenerList(); + cloned.listSelectionModel = + (DefaultListSelectionModel) listSelectionModel.clone(); + cloned.selectedPaths = new HashSet(); + cloned.tmpPaths = new HashSet(); + return cloned; } @@ -209,6 +268,7 @@ public class DefaultTreeSelectionModel public void setRowMapper(RowMapper mapper) { rowMapper = mapper; + resetRowSelection(); } /** @@ -236,8 +296,18 @@ public class DefaultTreeSelectionModel */ public void setSelectionMode(int mode) { + int oldMode = selectionMode; selectionMode = mode; - insureRowContinuity(); + // 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); } /** @@ -262,32 +332,10 @@ public class DefaultTreeSelectionModel */ public void setSelectionPath(TreePath path) { - // The most frequently only one cell in the tree is selected. - TreePath[] ose = selection; - selection = new TreePath[] { path }; - TreePath oldLead = leadPath; - leadIndex = 0; - leadRow = getRow(path); - leadPath = path; - - TreeSelectionEvent event; - - if (ose != null && ose.length > 0) - { - // The first item in the path list is the selected path. - // The remaining items are unselected pathes. - TreePath[] changed = new TreePath[ose.length + 1]; - boolean[] news = new boolean[changed.length]; - news[0] = true; - changed[0] = path; - System.arraycopy(ose, 0, changed, 1, ose.length); - event = new TreeSelectionEvent(this, changed, news, oldLead, path); - } - else - { - event = new TreeSelectionEvent(this, path, true, oldLead, path); - } - fireValueChanged(event); + TreePath[] paths = null; + if (path != null) + paths = new TreePath[]{ path }; + setSelectionPaths(paths); } /** @@ -307,7 +355,7 @@ public class DefaultTreeSelectionModel AbstractLayoutCache ama = (AbstractLayoutCache) mapper; return ama.getRowForPath(path); } - else + else if (mapper != null) { // Generic non optimized implementation. int[] rows = mapper.getRowsForPaths(new TreePath[] { path }); @@ -316,6 +364,7 @@ public class DefaultTreeSelectionModel else return rows[0]; } + return -1; } /** @@ -327,10 +376,90 @@ public class DefaultTreeSelectionModel */ public void setSelectionPaths(TreePath[] paths) { - // Must be called, as defined in JDK API 1.4. - insureUniqueness(); - clearSelection(); - addSelectionPaths(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 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(); + 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 newPaths = tmpPaths.iterator(); + validPaths = 0; + for (int i = 0; newPaths.hasNext(); i++) + newSelection[i] = (TreePath) 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(); + changedPaths.add(new PathPlaceHolder(selection[i], false)); + } + } + + // Perform changes and notification. + selection = newSelection; + HashSet 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); + } } /** @@ -345,29 +474,10 @@ public class DefaultTreeSelectionModel */ public void addSelectionPath(TreePath path) { - if (! isPathSelected(path)) + if (path != null) { - if (selectionMode == SINGLE_TREE_SELECTION || isSelectionEmpty() - || ! canPathBeAdded(path)) - setSelectionPath(path); - else - { - TreePath[] temp = new TreePath[selection.length + 1]; - System.arraycopy(selection, 0, temp, 0, selection.length); - temp[temp.length - 1] = path; - selection = new TreePath[temp.length]; - System.arraycopy(temp, 0, selection, 0, temp.length); - } - } - - if (path != leadPath) - { - TreePath oldLead = leadPath; - leadPath = path; - leadRow = getRow(path); - leadIndex = selection.length - 1; - fireValueChanged(new TreeSelectionEvent(this, path, true, oldLead, - leadPath)); + TreePath[] add = new TreePath[]{ path }; + addSelectionPaths(add); } } @@ -380,37 +490,76 @@ public class DefaultTreeSelectionModel */ public void addSelectionPaths(TreePath[] paths) { - // Must be called, as defined in JDK API 1.4. - insureUniqueness(); - - if (paths != null) + int length = paths != null ? paths.length : 0; + if (length > 0) { - TreePath v0 = null; - for (int i = 0; i < paths.length; i++) + 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 { - v0 = paths[i]; - if (! isPathSelected(v0)) + Vector 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 (isSelectionEmpty()) - setSelectionPath(v0); - else + if (paths[i] != null) { - TreePath[] temp = new TreePath[selection.length + 1]; - System.arraycopy(selection, 0, temp, 0, selection.length); - temp[temp.length - 1] = v0; - selection = new TreePath[temp.length]; - System.arraycopy(temp, 0, selection, 0, temp.length); + if (! selectedPaths.contains(paths[i])) + { + validPaths++; + if (changedPaths == null) + changedPaths = new Vector(); + changedPaths.add(new PathPlaceHolder(paths[i], true)); + selectedPaths.add(paths[i]); + tmpPaths.add(paths[i]); + } + leadPath = paths[i]; } - TreePath oldLead = leadPath; - leadPath = paths[paths.length - 1]; - leadRow = getRow(leadPath); - leadIndex = selection.length - 1; - - fireValueChanged(new TreeSelectionEvent(this, v0, true, - oldLead, leadPath)); } + 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 newPaths = tmpPaths.iterator(); + i = oldPaths; + while (newPaths.hasNext()) + { + newSelection[i] = (TreePath) 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(); } - insureRowContinuity(); } } @@ -422,36 +571,8 @@ public class DefaultTreeSelectionModel */ public void removeSelectionPath(TreePath path) { - if (isSelectionEmpty()) - return; - - int index = - 1; - if (isPathSelected(path)) - { - for (int i = 0; i < selection.length; i++) - { - if (selection[i].equals(path)) - { - index = i; - break; - } - } - TreePath[] temp = new TreePath[selection.length - 1]; - System.arraycopy(selection, 0, temp, 0, index); - System.arraycopy(selection, index + 1, temp, index, selection.length - - index - 1); - selection = new TreePath[temp.length]; - System.arraycopy(temp, 0, selection, 0, temp.length); - - // If the removed path was the lead path, set the lead path to null. - TreePath oldLead = leadPath; - if (path != null && leadPath != null && path.equals(leadPath)) - leadPath = null; - - fireValueChanged(new TreeSelectionEvent(this, path, false, oldLead, - leadPath)); - insureRowContinuity(); - } + if (path != null) + removeSelectionPaths(new TreePath[]{ path }); } /** @@ -462,40 +583,54 @@ public class DefaultTreeSelectionModel */ public void removeSelectionPaths(TreePath[] paths) { - if (isSelectionEmpty()) - return; - if (paths != null) + if (paths != null && selection != null && paths.length > 0) { - int index = - 1; - TreePath v0 = null; - TreePath oldLead = leadPath; - for (int i = 0; i < paths.length; i++) + if (! canPathsBeRemoved(paths)) + clearSelection(); + else { - v0 = paths[i]; - if (isPathSelected(v0)) + Vector pathsToRemove = null; + for (int i = paths.length - 1; i >= 0; i--) { - for (int x = 0; x < selection.length; x++) + if (paths[i] != null && selectedPaths.contains(paths[i])) { - if (selection[i].equals(v0)) - { - index = x; - break; - } - if (leadPath != null && leadPath.equals(v0)) + if (pathsToRemove == null) + pathsToRemove = new Vector(); + 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 keep = selectedPaths.iterator(); + for (int valid = 0; keep.hasNext(); valid++) + selection[valid] = (TreePath) keep.next(); + } + // Update lead path. + if (leadPath != null && ! selectedPaths.contains(leadPath)) + { + if (selection != null) + leadPath = selection[selection.length - 1]; + else leadPath = null; } - TreePath[] temp = new TreePath[selection.length - 1]; - System.arraycopy(selection, 0, temp, 0, index); - System.arraycopy(selection, index + 1, temp, index, - selection.length - index - 1); - selection = new TreePath[temp.length]; - System.arraycopy(temp, 0, selection, 0, temp.length); - - fireValueChanged(new TreeSelectionEvent(this, v0, false, - oldLead, leadPath)); + else if (selection != null) + leadPath = selection[selection.length - 1]; + else + leadPath = null; + updateLeadIndex(); + resetRowSelection(); + notifyPathChange(pathsToRemove, oldLead); } } - insureRowContinuity(); } } @@ -572,19 +707,22 @@ public class DefaultTreeSelectionModel */ public void clearSelection() { - if (! isSelectionEmpty()) + if (selection != null) { - TreeSelectionEvent event = new TreeSelectionEvent( - this, selection, new boolean[selection.length], leadPath, 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); } - else - { - leadPath = null; - selection = null; - } } /** @@ -638,7 +776,7 @@ public class DefaultTreeSelectionModel * @return an array of listeners * @since 1.3 */ - public EventListener[] getListeners(Class listenerType) + public <T extends EventListener> T[] getListeners(Class<T> listenerType) { return listenerList.getListeners(listenerType); } @@ -650,10 +788,43 @@ public class DefaultTreeSelectionModel */ public int[] getSelectionRows() { - if (rowMapper == null) - return null; - else - return rowMapper.getRowsForPaths(selection); + 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; } /** @@ -663,16 +834,7 @@ public class DefaultTreeSelectionModel */ public int getMinSelectionRow() { - if ((rowMapper == null) || (selection == null) || (selection.length == 0)) - return - 1; - else - { - int[] rows = rowMapper.getRowsForPaths(selection); - int minRow = Integer.MAX_VALUE; - for (int index = 0; index < rows.length; index++) - minRow = Math.min(minRow, rows[index]); - return minRow; - } + return listSelectionModel.getMinSelectionIndex(); } /** @@ -682,16 +844,7 @@ public class DefaultTreeSelectionModel */ public int getMaxSelectionRow() { - if ((rowMapper == null) || (selection == null) || (selection.length == 0)) - return - 1; - else - { - int[] rows = rowMapper.getRowsForPaths(selection); - int maxRow = - 1; - for (int index = 0; index < rows.length; index++) - maxRow = Math.max(maxRow, rows[index]); - return maxRow; - } + return listSelectionModel.getMaxSelectionIndex(); } /** @@ -706,29 +859,7 @@ public class DefaultTreeSelectionModel */ public boolean isRowSelected(int row) { - // Return false if nothing is selected. - if (isSelectionEmpty()) - return false; - - RowMapper mapper = getRowMapper(); - - if (mapper instanceof AbstractLayoutCache) - { - // The absolute majority of cases, unless the TreeUI is very - // seriously rewritten - AbstractLayoutCache ama = (AbstractLayoutCache) mapper; - TreePath path = ama.getPathForRow(row); - return isPathSelected(path); - } - else - { - // Generic non optimized implementation. - int[] rows = mapper.getRowsForPaths(selection); - for (int i = 0; i < rows.length; i++) - if (rows[i] == row) - return true; - return false; - } + return listSelectionModel.isSelectedIndex(row); } /** @@ -736,7 +867,32 @@ public class DefaultTreeSelectionModel */ public void resetRowSelection() { - // Nothing to do here. + 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; } /** @@ -766,6 +922,8 @@ public class DefaultTreeSelectionModel */ public void addPropertyChangeListener(PropertyChangeListener listener) { + if (changeSupport == null) + changeSupport = new SwingPropertyChangeSupport(this); changeSupport.addPropertyChangeListener(listener); } @@ -776,7 +934,8 @@ public class DefaultTreeSelectionModel */ public void removePropertyChangeListener(PropertyChangeListener listener) { - changeSupport.removePropertyChangeListener(listener); + if (changeSupport != null) + changeSupport.removePropertyChangeListener(listener); } /** @@ -787,7 +946,12 @@ public class DefaultTreeSelectionModel */ public PropertyChangeListener[] getPropertyChangeListeners() { - return changeSupport.getPropertyChangeListeners(); + PropertyChangeListener[] listeners = null; + if (changeSupport != null) + listeners = changeSupport.getPropertyChangeListeners(); + else + listeners = new PropertyChangeListener[0]; + return listeners; } /** @@ -801,67 +965,41 @@ public class DefaultTreeSelectionModel */ protected void insureRowContinuity() { - if (selection == null || selection.length < 2) - return; - else if (selectionMode == CONTIGUOUS_TREE_SELECTION) + if (selectionMode == CONTIGUOUS_TREE_SELECTION && selection != null + && rowMapper != null) { - if (rowMapper == null) - // This is the best we can do without the row mapper: - selectOne(); - else + int min = listSelectionModel.getMinSelectionIndex(); + if (min != -1) { - int[] rows = rowMapper.getRowsForPaths(selection); - Arrays.sort(rows); - int i; - for (i = 1; i < rows.length; i++) - { - if (rows[i - 1] != rows[i] - 1) - // Break if no longer continuous. - break; - } - - if (i < rows.length) + int max = listSelectionModel.getMaxSelectionIndex(); + for (int i = min; i <= max; i++) { - TreePath[] ns = new TreePath[i]; - for (int j = 0; j < ns.length; j++) - ns[i] = getPath(j); - setSelectionPaths(ns); + 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) - selectOne(); + else if (selectionMode == SINGLE_TREE_SELECTION && selection != null + && selection.length > 1) + setSelectionPath(selection[0]); } /** - * Keep only one (normally last or leading) path in the selection. - */ - private void selectOne() - { - if (leadIndex > 0 && leadIndex < selection.length) - setSelectionPath(selection[leadIndex]); - else - setSelectionPath(selection[selection.length - 1]); - } - - /** - * Get path for the given row that must be in the current selection. - */ - private TreePath getPath(int row) - { - if (rowMapper instanceof AbstractLayoutCache) - return ((AbstractLayoutCache) rowMapper).getPathForRow(row); - else - { - int[] rows = rowMapper.getRowsForPaths(selection); - for (int i = 0; i < rows.length; i++) - if (rows[i] == row) - return selection[i]; - } - throw new InternalError(row + " not in selection"); - } - - /** * 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. @@ -875,16 +1013,36 @@ public class DefaultTreeSelectionModel if (rowMapper == null || paths.length < 2) return true; - int[] rows = rowMapper.getRowsForPaths(paths); - - // The patches may not be sorted. - Arrays.sort(rows); - - for (int i = 1; i < rows.length; i++) + 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 (rows[i - 1] != rows[i] - 1) - return false; + 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; } @@ -904,34 +1062,51 @@ public class DefaultTreeSelectionModel */ protected boolean canPathsBeAdded(TreePath[] paths) { - if (rowMapper == null || isSelectionEmpty() - || selectionMode == DISCONTIGUOUS_TREE_SELECTION) + if (paths == null || paths.length == 0 || rowMapper == null + || selection == null || selectionMode == DISCONTIGUOUS_TREE_SELECTION) return true; - - TreePath [] all = new TreePath[paths.length + selection.length]; - System.arraycopy(paths, 0, all, 0, paths.length); - System.arraycopy(selection, 0, all, paths.length, selection.length); - return arePathsContiguous(all); + 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 single path can be added to selection. - */ - private boolean canPathBeAdded(TreePath path) - { - if (rowMapper == null || isSelectionEmpty() - || selectionMode == DISCONTIGUOUS_TREE_SELECTION) - return true; - - TreePath[] all = new TreePath[selection.length + 1]; - System.arraycopy(selection, 0, all, 0, selection.length); - all[all.length - 1] = path; - - return arePathsContiguous(all); - } - - /** * Checks if the paths can be removed without breaking the continuity of the * selection according to selectionMode. * @@ -966,20 +1141,23 @@ public class DefaultTreeSelectionModel * method will call listeners if invoked, but it is not called from the * implementation of this class. * - * @param vPathes the vector of the changed patches + * @param vPaths the vector of the changed patches * @param oldLeadSelection the old selection index */ - protected void notifyPathChange(Vector vPathes, TreePath oldLeadSelection) + protected void notifyPathChange(Vector vPaths, TreePath oldLeadSelection) { - TreePath[] pathes = new TreePath[vPathes.size()]; - for (int i = 0; i < pathes.length; i++) - pathes[i] = (TreePath) vPathes.get(i); - boolean[] news = new boolean[pathes.length]; - for (int i = 0; i < news.length; i++) - news[i] = isPathSelected(pathes[i]); + int numChangedPaths = vPaths.size(); + boolean[] news = new boolean[numChangedPaths]; + TreePath[] paths = new TreePath[numChangedPaths]; + for (int i = 0; i < numChangedPaths; i++) + { + PathPlaceHolder p = (PathPlaceHolder) vPaths.get(i); + news[i] = p.isNew; + paths[i] = p.path; + } - TreeSelectionEvent event = new TreeSelectionEvent(this, pathes, news, + TreeSelectionEvent event = new TreeSelectionEvent(this, paths, news, oldLeadSelection, leadPath); fireValueChanged(event); @@ -991,22 +1169,20 @@ public class DefaultTreeSelectionModel */ protected void updateLeadIndex() { - if (isSelectionEmpty()) + leadIndex = -1; + if (leadPath != null) { - leadRow = leadIndex = - 1; - } - else - { - leadRow = getRow(leadPath); - for (int i = 0; i < selection.length; i++) + leadRow = -1; + if (selection == null) + leadPath = null; + else { - if (selection[i].equals(leadPath)) + for (int i = selection.length - 1; i >= 0 && leadIndex == -1; i--) { - leadIndex = i; - break; + if (selection[i] == leadPath) + leadIndex = i; } } - leadIndex = leadRow; } } |