aboutsummaryrefslogtreecommitdiff
path: root/libjava/classpath/javax/swing/tree/DefaultTreeSelectionModel.java
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/classpath/javax/swing/tree/DefaultTreeSelectionModel.java')
-rw-r--r--libjava/classpath/javax/swing/tree/DefaultTreeSelectionModel.java1202
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.
- }
-}