Source for javax.swing.tree.DefaultTreeSelectionModel

   1: /* DefaultTreeSelectionModel.java 
   2:    Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
   3:    
   4: This file is part of GNU Classpath.
   5: 
   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)
   9: any later version.
  10: 
  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.
  15: 
  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
  19: 02110-1301 USA.
  20: 
  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
  24: combination.
  25: 
  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. */
  37: 
  38: package javax.swing.tree;
  39: 
  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;
  47: 
  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;
  53: 
  54: /**
  55:  * DefaultTreeSelectionModel
  56:  * 
  57:  * @author Andrew Selkirk
  58:  */
  59: public class DefaultTreeSelectionModel
  60:         implements Cloneable, Serializable, TreeSelectionModel
  61: {
  62:     static final long serialVersionUID = 3288129636638950196L;
  63: 
  64:     /**
  65:      * SELECTION_MODE_PROPERTY
  66:      */
  67:     public static final String SELECTION_MODE_PROPERTY = "selectionMode";
  68: 
  69:     /**
  70:      * Our Swing property change support.
  71:      */
  72:     protected SwingPropertyChangeSupport changeSupport;
  73: 
  74:     /**
  75:      * The current selection.
  76:      */
  77:     protected TreePath[] selection;
  78: 
  79:     /**
  80:      * Our TreeSelectionListeners.
  81:      */
  82:     protected EventListenerList listenerList;
  83: 
  84:     /**
  85:      * The current RowMapper.
  86:      */
  87:     protected transient RowMapper rowMapper;
  88: 
  89:     /**
  90:      * The current listSelectionModel.
  91:      */
  92:     protected DefaultListSelectionModel listSelectionModel;
  93: 
  94:     /**
  95:      * The current selection mode.
  96:      */
  97:     protected int selectionMode;
  98: 
  99:     /**
 100:      * The path that has been added last.
 101:      */
 102:     protected TreePath leadPath;
 103: 
 104:     /**
 105:      * The index of the last added path.
 106:      */
 107:     protected int leadIndex;
 108: 
 109:     /**
 110:      * The row of the last added path according to the RowMapper.
 111:      */
 112:     protected int leadRow;
 113: 
 114:     /**
 115:      * Constructs a new DefaultTreeSelectionModel.
 116:      */
 117:     public DefaultTreeSelectionModel()
 118:     {
 119:         setSelectionMode(DISCONTIGUOUS_TREE_SELECTION);
 120:         listenerList = new EventListenerList();
 121:     }
 122: 
 123:     /**
 124:      * Creates a clone of this DefaultTreeSelectionModel with the same
 125:      * selection.
 126:      * 
 127:      * @exception CloneNotSupportedException should not be thrown here
 128:      * 
 129:      * @return a clone of this DefaultTreeSelectionModel
 130:      */
 131:     public Object clone() throws CloneNotSupportedException
 132:     {
 133:         return null; // TODO
 134:     }
 135: 
 136:     /**
 137:      * Returns a string that shows this object's properties.
 138:      * 
 139:      * @return a string that shows this object's properties
 140:      */
 141:     public String toString()
 142:     {
 143:         return null; // TODO
 144:     }
 145: 
 146:     /**
 147:      * writeObject
 148:      * 
 149:      * @param value0 TODO
 150:      * @exception IOException TODO
 151:      */
 152:     private void writeObject(ObjectOutputStream value0) throws IOException
 153:     {
 154:         // TODO
 155:     }
 156: 
 157:     /**
 158:      * readObject
 159:      * 
 160:      * @param value0 TODO
 161:      * @exception IOException TODO
 162:      * @exception ClassNotFoundException TODO
 163:      */
 164:     private void readObject(ObjectInputStream value0) throws IOException,
 165:             ClassNotFoundException
 166:     {
 167:         // TODO
 168:     }
 169: 
 170:     /**
 171:      * Sets the RowMapper that should be used to map between paths and their
 172:      * rows.
 173:      * 
 174:      * @param rowMapper the RowMapper to set
 175:      * 
 176:      * @see RowMapper
 177:      */
 178:     public void setRowMapper(RowMapper rowMapper)
 179:     {
 180:         // TODO
 181:     }
 182: 
 183:     /**
 184:      * Returns the RowMapper that is currently used to map between paths and
 185:      * their rows.
 186:      * 
 187:      * @return the current RowMapper
 188:      * 
 189:      * @see RowMapper
 190:      */
 191:     public RowMapper getRowMapper()
 192:     {
 193:         return rowMapper;
 194:     }
 195: 
 196:     /**
 197:      * Sets the current selection mode. Possible values are
 198:      * {@link #SINGLE_TREE_SELECTION}, {@link #CONTIGUOUS_TREE_SELECTION} and
 199:      * {@link #DISCONTIGUOUS_TREE_SELECTION}.
 200:      * 
 201:      * @param mode the selection mode to be set
 202:      * 
 203:      * @see #getSelectionMode
 204:      * @see #SINGLE_TREE_SELECTION
 205:      * @see #CONTIGUOUS_TREE_SELECTION
 206:      * @see #DISCONTIGUOUS_TREE_SELECTION
 207:      */
 208:     public void setSelectionMode(int mode)
 209:     {
 210:         selectionMode = mode;
 211:     }
 212: 
 213:     /**
 214:      * Returns the current selection mode.
 215:      * 
 216:      * @return the current selection mode
 217:      * 
 218:      * @see #setSelectionMode
 219:      * @see #SINGLE_TREE_SELECTION
 220:      * @see #CONTIGUOUS_TREE_SELECTION
 221:      * @see #DISCONTIGUOUS_TREE_SELECTION
 222:      */
 223:     public int getSelectionMode()
 224:     {
 225:         return selectionMode;
 226:     }
 227: 
 228:     /**
 229:      * Sets this path as the only selection.
 230:      * 
 231:      * If this changes the selection the registered TreeSelectionListeners are
 232:      * notified.
 233:      * 
 234:      * @param path the path to set as selection
 235:      */
 236:     public void setSelectionPath(TreePath path)
 237:     {
 238:         selection = new TreePath[] {
 239:             path };
 240:     }
 241: 
 242:     /**
 243:      * Sets the paths as selection. This method checks for duplicates and
 244:      * removes them.
 245:      * 
 246:      * If this changes the selection the registered TreeSelectionListeners are
 247:      * notified.
 248:      * 
 249:      * @param paths the paths to set as selection
 250:      */
 251:     public void setSelectionPaths(TreePath[] paths)
 252:     {
 253:         // TODO
 254:     }
 255: 
 256:     /**
 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.
 259:      * 
 260:      * If this changes the selection the registered TreeSelectionListeners are
 261:      * notified.
 262:      * 
 263:      * @param path the path to add to the selection
 264:      */
 265:     public void addSelectionPath(TreePath path)
 266:     {
 267:         if (!isPathSelected(path))
 268:         {
 269:             if (isSelectionEmpty())
 270:                 setSelectionPath(path);
 271:             else
 272:             {
 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);
 278:             }
 279:             leadPath = path;
 280:             fireValueChanged(new TreeSelectionEvent(this, path, true,
 281:                     leadPath, path));
 282:         }
 283:     }
 284: 
 285:     /**
 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.
 288:      * 
 289:      * If this changes the selection the registered TreeSelectionListeners are
 290:      * notified.
 291:      * 
 292:      * @param paths the paths to add to the selection
 293:      */
 294:     public void addSelectionPaths(TreePath[] paths)
 295:     {
 296:         if (paths != null)
 297:         {
 298:             TreePath v0 = null;
 299:             for (int i = 0; i < paths.length; i++)
 300:             {
 301:                 v0 = paths[i];
 302:                 if (!isPathSelected(v0))
 303:                 {
 304:                     if (isSelectionEmpty())
 305:                         setSelectionPath(v0);
 306:                     else
 307:                     {
 308:                         TreePath[] temp = new TreePath[selection.length + 1];
 309:                         System.arraycopy(selection, 0, temp, 0,
 310:                                 selection.length);
 311:                         temp[temp.length - 1] = v0;
 312:                         selection = new TreePath[temp.length];
 313:                         System.arraycopy(temp, 0, selection, 0, temp.length);
 314:                     }
 315:                     leadPath = paths[paths.length - 1];
 316:                     fireValueChanged(new TreeSelectionEvent(this, v0, true,
 317:                             leadPath, paths[0]));
 318:                 }
 319:             }
 320:         }
 321:     }
 322: 
 323:     /**
 324:      * Removes the path from the selection.
 325:      * 
 326:      * If this changes the selection the registered TreeSelectionListeners are
 327:      * notified.
 328:      * 
 329:      * @param path the path to remove
 330:      */
 331:     public void removeSelectionPath(TreePath path)
 332:     {
 333:         int index = -1;
 334:         if (isPathSelected(path))
 335:         {
 336:             for (int i = 0; i < selection.length; i++)
 337:             {
 338:                 if (selection[i].equals(path))
 339:                 {
 340:                     index = i;
 341:                     break;
 342:                 }
 343:             }
 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);
 350: 
 351:             fireValueChanged(new TreeSelectionEvent(this, path, false,
 352:                     leadPath, path));
 353:         }
 354:     }
 355: 
 356:     /**
 357:      * Removes the paths from the selection.
 358:      * 
 359:      * If this changes the selection the registered TreeSelectionListeners are
 360:      * notified.
 361:      * 
 362:      * @param paths the paths to remove
 363:      */
 364:     public void removeSelectionPaths(TreePath[] paths)
 365:     {
 366:         if (paths != null)
 367:         {
 368:             int index = -1;
 369:             TreePath v0 = null;
 370:             for (int i = 0; i < paths.length; i++)
 371:             {
 372:                 v0 = paths[i];
 373:                 if (isPathSelected(v0))
 374:                 {
 375:                     for (int x = 0; x < selection.length; x++)
 376:                     {
 377:                         if (selection[i].equals(v0))
 378:                         {
 379:                             index = x;
 380:                             break;
 381:                         }
 382:                     }
 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);
 389: 
 390:                     fireValueChanged(new TreeSelectionEvent(this, v0, false,
 391:                             leadPath, paths[0]));
 392:                 }
 393:             }
 394:         }
 395:     }
 396: 
 397:     /**
 398:      * Returns the first path in the selection. This is especially useful when
 399:      * the selectionMode is {@link #SINGLE_TREE_SELECTION}.
 400:      * 
 401:      * @return the first path in the selection
 402:      */
 403:     public TreePath getSelectionPath()
 404:     {
 405:         if ((selection == null) || (selection.length == 0))
 406:             return null;
 407:         else
 408:             return selection[0];
 409:     }
 410: 
 411:     /**
 412:      * Returns the complete selection.
 413:      * 
 414:      * @return the complete selection
 415:      */
 416:     public TreePath[] getSelectionPaths()
 417:     {
 418:         return selection;
 419:     }
 420: 
 421:     /**
 422:      * Returns the number of paths in the selection.
 423:      * 
 424:      * @return the number of paths in the selection
 425:      */
 426:     public int getSelectionCount()
 427:     {
 428:         if (selection == null)
 429:             return 0;
 430:         else
 431:             return selection.length;
 432:     }
 433: 
 434:     /**
 435:      * Checks if a given path is in the selection.
 436:      * 
 437:      * @param path the path to check
 438:      * 
 439:      * @return <code>true</code> if the path is in the selection,
 440:      *         <code>false</code> otherwise
 441:      */
 442:     public boolean isPathSelected(TreePath path)
 443:     {
 444:         if (selection == null)
 445:             return false;
 446: 
 447:         for (int i = 0; i < selection.length; i++)
 448:         {
 449:             if (selection[i].equals(path))
 450:                 return true;
 451:         }
 452:         return false;
 453:     }
 454: 
 455:     /**
 456:      * Checks if the selection is empty.
 457:      * 
 458:      * @return <code>true</code> if the selection is empty, <code>false</code>
 459:      *         otherwise
 460:      */
 461:     public boolean isSelectionEmpty()
 462:     {
 463:         return ((selection == null) || (selection.length == 0));
 464:     }
 465: 
 466:     /**
 467:      * Removes all paths from the selection.
 468:      */
 469:     public void clearSelection()
 470:     {
 471:         leadPath = null;
 472:         selection = null;
 473:     }
 474: 
 475:     /**
 476:      * Adds a <code>TreeSelectionListener</code> object to this model.
 477:      * 
 478:      * @param listener the listener to add
 479:      */
 480:     public void addTreeSelectionListener(TreeSelectionListener listener)
 481:     {
 482:         listenerList.add(TreeSelectionListener.class, listener);
 483:     }
 484: 
 485:     /**
 486:      * Removes a <code>TreeSelectionListener</code> object from this model.
 487:      * 
 488:      * @param listener the listener to remove
 489:      */
 490:     public void removeTreeSelectionListener(TreeSelectionListener listener)
 491:     {
 492:         listenerList.remove(TreeSelectionListener.class, listener);
 493:     }
 494: 
 495:     /**
 496:      * Returns all <code>TreeSelectionListener</code> added to this model.
 497:      * 
 498:      * @return an array of listeners
 499:      * 
 500:      * @since 1.4
 501:      */
 502:     public TreeSelectionListener[] getTreeSelectionListeners()
 503:     {
 504:         return (TreeSelectionListener[]) 
 505:                 getListeners(TreeSelectionListener.class);
 506:     }
 507: 
 508:     /**
 509:      * fireValueChanged
 510:      * 
 511:      * @param event the event to fire.
 512:      */
 513:     protected void fireValueChanged(TreeSelectionEvent event)
 514:     {
 515:         TreeSelectionListener[] listeners = getTreeSelectionListeners();
 516: 
 517:         for (int i = 0; i < listeners.length; ++i)
 518:             listeners[i].valueChanged(event);
 519:     }
 520: 
 521:     /**
 522:      * Returns all added listeners of a special type.
 523:      * 
 524:      * @param listenerType the listener type
 525:      * 
 526:      * @return an array of listeners
 527:      * 
 528:      * @since 1.3
 529:      */
 530:     public EventListener[] getListeners(Class listenerType)
 531:     {
 532:         return listenerList.getListeners(listenerType);
 533:     }
 534: 
 535:     /**
 536:      * Returns the currently selected rows.
 537:      * 
 538:      * @return the currently selected rows
 539:      */
 540:     public int[] getSelectionRows()
 541:     {
 542:         if (rowMapper == null)
 543:             return null;
 544:         else
 545:             return rowMapper.getRowsForPaths(selection);
 546:     }
 547: 
 548:     /**
 549:      * Returns the smallest row index from the selection.
 550:      * 
 551:      * @return the smallest row index from the selection
 552:      */
 553:     public int getMinSelectionRow()
 554:     {
 555:         if ((rowMapper == null) || (selection == null)
 556:                 || (selection.length == 0))
 557:             return -1;
 558:         else
 559:         {
 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]);
 564:             return minRow;
 565:         }
 566:     }
 567: 
 568:     /**
 569:      * Returns the largest row index from the selection.
 570:      * 
 571:      * @return the largest row index from the selection
 572:      */
 573:     public int getMaxSelectionRow()
 574:     {
 575:         if ((rowMapper == null) || (selection == null)
 576:                 || (selection.length == 0))
 577:             return -1;
 578:         else
 579:         {
 580:             int[] rows = rowMapper.getRowsForPaths(selection);
 581:             int maxRow = -1;
 582:             for (int index = 0; index < rows.length; index++)
 583:                 maxRow = Math.max(maxRow, rows[index]);
 584:             return maxRow;
 585:         }
 586:     }
 587: 
 588:     /**
 589:      * Checks if a particular row is selected.
 590:      * 
 591:      * @param row the index of the row to check
 592:      * 
 593:      * @return <code>true</code> if the row is in this selection,
 594:      *         <code>false</code> otherwise
 595:      */
 596:     public boolean isRowSelected(int row)
 597:     {
 598:         return false; // TODO
 599:     }
 600: 
 601:     /**
 602:      * Updates the mappings from TreePaths to row indices.
 603:      */
 604:     public void resetRowSelection()
 605:     {
 606:         // TODO
 607:     }
 608: 
 609:     /**
 610:      * getLeadSelectionRow
 611:      * 
 612:      * @return int
 613:      */
 614:     public int getLeadSelectionRow()
 615:     {
 616:         if ((rowMapper == null) || (leadPath == null))
 617:             return -1;
 618:         else
 619:             return rowMapper.getRowsForPaths(new TreePath[] {
 620:                 leadPath })[0];
 621:     }
 622: 
 623:     /**
 624:      * getLeadSelectionPath
 625:      * 
 626:      * @return TreePath
 627:      */
 628:     public TreePath getLeadSelectionPath()
 629:     {
 630:         return leadPath;
 631:     }
 632: 
 633:     /**
 634:      * Adds a <code>PropertyChangeListener</code> object to this model.
 635:      * 
 636:      * @param listener the listener to add.
 637:      */
 638:     public void addPropertyChangeListener(PropertyChangeListener listener)
 639:     {
 640:         changeSupport.addPropertyChangeListener(listener);
 641:     }
 642: 
 643:     /**
 644:      * Removes a <code>PropertyChangeListener</code> object from this model.
 645:      * 
 646:      * @param listener the listener to remove.
 647:      */
 648:     public void removePropertyChangeListener(PropertyChangeListener listener)
 649:     {
 650:         changeSupport.removePropertyChangeListener(listener);
 651:     }
 652: 
 653:     /**
 654:      * Returns all added <code>PropertyChangeListener</code> objects.
 655:      * 
 656:      * @return an array of listeners.
 657:      * 
 658:      * @since 1.4
 659:      */
 660:     public PropertyChangeListener[] getPropertyChangeListeners()
 661:     {
 662:         return changeSupport.getPropertyChangeListeners();
 663:     }
 664: 
 665:     /**
 666:      * Makes sure the currently selected paths are valid according to the
 667:      * current selectionMode.
 668:      * 
 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.
 672:      * 
 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.
 676:      */
 677:     protected void insureRowContinuity()
 678:     {
 679:         // TODO
 680:     }
 681: 
 682:     /**
 683:      * Returns <code>true</code> if the paths are contiguous or we have no
 684:      * RowMapper assigned.
 685:      * 
 686:      * @param paths the paths to check for continuity
 687:      * @return <code>true</code> if the paths are contiguous or we have no
 688:      *         RowMapper assigned
 689:      */
 690:     protected boolean arePathsContiguous(TreePath[] paths)
 691:     {
 692:         return false; // TODO
 693:     }
 694: 
 695:     /**
 696:      * Checks if the paths can be added. This returns <code>true</code> if:
 697:      * <ul>
 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
 703:      * of paths</li>
 704:      * 
 705:      * @param paths the paths to check
 706:      * 
 707:      * @return <code>true</code> if the paths can be added with respect to the
 708:      *         selectionMode
 709:      */
 710:     protected boolean canPathsBeAdded(TreePath[] paths)
 711:     {
 712:         return false; // TODO
 713:     }
 714: 
 715:     /**
 716:      * Checks if the paths can be removed without breaking the continuity of the
 717:      * selection according to selectionMode.
 718:      * 
 719:      * @param paths the paths to check
 720:      * @return <code>true</code> if the paths can be removed with respect to
 721:      *         the selectionMode
 722:      */
 723:     protected boolean canPathsBeRemoved(TreePath[] paths)
 724:     {
 725:         return false; // TODO
 726:     }
 727: 
 728:     /**
 729:      * notifyPathChange
 730:      * 
 731:      * @param value0 TODO
 732:      * @param value1 TODO
 733:      */
 734:     protected void notifyPathChange(Vector value0, TreePath value1)
 735:     {
 736:         // TODO
 737:     }
 738: 
 739:     /**
 740:      * Updates the lead index instance field.
 741:      */
 742:     protected void updateLeadIndex()
 743:     {
 744:         // TODO
 745:     }
 746: 
 747:     /**
 748:      * Deprecated and not used.
 749:      */
 750:     protected void insureUniqueness()
 751:     {
 752:         // TODO
 753:     }
 754: }