1 /* DefaultTreeSelectionModel.java
2 Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
38 package javax.swing.tree;
40 import java.beans.PropertyChangeListener;
41 import java.io.IOException;
42 import java.io.ObjectInputStream;
43 import java.io.ObjectOutputStream;
44 import java.io.Serializable;
45 import java.util.EventListener;
46 import java.util.Vector;
48 import javax.swing.DefaultListSelectionModel;
49 import javax.swing.event.EventListenerList;
50 import javax.swing.event.SwingPropertyChangeSupport;
51 import javax.swing.event.TreeSelectionEvent;
52 import javax.swing.event.TreeSelectionListener;
55 * DefaultTreeSelectionModel
57 * @author Andrew Selkirk
59 public class DefaultTreeSelectionModel
60 implements Cloneable, Serializable, TreeSelectionModel
62 static final long serialVersionUID = 3288129636638950196L;
65 * SELECTION_MODE_PROPERTY
67 public static final String SELECTION_MODE_PROPERTY = "selectionMode";
70 * Our Swing property change support.
72 protected SwingPropertyChangeSupport changeSupport;
75 * The current selection.
77 protected TreePath[] selection;
80 * Our TreeSelectionListeners.
82 protected EventListenerList listenerList;
85 * The current RowMapper.
87 protected transient RowMapper rowMapper;
90 * The current listSelectionModel.
92 protected DefaultListSelectionModel listSelectionModel;
95 * The current selection mode.
97 protected int selectionMode;
100 * The path that has been added last.
102 protected TreePath leadPath;
105 * The index of the last added path.
107 protected int leadIndex;
110 * The row of the last added path according to the RowMapper.
112 protected int leadRow;
115 * Constructs a new DefaultTreeSelectionModel.
117 public DefaultTreeSelectionModel()
119 setSelectionMode(SINGLE_TREE_SELECTION);
120 listenerList = new EventListenerList();
124 * Creates a clone of this DefaultTreeSelectionModel with the same
127 * @exception CloneNotSupportedException should not be thrown here
129 * @return a clone of this DefaultTreeSelectionModel
131 public Object clone() throws CloneNotSupportedException
137 * Returns a string that shows this object's properties.
139 * @return a string that shows this object's properties
141 public String toString()
150 * @exception IOException TODO
152 private void writeObject(ObjectOutputStream value0) throws IOException
161 * @exception IOException TODO
162 * @exception ClassNotFoundException TODO
164 private void readObject(ObjectInputStream value0) throws IOException,
165 ClassNotFoundException
171 * Sets the RowMapper that should be used to map between paths and their
174 * @param rowMapper the RowMapper to set
178 public void setRowMapper(RowMapper rowMapper)
184 * Returns the RowMapper that is currently used to map between paths and
187 * @return the current RowMapper
191 public RowMapper getRowMapper()
197 * Sets the current selection mode. Possible values are
198 * {@link #SINGLE_TREE_SELECTION}, {@link #CONTIGUOUS_TREE_SELECTION} and
199 * {@link #DISCONTIGUOUS_TREE_SELECTION}.
201 * @param mode the selection mode to be set
203 * @see #getSelectionMode
204 * @see #SINGLE_TREE_SELECTION
205 * @see #CONTIGUOUS_TREE_SELECTION
206 * @see #DISCONTIGUOUS_TREE_SELECTION
208 public void setSelectionMode(int mode)
210 selectionMode = mode;
214 * Returns the current selection mode.
216 * @return the current selection mode
218 * @see #setSelectionMode
219 * @see #SINGLE_TREE_SELECTION
220 * @see #CONTIGUOUS_TREE_SELECTION
221 * @see #DISCONTIGUOUS_TREE_SELECTION
223 public int getSelectionMode()
225 return selectionMode;
229 * Sets this path as the only selection.
231 * If this changes the selection the registered TreeSelectionListeners are
234 * @param path the path to set as selection
236 public void setSelectionPath(TreePath path)
238 selection = new TreePath[] {
243 * Sets the paths as selection. This method checks for duplicates and
246 * If this changes the selection the registered TreeSelectionListeners are
249 * @param paths the paths to set as selection
251 public void setSelectionPaths(TreePath[] paths)
257 * Adds a path to the list of selected paths. This method checks if the path
258 * is already selected and doesn't add the same path twice.
260 * If this changes the selection the registered TreeSelectionListeners are
263 * @param path the path to add to the selection
265 public void addSelectionPath(TreePath path)
267 if (!isPathSelected(path))
269 if (isSelectionEmpty())
270 setSelectionPath(path);
273 TreePath[] temp = new TreePath[selection.length + 1];
274 System.arraycopy(selection, 0, temp, 0, selection.length);
275 temp[temp.length - 1] = path;
276 selection = new TreePath[temp.length];
277 System.arraycopy(temp, 0, selection, 0, temp.length);
280 fireValueChanged(new TreeSelectionEvent(this, path, true,
286 * Adds the paths to the list of selected paths. This method checks if the
287 * paths are already selected and doesn't add the same path twice.
289 * If this changes the selection the registered TreeSelectionListeners are
292 * @param paths the paths to add to the selection
294 public void addSelectionPaths(TreePath[] paths)
299 for (int i = 0; i < paths.length; i++)
302 if (!isPathSelected(v0))
304 if (isSelectionEmpty())
305 setSelectionPath(v0);
308 TreePath[] temp = new TreePath[selection.length + 1];
309 System.arraycopy(selection, 0, temp, 0,
311 temp[temp.length - 1] = v0;
312 selection = new TreePath[temp.length];
313 System.arraycopy(temp, 0, selection, 0, temp.length);
315 leadPath = paths[paths.length - 1];
316 fireValueChanged(new TreeSelectionEvent(this, v0, true,
317 leadPath, paths[0]));
324 * Removes the path from the selection.
326 * If this changes the selection the registered TreeSelectionListeners are
329 * @param path the path to remove
331 public void removeSelectionPath(TreePath path)
334 if (isPathSelected(path))
336 for (int i = 0; i < selection.length; i++)
338 if (selection[i].equals(path))
344 TreePath[] temp = new TreePath[selection.length - 1];
345 System.arraycopy(selection, 0, temp, 0, index);
346 System.arraycopy(selection, index + 1, temp, index,
347 selection.length - index - 1);
348 selection = new TreePath[temp.length];
349 System.arraycopy(temp, 0, selection, 0, temp.length);
351 fireValueChanged(new TreeSelectionEvent(this, path, false,
357 * Removes the paths from the selection.
359 * If this changes the selection the registered TreeSelectionListeners are
362 * @param paths the paths to remove
364 public void removeSelectionPaths(TreePath[] paths)
370 for (int i = 0; i < paths.length; i++)
373 if (isPathSelected(v0))
375 for (int x = 0; x < selection.length; x++)
377 if (selection[i].equals(v0))
383 TreePath[] temp = new TreePath[selection.length - 1];
384 System.arraycopy(selection, 0, temp, 0, index);
385 System.arraycopy(selection, index + 1, temp, index,
386 selection.length - index - 1);
387 selection = new TreePath[temp.length];
388 System.arraycopy(temp, 0, selection, 0, temp.length);
390 fireValueChanged(new TreeSelectionEvent(this, v0, false,
391 leadPath, paths[0]));
398 * Returns the first path in the selection. This is especially useful when
399 * the selectionMode is {@link #SINGLE_TREE_SELECTION}.
401 * @return the first path in the selection
403 public TreePath getSelectionPath()
405 if ((selection == null) || (selection.length == 0))
412 * Returns the complete selection.
414 * @return the complete selection
416 public TreePath[] getSelectionPaths()
422 * Returns the number of paths in the selection.
424 * @return the number of paths in the selection
426 public int getSelectionCount()
428 if (selection == null)
431 return selection.length;
435 * Checks if a given path is in the selection.
437 * @param path the path to check
439 * @return <code>true</code> if the path is in the selection,
440 * <code>false</code> otherwise
442 public boolean isPathSelected(TreePath path)
444 if (selection == null)
447 for (int i = 0; i < selection.length; i++)
449 if (selection[i].equals(path))
456 * Checks if the selection is empty.
458 * @return <code>true</code> if the selection is empty, <code>false</code>
461 public boolean isSelectionEmpty()
463 return ((selection == null) || (selection.length == 0));
467 * Removes all paths from the selection.
469 public void clearSelection()
476 * Adds a <code>TreeSelectionListener</code> object to this model.
478 * @param listener the listener to add
480 public void addTreeSelectionListener(TreeSelectionListener listener)
482 listenerList.add(TreeSelectionListener.class, listener);
486 * Removes a <code>TreeSelectionListener</code> object from this model.
488 * @param listener the listener to remove
490 public void removeTreeSelectionListener(TreeSelectionListener listener)
492 listenerList.remove(TreeSelectionListener.class, listener);
496 * Returns all <code>TreeSelectionListener</code> added to this model.
498 * @return an array of listeners
502 public TreeSelectionListener[] getTreeSelectionListeners()
504 return (TreeSelectionListener[])
505 getListeners(TreeSelectionListener.class);
511 * @param event the event to fire.
513 protected void fireValueChanged(TreeSelectionEvent event)
515 TreeSelectionListener[] listeners = getTreeSelectionListeners();
517 for (int i = 0; i < listeners.length; ++i)
518 listeners[i].valueChanged(event);
522 * Returns all added listeners of a special type.
524 * @param listenerType the listener type
526 * @return an array of listeners
530 public EventListener[] getListeners(Class listenerType)
532 return listenerList.getListeners(listenerType);
536 * Returns the currently selected rows.
538 * @return the currently selected rows
540 public int[] getSelectionRows()
542 if (rowMapper == null)
545 return rowMapper.getRowsForPaths(selection);
549 * Returns the smallest row index from the selection.
551 * @return the smallest row index from the selection
553 public int getMinSelectionRow()
555 if ((rowMapper == null) || (selection == null)
556 || (selection.length == 0))
560 int[] rows = rowMapper.getRowsForPaths(selection);
561 int minRow = Integer.MAX_VALUE;
562 for (int index = 0; index < rows.length; index++)
563 minRow = Math.min(minRow, rows[index]);
569 * Returns the largest row index from the selection.
571 * @return the largest row index from the selection
573 public int getMaxSelectionRow()
575 if ((rowMapper == null) || (selection == null)
576 || (selection.length == 0))
580 int[] rows = rowMapper.getRowsForPaths(selection);
582 for (int index = 0; index < rows.length; index++)
583 maxRow = Math.max(maxRow, rows[index]);
589 * Checks if a particular row is selected.
591 * @param row the index of the row to check
593 * @return <code>true</code> if the row is in this selection,
594 * <code>false</code> otherwise
596 public boolean isRowSelected(int row)
598 return false; // TODO
602 * Updates the mappings from TreePaths to row indices.
604 public void resetRowSelection()
610 * getLeadSelectionRow
614 public int getLeadSelectionRow()
616 if ((rowMapper == null) || (leadPath == null))
619 return rowMapper.getRowsForPaths(new TreePath[] {
624 * getLeadSelectionPath
628 public TreePath getLeadSelectionPath()
634 * Adds a <code>PropertyChangeListener</code> object to this model.
636 * @param listener the listener to add.
638 public void addPropertyChangeListener(PropertyChangeListener listener)
640 changeSupport.addPropertyChangeListener(listener);
644 * Removes a <code>PropertyChangeListener</code> object from this model.
646 * @param listener the listener to remove.
648 public void removePropertyChangeListener(PropertyChangeListener listener)
650 changeSupport.removePropertyChangeListener(listener);
654 * Returns all added <code>PropertyChangeListener</code> objects.
656 * @return an array of listeners.
660 public PropertyChangeListener[] getPropertyChangeListeners()
662 return changeSupport.getPropertyChangeListeners();
666 * Makes sure the currently selected paths are valid according to the
667 * current selectionMode.
669 * If the selectionMode is set to {@link #CONTIGUOUS_TREE_SELECTION} and the
670 * selection isn't contiguous then the selection is reset to the first set
671 * of contguous paths.
673 * If the selectionMode is set to {@link #SINGLE_TREE_SELECTION} and the
674 * selection has more than one path, the selection is reset to the contain
675 * only the first path.
677 protected void insureRowContinuity()
683 * Returns <code>true</code> if the paths are contiguous or we have no
684 * RowMapper assigned.
686 * @param paths the paths to check for continuity
687 * @return <code>true</code> if the paths are contiguous or we have no
690 protected boolean arePathsContiguous(TreePath[] paths)
692 return false; // TODO
696 * Checks if the paths can be added. This returns <code>true</code> if:
698 * <li><code>paths</code> is <code>null</code> or empty</li>
699 * <li>we have no RowMapper assigned</li>
700 * <li>nothing is currently selected</li>
701 * <li>selectionMode is {@link #DISCONTIGUOUS_TREE_SELECTION}</li>
702 * <li>adding the paths to the selection still results in a contiguous set
705 * @param paths the paths to check
707 * @return <code>true</code> if the paths can be added with respect to the
710 protected boolean canPathsBeAdded(TreePath[] paths)
712 return false; // TODO
716 * Checks if the paths can be removed without breaking the continuity of the
717 * selection according to selectionMode.
719 * @param paths the paths to check
720 * @return <code>true</code> if the paths can be removed with respect to
723 protected boolean canPathsBeRemoved(TreePath[] paths)
725 return false; // TODO
734 protected void notifyPathChange(Vector value0, TreePath value1)
740 * Updates the lead index instance field.
742 protected void updateLeadIndex()
748 * Deprecated and not used.
750 protected void insureUniqueness()