Source for javax.swing.JList

   1: /* JList.java --
   2:    Copyright (C) 2002, 2003, 2004, 2005, 2006,  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: 
  39: package javax.swing;
  40: 
  41: import gnu.java.lang.CPStringBuilder;
  42: 
  43: import java.awt.Color;
  44: import java.awt.Component;
  45: import java.awt.ComponentOrientation;
  46: import java.awt.Cursor;
  47: import java.awt.Dimension;
  48: import java.awt.Font;
  49: import java.awt.FontMetrics;
  50: import java.awt.Point;
  51: import java.awt.Rectangle;
  52: import java.awt.event.FocusListener;
  53: import java.beans.PropertyChangeEvent;
  54: import java.beans.PropertyChangeListener;
  55: import java.util.Locale;
  56: import java.util.Vector;
  57: 
  58: import javax.accessibility.Accessible;
  59: import javax.accessibility.AccessibleComponent;
  60: import javax.accessibility.AccessibleContext;
  61: import javax.accessibility.AccessibleRole;
  62: import javax.accessibility.AccessibleSelection;
  63: import javax.accessibility.AccessibleState;
  64: import javax.accessibility.AccessibleStateSet;
  65: import javax.swing.event.ListDataEvent;
  66: import javax.swing.event.ListDataListener;
  67: import javax.swing.event.ListSelectionEvent;
  68: import javax.swing.event.ListSelectionListener;
  69: import javax.swing.plaf.ListUI;
  70: import javax.swing.text.Position;
  71: 
  72: /**
  73:  * <p>This class is a facade over three separate objects: {@link
  74:  * javax.swing.ListModel}, {@link javax.swing.ListSelectionModel} and
  75:  * {@link javax.swing.plaf.ListUI}. The facade represents a unified "list"
  76:  * concept, with independently replacable (possibly client-provided) models
  77:  * for its contents and its current selection. In addition, each element in
  78:  * the list is rendered via a strategy class {@link
  79:  * javax.swing.ListCellRenderer}.</p>
  80:  *
  81:  * <p>Lists have many properties, some of which are stored in this class
  82:  * while others are delegated to the list's model or selection. The
  83:  * following properties are available:</p>
  84:  *
  85:  * <table>
  86:  * <tr><th>Property                       </th><th>Stored in</th><th>Bound?</th></tr>
  87:  * <tr><td>accessibleContext              </td><td>list     </td><td>no    </td></tr>
  88:  * <tr><td>anchorSelectionIndex           </td><td>selection</td><td>no    </td></tr>
  89:  * <tr><td>cellRenderer                   </td><td>list     </td><td>yes   </td></tr>
  90:  * <tr><td>dragEnabled                    </td><td>list     </td><td>no    </td></tr>
  91:  * <tr><td>firstVisibleIndex              </td><td>list     </td><td>no    </td></tr>
  92:  * <tr><td>fixedCellHeight                </td><td>list     </td><td>yes   </td></tr>
  93:  * <tr><td>fixedCellWidth                 </td><td>list     </td><td>yes   </td></tr>
  94:  * <tr><td>lastVisibleIndex               </td><td>list     </td><td>no    </td></tr>
  95:  * <tr><td>layoutOrientation              </td><td>list     </td><td>yes   </td></tr>
  96:  * <tr><td>leadSelectionIndex             </td><td>selection</td><td>no    </td></tr>
  97:  * <tr><td>maxSelectionIndex              </td><td>selection</td><td>no    </td></tr>
  98:  * <tr><td>minSelectionIndex              </td><td>selection</td><td>no    </td></tr>
  99:  * <tr><td>model                          </td><td>list     </td><td>yes   </td></tr>
 100:  * <tr><td>opaque                         </td><td>list     </td><td>no    </td></tr>
 101:  * <tr><td>preferredScrollableViewportSize</td><td>list     </td><td>no    </td></tr>
 102:  * <tr><td>prototypeCellValue             </td><td>list     </td><td>yes   </td></tr>
 103:  * <tr><td>scrollableTracksViewportHeight </td><td>list     </td><td>no    </td></tr>
 104:  * <tr><td>scrollableTracksViewportWidth  </td><td>list     </td><td>no    </td></tr>
 105:  * <tr><td>selectedIndex                  </td><td>selection</td><td>no    </td></tr>
 106:  * <tr><td>selectedIndices                </td><td>selection</td><td>no    </td></tr>
 107:  * <tr><td>selectedValue                  </td><td>model    </td><td>no    </td></tr>
 108:  * <tr><td>selectedValues                 </td><td>model    </td><td>no    </td></tr>
 109:  * <tr><td>selectionBackground            </td><td>list     </td><td>yes   </td></tr>
 110:  * <tr><td>selectionEmpty                 </td><td>selection</td><td>no    </td></tr>
 111:  * <tr><td>selectionForeground            </td><td>list     </td><td>yes   </td></tr>
 112:  * <tr><td>selectionMode                  </td><td>selection</td><td>no    </td></tr>
 113:  * <tr><td>selectionModel                 </td><td>list     </td><td>yes   </td></tr>
 114:  * <tr><td>UI                             </td><td>list     </td><td>yes   </td></tr>
 115:  * <tr><td>UIClassID                      </td><td>list     </td><td>no    </td></tr>
 116:  * <tr><td>valueIsAdjusting               </td><td>list     </td><td>no    </td></tr>
 117:  * <tr><td>visibleRowCount                </td><td>list     </td><td>no    </td></tr>
 118:  * </table>
 119:  *
 120:  * @author Graydon Hoare (graydon@redhat.com)
 121:  */
 122: 
 123: public class JList extends JComponent implements Accessible, Scrollable
 124: {
 125: 
 126:   /**
 127:    * Provides accessibility support for <code>JList</code>.
 128:    */
 129:   protected class AccessibleJList extends AccessibleJComponent
 130:     implements AccessibleSelection, PropertyChangeListener,
 131:                ListSelectionListener, ListDataListener
 132:   {
 133: 
 134:     /**
 135:      * Provides accessibility support for list elements in <code>JList</code>s.
 136:      */
 137:     protected class AccessibleJListChild extends AccessibleContext
 138:       implements Accessible, AccessibleComponent
 139:     {
 140: 
 141:       /**
 142:        * The parent list.
 143:        */
 144:       JList parent;
 145: 
 146:       /**
 147:        * The index in the list for that child.
 148:        */
 149:       int listIndex;
 150: 
 151:       /**
 152:        * The cursor for this list child.
 153:        */
 154:       // TODO: Testcases show that this class somehow stores state about the
 155:       // cursor. I cannot make up though how that could affect
 156:       // the actual list.
 157:       Cursor cursor = Cursor.getDefaultCursor();
 158: 
 159:       /**
 160:        * Creates a new instance of <code>AccessibleJListChild</code>.
 161:        *
 162:        * @param list the list of which this is an accessible child
 163:        * @param index the list index for this child
 164:        */
 165:       public AccessibleJListChild(JList list, int index)
 166:       {
 167:         parent = list;
 168:         listIndex = index;
 169:       }
 170: 
 171:       /**
 172:        * Returns the accessible context of this object. Returns
 173:        * <code>this</code> since <code>AccessibleJListChild</code>s are their
 174:        * own accessible contexts.
 175:        *
 176:        * @return the accessible context of this object, <code>this</code>
 177:        */
 178:       public AccessibleContext getAccessibleContext()
 179:       {
 180:         return this;
 181:       }
 182: 
 183:       /**
 184:        * Returns the background color for this list child. This returns the
 185:        * background of the <code>JList</code> itself since the background
 186:        * cannot be set on list children individually
 187:        *
 188:        * @return the background color for this list child
 189:        */
 190:       public Color getBackground()
 191:       {
 192:         return parent.getBackground();
 193:       }
 194: 
 195:       /**
 196:        * Calling this method has no effect, since the background color cannot be
 197:        * set on list children individually.
 198:        *
 199:        * @param color not used here.
 200:        */
 201:       public void setBackground(Color color)
 202:       {
 203:         // Calling this method has no effect, since the background color cannot
 204:         // be set on list children individually.
 205:       }
 206: 
 207:       /**
 208:        * Returns the foreground color for this list child. This returns the
 209:        * background of the <code>JList</code> itself since the foreground
 210:        * cannot be set on list children individually.
 211:        *
 212:        * @return the background color for this list child
 213:        */
 214:       public Color getForeground()
 215:       {
 216:         return parent.getForeground();
 217:       }
 218: 
 219:       /**
 220:        * Calling this method has no effect, since the foreground color cannot be
 221:        * set on list children individually.
 222:        *
 223:        * @param color not used here.
 224:        */
 225:       public void setForeground(Color color)
 226:       {
 227:         // Calling this method has no effect, since the foreground color cannot
 228:         // be set on list children individually.
 229:       }
 230: 
 231:       /**
 232:        * Returns the cursor for this list child.
 233:        *
 234:        * @return the cursor for this list child
 235:        */
 236:       public Cursor getCursor()
 237:       {
 238:         // TODO: Testcases show that this method returns the cursor that has
 239:         // been set by setCursor. I cannot make up though how that could affect
 240:         // the actual list.
 241:         return cursor;
 242:       }
 243: 
 244:       /**
 245:        * Sets the cursor for this list child.
 246:        */
 247:       public void setCursor(Cursor cursor)
 248:       {
 249:         this.cursor = cursor;
 250:         // TODO: Testcases show that this method returns the cursor that has
 251:         // been set by setCursor. I cannot make up though how that could affect
 252:         // the actual list.
 253:       }
 254: 
 255:       /**
 256:        * Returns the font of the <code>JList</code> since it is not possible to
 257:        * set fonts for list children individually.
 258:        *
 259:        * @return the font of the <code>JList</code>
 260:        */
 261:       public Font getFont()
 262:       {
 263:         return parent.getFont();
 264:       }
 265: 
 266:       /**
 267:        * Does nothing since it is not possible to set the font on list children
 268:        * individually.
 269:        *
 270:        * @param font not used here
 271:        */
 272:       public void setFont(Font font)
 273:       {
 274:         // Does nothing since it is not possible to set the font on list
 275:         // children individually.
 276:       }
 277: 
 278:       /**
 279:        * Returns the font metrics for the specified font. This method forwards
 280:        * to the parent <code>JList</code>.
 281:        *
 282:        * @param font the font for which the font metrics is queried
 283:        *
 284:        * @return the font metrics for the specified font
 285:        */
 286:       public FontMetrics getFontMetrics(Font font)
 287:       {
 288:         return parent.getFontMetrics(font);
 289:       }
 290: 
 291:       /**
 292:        * Returns <code>true</code> if the parent <code>JList</code> is enabled,
 293:        * <code>false</code> otherwise. The list children cannot have an enabled
 294:        * flag set individually.
 295:        *
 296:        * @return <code>true</code> if the parent <code>JList</code> is enabled,
 297:        *         <code>false</code> otherwise
 298:        */
 299:       public boolean isEnabled()
 300:       {
 301:         return parent.isEnabled();
 302:       }
 303: 
 304:       /**
 305:        * Does nothing since the enabled flag cannot be set for list children
 306:        * individually.
 307:        *
 308:        * @param b not used here
 309:        */
 310:       public void setEnabled(boolean b)
 311:       {
 312:         // Does nothing since the enabled flag cannot be set for list children
 313:         // individually.
 314:       }
 315: 
 316:       /**
 317:        * Returns <code>true</code> if this list child is visible,
 318:        * <code>false</code> otherwise. The value of this property depends
 319:        * on {@link JList#getFirstVisibleIndex()} and
 320:        * {@link JList#getLastVisibleIndex()}.
 321:        *
 322:        * @return <code>true</code> if this list child is visible,
 323:        *         <code>false</code> otherwise
 324:        */
 325:       public boolean isVisible()
 326:       {
 327:         return listIndex >= parent.getFirstVisibleIndex()
 328:                && listIndex <= parent.getLastVisibleIndex();
 329:       }
 330: 
 331:       /**
 332:        * The value of the visible property cannot be modified, so this method
 333:        * does nothing.
 334:        *
 335:        * @param b not used here
 336:        */
 337:       public void setVisible(boolean b)
 338:       {
 339:         // The value of the visible property cannot be modified, so this method
 340:         // does nothing.
 341:       }
 342: 
 343:       /**
 344:        * Returns <code>true</code> if this list child is currently showing on
 345:        * screen and <code>false</code> otherwise. The list child is showing if
 346:        * it is visible and if it's parent JList is currently showing.
 347:        *
 348:        * @return <code>true</code> if this list child is currently showing on
 349:        *         screen and <code>false</code> otherwise
 350:        */
 351:       public boolean isShowing()
 352:       {
 353:         return isVisible() && parent.isShowing();
 354:       }
 355: 
 356:       /**
 357:        * Returns <code>true</code> if this list child covers the screen location
 358:        * <code>point</code> (relative to the <code>JList</code> coordinate
 359:        * system, <code>false</code> otherwise.
 360:        *
 361:        * @return <code>true</code> if this list child covers the screen location
 362:        *         <code>point</code> , <code>false</code> otherwise
 363:        */
 364:       public boolean contains(Point point)
 365:       {
 366:         return getBounds().contains(point);
 367:       }
 368: 
 369:       /**
 370:        * Returns the absolute screen location of this list child.
 371:        *
 372:        * @return the absolute screen location of this list child
 373:        */
 374:       public Point getLocationOnScreen()
 375:       {
 376:         Point loc = getLocation();
 377:         SwingUtilities.convertPointToScreen(loc, parent);
 378:         return loc;
 379:       }
 380: 
 381:       /**
 382:        * Returns the screen location of this list child relative to it's parent.
 383:        *
 384:        * @return the location of this list child relative to it's parent
 385:        *
 386:        * @see JList#indexToLocation(int)
 387:        */
 388:       public Point getLocation()
 389:       {
 390:         return parent.indexToLocation(listIndex);
 391:       }
 392: 
 393:       /**
 394:        * Does nothing since the screen location cannot be set on list children
 395:        * explictitly.
 396:        *
 397:        * @param point not used here
 398:        */
 399:       public void setLocation(Point point)
 400:       {
 401:         // Does nothing since the screen location cannot be set on list children
 402:         // explictitly.
 403:       }
 404: 
 405:       /**
 406:        * Returns the bounds of this list child.
 407:        *
 408:        * @return the bounds of this list child
 409:        *
 410:        * @see JList#getCellBounds(int, int)
 411:        */
 412:       public Rectangle getBounds()
 413:       {
 414:         return parent.getCellBounds(listIndex, listIndex);
 415:       }
 416: 
 417:       /**
 418:        * Does nothing since the bounds cannot be set on list children
 419:        * individually.
 420:        *
 421:        * @param rectangle not used here
 422:        */
 423:       public void setBounds(Rectangle rectangle)
 424:       {
 425:         // Does nothing since the bounds cannot be set on list children
 426:         // individually.
 427:       }
 428: 
 429:       /**
 430:        * Returns the size of this list child.
 431:        *
 432:        * @return the size of this list child
 433:        */
 434:       public Dimension getSize()
 435:       {
 436:         Rectangle b = getBounds();
 437:         return b.getSize();
 438:       }
 439: 
 440:       /**
 441:        * Does nothing since the size cannot be set on list children
 442:        * individually.
 443:        *
 444:        * @param dimension not used here
 445:        */
 446:       public void setSize(Dimension dimension)
 447:       {
 448:         // Does nothing since the size cannot be set on list children
 449:         // individually.
 450:       }
 451: 
 452:       /**
 453:        * Returns <code>null</code> because list children do not have children
 454:        * themselves
 455:        *
 456:        * @return <code>null</code>
 457:        */
 458:       public Accessible getAccessibleAt(Point point)
 459:       {
 460:         return null;
 461:       }
 462: 
 463:       /**
 464:        * Returns <code>true</code> since list children are focus traversable.
 465:        *
 466:        * @return true
 467:        */
 468:       public boolean isFocusTraversable()
 469:       {
 470:         // TODO: Is this 100% ok?
 471:         return true;
 472:       }
 473: 
 474:       /**
 475:        * Requests focus on the parent list. List children cannot request focus
 476:        * individually.
 477:        */
 478:       public void requestFocus()
 479:       {
 480:         // TODO: Is this 100% ok?
 481:         parent.requestFocus();
 482:       }
 483: 
 484:       /**
 485:        * Adds a focus listener to the parent list. List children do not have
 486:        * their own focus management.
 487:        *
 488:        * @param listener the focus listener to add
 489:        */
 490:       public void addFocusListener(FocusListener listener)
 491:       {
 492:         // TODO: Is this 100% ok?
 493:         parent.addFocusListener(listener);
 494:       }
 495: 
 496:       /**
 497:        * Removes a focus listener from the parent list. List children do not
 498:        * have their own focus management.
 499:        *
 500:        * @param listener the focus listener to remove
 501:        */
 502:       public void removeFocusListener(FocusListener listener)
 503:       {
 504:         // TODO: Is this 100%
 505:         parent.removeFocusListener(listener);
 506:       }
 507: 
 508:       /**
 509:        * Returns the accessible role of this list item, which is
 510:        * {@link AccessibleRole#LABEL}.
 511:        *
 512:        * @return {@link AccessibleRole#LABEL}
 513:        */
 514:       public AccessibleRole getAccessibleRole()
 515:       {
 516:         return AccessibleRole.LABEL;
 517:       }
 518: 
 519:       /**
 520:        * Returns the accessible state set of this list item.
 521:        *
 522:        * @return the accessible state set of this list item
 523:        */
 524:       public AccessibleStateSet getAccessibleStateSet()
 525:       {
 526:         AccessibleStateSet states = new AccessibleStateSet();
 527:         if (isVisible())
 528:           states.add(AccessibleState.VISIBLE);
 529:         if (isShowing())
 530:           states.add(AccessibleState.SHOWING);
 531:         if (isFocusTraversable())
 532:           states.add(AccessibleState.FOCUSABLE);
 533:         // TODO: How should the active state be handled? The API docs
 534:         // suggest that this state is set on the activated list child,
 535:         // that is the one that is drawn with a box. However, I don't know how
 536:         // to implement this.
 537: 
 538:         // TODO: We set the selectable state here because list children are
 539:         // selectable. Is there a way to disable single children?
 540:         if (parent.isEnabled())
 541:           states.add(AccessibleState.SELECTABLE);
 542: 
 543:         if (parent.isSelectedIndex(listIndex))
 544:           states.add(AccessibleState.SELECTED);
 545: 
 546:         // TODO: Handle more states here?
 547:         return states;
 548:       }
 549: 
 550:       /**
 551:        * Returns the index of this list child within it's parent list.
 552:        *
 553:        * @return the index of this list child within it's parent list
 554:        */
 555:       public int getAccessibleIndexInParent()
 556:       {
 557:         return listIndex;
 558:       }
 559: 
 560:       /**
 561:        * Returns <code>0</code> since list children don't have children
 562:        * themselves.
 563:        *
 564:        * @return <code>0</code>
 565:        */
 566:       public int getAccessibleChildrenCount()
 567:       {
 568:         return 0;
 569:       }
 570: 
 571:       /**
 572:        * Returns <code>null</code> since list children don't have children
 573:        * themselves.
 574:        *
 575:        * @return <code>null</code>
 576:        */
 577:       public Accessible getAccessibleChild(int i)
 578:       {
 579:         return null;
 580:       }
 581: 
 582:       /**
 583:        * Returns the locale of this component. This call is forwarded to the
 584:        * parent list since list children don't have a separate locale setting.
 585:        *
 586:        * @return the locale of this component
 587:        */
 588:       public Locale getLocale()
 589:       {
 590:         return parent.getLocale();
 591:       }
 592: 
 593:       /**
 594:        * This method does
 595:        * nothing, list children are transient accessible objects which means
 596:        * that they don't fire property change events.
 597:        *
 598:        * @param l not used here
 599:        */
 600:       public void addPropertyChangeListener(PropertyChangeListener l)
 601:       {
 602:         // Do nothing here.
 603:       }
 604: 
 605:       /**
 606:        * This method does
 607:        * nothing, list children are transient accessible objects which means
 608:        * that they don't fire property change events.
 609:        *
 610:        * @param l not used here
 611:        */
 612:       public void removePropertyChangeListener(PropertyChangeListener l)
 613:       {
 614:         // Do nothing here.
 615:       }
 616: 
 617:       // TODO: Implement the remaining methods of this class.
 618:     }
 619: 
 620:     /**
 621:      * Create a new AccessibleJList.
 622:      */
 623:     public AccessibleJList()
 624:     {
 625:       // Nothing to do here.
 626:     }
 627: 
 628:     /**
 629:      * Returns the number of selected accessible children.
 630:      *
 631:      * @return the number of selected accessible children
 632:      */
 633:     public int getAccessibleSelectionCount()
 634:     {
 635:       return getSelectedIndices().length;
 636:     }
 637: 
 638:     /**
 639:      * Returns the n-th selected accessible child.
 640:      *
 641:      * @param n the index of the selected child to return
 642:      *
 643:      * @return the n-th selected accessible child
 644:      */
 645:     public Accessible getAccessibleSelection(int n)
 646:     {
 647:       return new AccessibleJListChild(JList.this, getSelectedIndices()[n]);
 648:     }
 649: 
 650:     /**
 651:      * Returns <code>true</code> if the n-th child is selected,
 652:      * <code>false</code> otherwise.
 653:      *
 654:      * @param n the index of the child of which the selected state is queried
 655:      *
 656:      * @return <code>true</code> if the n-th child is selected,
 657:      *         <code>false</code> otherwise
 658:      */
 659:     public boolean isAccessibleChildSelected(int n)
 660:     {
 661:       return isSelectedIndex(n);
 662:     }
 663: 
 664:     /**
 665:      * Adds the accessible item with the specified index to the selected items.
 666:      * If multiple selections are supported, the item is added to the selection,
 667:      * otherwise the item replaces the current selection.
 668:      *
 669:      * @param i the index of the item to add to the selection
 670:      */
 671:     public void addAccessibleSelection(int i)
 672:     {
 673:       addSelectionInterval(i, i);
 674:     }
 675: 
 676:     /**
 677:      * Removes the accessible item with the specified index to the selection.
 678:      *
 679:      * @param i the index of the item to be removed from the selection
 680:      */
 681:     public void removeAccessibleSelection(int i)
 682:     {
 683:       removeSelectionInterval(i, i);
 684:     }
 685: 
 686:     /**
 687:      * Remove all selection items from the selection.
 688:      */
 689:     public void clearAccessibleSelection()
 690:     {
 691:       clearSelection();
 692:     }
 693: 
 694:     /**
 695:      * Selects all items if multiple selections are supported.
 696:      * Otherwise do nothing.
 697:      */
 698:     public void selectAllAccessibleSelection()
 699:     {
 700:       addSelectionInterval(0, getModel().getSize());
 701:     }
 702: 
 703:     /**
 704:      * Receices notification when the list selection is changed. This method
 705:      * fires two property change events, the first with
 706:      * {@link AccessibleContext#ACCESSIBLE_VISIBLE_DATA_PROPERTY} and the second
 707:      * with {@link AccessibleContext#ACCESSIBLE_SELECTION_PROPERTY}.
 708:      *
 709:      * @param event the list selection event
 710:      */
 711:     public void valueChanged(ListSelectionEvent event)
 712:     {
 713:       firePropertyChange(ACCESSIBLE_VISIBLE_DATA_PROPERTY, Boolean.FALSE,
 714:                          Boolean.TRUE);
 715:       firePropertyChange(ACCESSIBLE_SELECTION_PROPERTY, Boolean.FALSE,
 716:                          Boolean.TRUE);
 717:     }
 718: 
 719:     /**
 720:      * Receives notification when items have changed in the
 721:      * <code>JList</code>. This method fires a property change event with
 722:      * {@link AccessibleContext#ACCESSIBLE_VISIBLE_DATA_PROPERTY}.
 723:      *
 724:      * @param event the list data event
 725:      */
 726:     public void contentsChanged(ListDataEvent event)
 727:     {
 728:       firePropertyChange(ACCESSIBLE_VISIBLE_DATA_PROPERTY, Boolean.FALSE,
 729:                          Boolean.TRUE);
 730:     }
 731: 
 732:     /**
 733:      * Receives notification when items are inserted into the
 734:      * <code>JList</code>. This method fires a property change event with
 735:      * {@link AccessibleContext#ACCESSIBLE_VISIBLE_DATA_PROPERTY}.
 736:      *
 737:      * @param event the list data event
 738:      */
 739:     public void intervalAdded(ListDataEvent event)
 740:     {
 741:       firePropertyChange(ACCESSIBLE_VISIBLE_DATA_PROPERTY, Boolean.FALSE,
 742:                          Boolean.TRUE);
 743:     }
 744: 
 745:     /**
 746:      * Receives notification when items are removed from the
 747:      * <code>JList</code>. This method fires a property change event with
 748:      * {@link AccessibleContext#ACCESSIBLE_VISIBLE_DATA_PROPERTY}.
 749:      *
 750:      * @param event the list data event
 751:      */
 752:     public void intervalRemoved(ListDataEvent event)
 753:     {
 754:       firePropertyChange(ACCESSIBLE_VISIBLE_DATA_PROPERTY, Boolean.FALSE,
 755:                          Boolean.TRUE);
 756:     }
 757: 
 758: 
 759:     /**
 760:      * Receives notification about changes of the <code>JList</code>'s
 761:      * properties. This is used to re-register this object as listener to
 762:      * the data model and selection model when the data model or selection model
 763:      * changes.
 764:      *
 765:      * @param e the property change event
 766:      */
 767:     public void propertyChange(PropertyChangeEvent e)
 768:     {
 769:       String propertyName = e.getPropertyName();
 770:       if (propertyName.equals("model"))
 771:         {
 772:           ListModel oldModel = (ListModel) e.getOldValue();
 773:           oldModel.removeListDataListener(this);
 774:           ListModel newModel = (ListModel) e.getNewValue();
 775:           newModel.addListDataListener(this);
 776:         }
 777:       else if (propertyName.equals("selectionModel"))
 778:         {
 779:           ListSelectionModel oldModel = (ListSelectionModel) e.getOldValue();
 780:           oldModel.removeListSelectionListener(this);
 781:           ListSelectionModel newModel = (ListSelectionModel) e.getNewValue();
 782:           oldModel.addListSelectionListener(this);
 783:         }
 784:     }
 785: 
 786:     /**
 787:      * Return the state set of the <code>JList</code>.
 788:      *
 789:      * @return the state set of the <code>JList</code>
 790:      */
 791:     public AccessibleStateSet getAccessibleStateSet()
 792:     {
 793:       // TODO: Figure out if there is possibly more state that must be
 794:       // handled here.
 795:       AccessibleStateSet s = super.getAccessibleStateSet();
 796:       if (getSelectionMode() != ListSelectionModel.SINGLE_SELECTION)
 797:         s.add(AccessibleState.MULTISELECTABLE);
 798:       return s;
 799:     }
 800: 
 801:     /**
 802:      * Returns the accessible role for <code>JList</code>,
 803:      * {@link AccessibleRole#LIST}.
 804:      *
 805:      * @return the accessible role for <code>JList</code>
 806:      */
 807:     public AccessibleRole getAccessibleRole()
 808:     {
 809:       return AccessibleRole.LIST;
 810:     }
 811: 
 812:     /**
 813:      * Returns the accessible child at the visual location <code>p</code>
 814:      * (relative to the upper left corner of the <code>JList</code>). If there
 815:      * is no child at that location, this returns <code>null</code>.
 816:      *
 817:      * @param p the screen location for which to return the accessible child
 818:      *
 819:      * @return the accessible child at the specified location, or
 820:      *         <code>null</code> if there is no child at that location
 821:      */
 822:     public Accessible getAccessibleAt(Point p)
 823:     {
 824:       int childIndex = locationToIndex(p);
 825:       return getAccessibleChild(childIndex);
 826:     }
 827: 
 828:     /**
 829:      * Returns the number of accessible children in the <code>JList</code>.
 830:      *
 831:      * @return the number of accessible children in the <code>JList</code>
 832:      */
 833:     public int getAccessibleChildrenCount()
 834:     {
 835:       return getModel().getSize();
 836:     }
 837: 
 838:     /**
 839:      * Returns the n-th accessible child of this <code>JList</code>. This will
 840:      * be an instance of {@link AccessibleJListChild}. If there is no child
 841:      * at that index, <code>null</code> is returned.
 842:      *
 843:      * @param n the index of the child to return
 844:      *
 845:      * @return the n-th accessible child of this <code>JList</code>
 846:      */
 847:     public Accessible getAccessibleChild(int n)
 848:     {
 849:       if (getModel().getSize() <= n)
 850:         return null;
 851:       return new AccessibleJListChild(JList.this, n);
 852:     }
 853:   }
 854: 
 855:   private static final long serialVersionUID = 4406629526391098046L;
 856: 
 857:   /**
 858:    * Constant value used in "layoutOrientation" property. This value means
 859:    * that cells are laid out in a single vertical column. This is the default.
 860:    */
 861:   public static final int VERTICAL = 0;
 862: 
 863:   /**
 864:    * Constant value used in "layoutOrientation" property. This value means
 865:    * that cells are laid out in multiple columns "newspaper style", filling
 866:    * vertically first, then horizontally.
 867:    */
 868:   public static final int VERTICAL_WRAP = 1;
 869: 
 870:   /**
 871:    * Constant value used in "layoutOrientation" property. This value means
 872:    * that cells are laid out in multiple columns "newspaper style",
 873:    * filling horizontally first, then vertically.
 874:    */
 875:   public static final int HORIZONTAL_WRAP = 2;
 876: 
 877:   /**
 878:    * This property indicates whether "drag and drop" functions are enabled
 879:    * on the list.
 880:    */
 881:   boolean dragEnabled;
 882: 
 883:   /** This property provides a strategy for rendering cells in the list. */
 884:   ListCellRenderer cellRenderer;
 885: 
 886:   /**
 887:    * This property indicates an fixed width to assign to all cells in the
 888:    * list. If its value is <code>-1</code>, no width has been
 889:    * assigned. This value can be set explicitly, or implicitly by setting
 890:    * the {@link #prototypeCellValue} property.
 891:    */
 892:   int fixedCellWidth;
 893: 
 894:   /**
 895:    * This property indicates an fixed height to assign to all cells in the
 896:    * list. If its value is <code>-1</code>, no height has been
 897:    * assigned. This value can be set explicitly, or implicitly by setting
 898:    * the {@link #prototypeCellValue} property.
 899:    */
 900:   int fixedCellHeight;
 901: 
 902:   /**
 903:    * This property holds the current layout orientation of the list, which
 904:    * is one of the integer constants {@link #VERTICAL}, {@link
 905:    * #VERTICAL_WRAP}, or {@link #HORIZONTAL_WRAP}.
 906:    */
 907:   int layoutOrientation;
 908: 
 909:   /** This property holds the data elements displayed by the list. */
 910:   ListModel model;
 911: 
 912:   /**
 913:    * <p>This property holds a reference to a "prototype" data value --
 914:    * typically a String -- which is used to calculate the {@link
 915:    * #fixedCellWidth} and {@link #fixedCellHeight} properties, using the
 916:    * {@link #cellRenderer} property to acquire a component to render the
 917:    * prototype.</p>
 918:    *
 919:    * <p>It is important that you <em>not</em> set this value to a
 920:    * component. It has to be a <em>data value</em> such as the objects you
 921:    * would find in the list's model. Setting it to a component will have
 922:    * undefined (and undesirable) affects. </p>
 923:    */
 924:   Object prototypeCellValue;
 925: 
 926:   /**
 927:    * This property specifies a foreground color for the selected cells in
 928:    * the list. When {@link ListCellRenderer#getListCellRendererComponent}
 929:    * is called with a selected cell object, the component returned will
 930:    * have its "foreground" set to this color.
 931:    */
 932:   Color selectionBackground;
 933: 
 934:   /**
 935:    * This property specifies a background color for the selected cells in
 936:    * the list. When {@link ListCellRenderer#getListCellRendererComponent}
 937:    * is called with a selected cell object, the component returned will
 938:    * have its "background" property set to this color.
 939:    */
 940:   Color selectionForeground;
 941: 
 942:   /**
 943:    * This property holds a description of which data elements in the {@link
 944:    * #model} property should be considered "selected", when displaying and
 945:    * interacting with the list.
 946:    */
 947:   ListSelectionModel selectionModel;
 948: 
 949:   /**
 950:    * This property indicates a <em>preference</em> for the number of rows
 951:    * displayed in the list, and will scale the
 952:    * {@link #getPreferredScrollableViewportSize} property accordingly. The actual
 953:    * number of displayed rows, when the list is placed in a real {@link
 954:    * JViewport} or other component, may be greater or less than this number.
 955:    */
 956:   int visibleRowCount;
 957: 
 958:   /**
 959:    * Fire a {@link ListSelectionEvent} to all the registered
 960:    * ListSelectionListeners.
 961:    *
 962:    * @param firstIndex  the lowest index covering the selection change.
 963:    * @param lastIndex  the highest index covering the selection change.
 964:    * @param isAdjusting  a flag indicating if this event is one in a series
 965:    *     of events updating the selection.
 966:    */
 967:   protected void fireSelectionValueChanged(int firstIndex, int lastIndex,
 968:                                            boolean isAdjusting)
 969:   {
 970:     ListSelectionEvent evt = new ListSelectionEvent(this, firstIndex,
 971:                                                     lastIndex, isAdjusting);
 972:     ListSelectionListener listeners[] = getListSelectionListeners();
 973:     for (int i = 0; i < listeners.length; ++i)
 974:       {
 975:         listeners[i].valueChanged(evt);
 976:       }
 977:   }
 978: 
 979:   /**
 980:    * This private listener propagates {@link ListSelectionEvent} events
 981:    * from the list's "selectionModel" property to the list's {@link
 982:    * ListSelectionListener} listeners. It also listens to {@link
 983:    * ListDataEvent} events from the list's {@link #model} property. If this
 984:    * class receives either type of event, it triggers repainting of the
 985:    * list.
 986:    */
 987:   private class ListListener
 988:     implements ListSelectionListener, ListDataListener
 989:   {
 990:     // ListDataListener events
 991:     public void contentsChanged(ListDataEvent event)
 992:     {
 993:       JList.this.revalidate();
 994:       JList.this.repaint();
 995:     }
 996:     public void intervalAdded(ListDataEvent event)
 997:     {
 998:       JList.this.revalidate();
 999:       JList.this.repaint();
1000:     }
1001:     public void intervalRemoved(ListDataEvent event)
1002:     {
1003:       JList.this.revalidate();
1004:       JList.this.repaint();
1005:     }
1006:     // ListSelectionListener events
1007:     public void valueChanged(ListSelectionEvent event)
1008:     {
1009:       JList.this.fireSelectionValueChanged(event.getFirstIndex(),
1010:                                            event.getLastIndex(),
1011:                                            event.getValueIsAdjusting());
1012:       JList.this.repaint();
1013:     }
1014:   }
1015: 
1016:   /**
1017:    * Shared ListListener instance, subscribed to both the current {@link
1018:    * #model} and {@link #selectionModel} properties of the list.
1019:    */
1020:   ListListener listListener;
1021: 
1022: 
1023:   /**
1024:    * Creates a new <code>JList</code> object.
1025:    */
1026:   public JList()
1027:   {
1028:     init(new DefaultListModel());
1029:   }
1030: 
1031:   /**
1032:    * Creates a new <code>JList</code> object.
1033:    *
1034:    * @param items  the initial list items.
1035:    */
1036:   public JList(Object[] items)
1037:   {
1038:     init(createListModel(items));
1039:   }
1040: 
1041:   /**
1042:    * Creates a new <code>JList</code> object.
1043:    *
1044:    * @param items  the initial list items.
1045:    */
1046:   public JList(Vector<?> items)
1047:   {
1048:     init(createListModel(items));
1049:   }
1050: 
1051:   /**
1052:    * Creates a new <code>JList</code> object.
1053:    *
1054:    * @param model  a model containing the list items (<code>null</code> not
1055:    *     permitted).
1056:    *
1057:    * @throws IllegalArgumentException if <code>model</code> is
1058:    *     <code>null</code>.
1059:    */
1060:   public JList(ListModel model)
1061:   {
1062:     init(model);
1063:   }
1064: 
1065:   /**
1066:    * Initializes the list.
1067:    *
1068:    * @param m  the list model (<code>null</code> not permitted).
1069:    */
1070:   private void init(ListModel m)
1071:   {
1072:     if (m == null)
1073:       throw new IllegalArgumentException("Null model not permitted.");
1074:     dragEnabled = false;
1075:     fixedCellHeight = -1;
1076:     fixedCellWidth = -1;
1077:     layoutOrientation = VERTICAL;
1078:     opaque = true;
1079:     visibleRowCount = 8;
1080: 
1081:     cellRenderer = new DefaultListCellRenderer();
1082:     listListener = new ListListener();
1083: 
1084:     model = m;
1085:     if (model != null)
1086:       model.addListDataListener(listListener);
1087: 
1088:     selectionModel = createSelectionModel();
1089:     if (selectionModel != null)
1090:       {
1091:         selectionModel.addListSelectionListener(listListener);
1092:         selectionModel.setSelectionMode
1093:                               (ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
1094:       }
1095:     setLayout(null);
1096: 
1097:     updateUI();
1098:   }
1099: 
1100:   /**
1101:    * Creates the default <code>ListSelectionModel</code>.
1102:    *
1103:    * @return the <code>ListSelectionModel</code>
1104:    */
1105:   protected ListSelectionModel createSelectionModel()
1106:   {
1107:     return new DefaultListSelectionModel();
1108:   }
1109: 
1110:   /**
1111:    * Gets the value of the {@link #fixedCellHeight} property. This property
1112:    * may be <code>-1</code> to indicate that no cell height has been
1113:    * set. This property is also set implicitly when the
1114:    * {@link #prototypeCellValue} property is set.
1115:    *
1116:    * @return The current value of the property
1117:    *
1118:    * @see #fixedCellHeight
1119:    * @see #setFixedCellHeight
1120:    * @see #setPrototypeCellValue
1121:    */
1122:   public int getFixedCellHeight()
1123:   {
1124:     return fixedCellHeight;
1125:   }
1126: 
1127:   /**
1128:    * Sets the value of the {@link #fixedCellHeight} property. This property
1129:    * may be <code>-1</code> to indicate that no cell height has been
1130:    * set. This property is also set implicitly when the {@link
1131:    * #prototypeCellValue} property is set, but setting it explicitly
1132:    * overrides the height computed from {@link #prototypeCellValue}.
1133:    *
1134:    * @param h  the height.
1135:    *
1136:    * @see #getFixedCellHeight
1137:    * @see #getPrototypeCellValue
1138:    */
1139:   public void setFixedCellHeight(int h)
1140:   {
1141:     if (fixedCellHeight == h)
1142:       return;
1143: 
1144:     int old = fixedCellHeight;
1145:     fixedCellHeight = h;
1146:     firePropertyChange("fixedCellHeight", old, h);
1147:   }
1148: 
1149: 
1150:   /**
1151:    * Gets the value of the {@link #fixedCellWidth} property. This property
1152:    * may be <code>-1</code> to indicate that no cell width has been
1153:    * set. This property is also set implicitly when the {@link
1154:    * #prototypeCellValue} property is set.
1155:    *
1156:    * @return The current value of the property
1157:    *
1158:    * @see #setFixedCellWidth
1159:    * @see #setPrototypeCellValue
1160:    */
1161:   public int getFixedCellWidth()
1162:   {
1163:     return fixedCellWidth;
1164:   }
1165: 
1166:   /**
1167:    * Sets the value of the {@link #fixedCellWidth} property. This property
1168:    * may be <code>-1</code> to indicate that no cell width has been
1169:    * set. This property is also set implicitly when the {@link
1170:    * #prototypeCellValue} property is set, but setting it explicitly
1171:    * overrides the width computed from {@link #prototypeCellValue}.
1172:    *
1173:    * @param w  the width.
1174:    *
1175:    * @see #getFixedCellHeight
1176:    * @see #getPrototypeCellValue
1177:    */
1178:   public void setFixedCellWidth(int w)
1179:   {
1180:     if (fixedCellWidth == w)
1181:       return;
1182: 
1183:     int old = fixedCellWidth;
1184:     fixedCellWidth = w;
1185:     firePropertyChange("fixedCellWidth", old, w);
1186:   }
1187: 
1188:   /**
1189:    * Gets the value of the {@link #visibleRowCount} property.  The default
1190:    * value is 8.
1191:    *
1192:    * @return the current value of the property.
1193:    *
1194:    * @see #setVisibleRowCount(int)
1195:    */
1196:   public int getVisibleRowCount()
1197:   {
1198:     return visibleRowCount;
1199:   }
1200: 
1201:   /**
1202:    * Sets the value of the {@link #visibleRowCount} property.
1203:    *
1204:    * @param vc The new property value
1205:    *
1206:    * @see #getVisibleRowCount()
1207:    */
1208:   public void setVisibleRowCount(int vc)
1209:   {
1210:     if (visibleRowCount != vc)
1211:       {
1212:         int oldValue = visibleRowCount;
1213:         visibleRowCount = Math.max(vc, 0);
1214:         firePropertyChange("visibleRowCount", oldValue, vc);
1215:         revalidate();
1216:         repaint();
1217:       }
1218:   }
1219: 
1220:   /**
1221:    * Adds a {@link ListSelectionListener} to the listener list for this
1222:    * list. The listener will be called back with a {@link
1223:    * ListSelectionEvent} any time the list's {@link #selectionModel}
1224:    * property changes. The source of such events will be the JList,
1225:    * not the selection model.
1226:    *
1227:    * @param listener The new listener to add
1228:    */
1229:   public void addListSelectionListener(ListSelectionListener listener)
1230:   {
1231:     listenerList.add (ListSelectionListener.class, listener);
1232:   }
1233: 
1234:   /**
1235:    * Removes a {@link ListSelectionListener} from the listener list for
1236:    * this list. The listener will no longer be called when the list's
1237:    * {@link #selectionModel} changes.
1238:    *
1239:    * @param listener The listener to remove
1240:    */
1241:   public void removeListSelectionListener(ListSelectionListener listener)
1242:   {
1243:     listenerList.remove(ListSelectionListener.class, listener);
1244:   }
1245: 
1246:   /**
1247:    * Returns an array of all ListSelectionListeners subscribed to this
1248:    * list.
1249:    *
1250:    * @return The current subscribed listeners
1251:    *
1252:    * @since 1.4
1253:    */
1254:   public ListSelectionListener[] getListSelectionListeners()
1255:   {
1256:     return (ListSelectionListener[]) getListeners(ListSelectionListener.class);
1257:   }
1258: 
1259:   /**
1260:    * Returns the selection mode for the list (one of:
1261:    * {@link ListSelectionModel#SINGLE_SELECTION},
1262:    * {@link ListSelectionModel#SINGLE_INTERVAL_SELECTION} and
1263:    * {@link ListSelectionModel#MULTIPLE_INTERVAL_SELECTION}).
1264:    *
1265:    * @return The selection mode.
1266:    *
1267:    * @see #setSelectionMode(int)
1268:    */
1269:   public int getSelectionMode()
1270:   {
1271:     return selectionModel.getSelectionMode();
1272:   }
1273: 
1274:   /**
1275:    * Sets the list's "selectionMode" property, which simply mirrors the
1276:    * same property on the list's {@link #selectionModel} property. This
1277:    * property should be one of the integer constants
1278:    * <code>SINGLE_SELECTION</code>, <code>SINGLE_INTERVAL_SELECTION</code>,
1279:    * or <code>MULTIPLE_INTERVAL_SELECTION</code> from the {@link
1280:    * ListSelectionModel} interface.
1281:    *
1282:    * @param a The new selection mode
1283:    */
1284:   public void setSelectionMode(int a)
1285:   {
1286:     selectionModel.setSelectionMode(a);
1287:   }
1288: 
1289:   /**
1290:    * Adds the interval <code>[a,a]</code> to the set of selections managed
1291:    * by this list's {@link #selectionModel} property. Depending on the
1292:    * selection mode, this may cause existing selections to become invalid,
1293:    * or may simply expand the set of selections.
1294:    *
1295:    * @param a A number in the half-open range <code>[0, x)</code> where
1296:    * <code>x = getModel.getSize()</code>, indicating the index of an
1297:    * element in the list to select. When &lt; 0 the selection is cleared.
1298:    *
1299:    * @see #setSelectionMode
1300:    * @see #selectionModel
1301:    */
1302:   public void setSelectedIndex(int a)
1303:   {
1304:     if (a < 0)
1305:       selectionModel.clearSelection();
1306:     else
1307:       selectionModel.setSelectionInterval(a, a);
1308:   }
1309: 
1310:   /**
1311:    * For each element <code>a[i]</code> of the provided array
1312:    * <code>a</code>, calls {@link #setSelectedIndex} on <code>a[i]</code>.
1313:    *
1314:    * @param a  an array of selected indices (<code>null</code> not permitted).
1315:    *
1316:    * @throws NullPointerException if <code>a</code> is <code>null</code>.
1317:    * @see #setSelectionMode
1318:    * @see #selectionModel
1319:    */
1320:   public void setSelectedIndices(int [] a)
1321:   {
1322:     for (int i = 0; i < a.length; ++i)
1323:       setSelectedIndex(a[i]);
1324:   }
1325: 
1326:   /**
1327:    * Returns the minimum index of an element in the list which is currently
1328:    * selected.
1329:    *
1330:    * @return A number in the half-open range <code>[0, x)</code> where
1331:    * <code>x = getModel.getSize()</code>, indicating the minimum index of
1332:    * an element in the list for which the element is selected, or
1333:    * <code>-1</code> if no elements are selected
1334:    */
1335:   public int getSelectedIndex()
1336:   {
1337:     return selectionModel.getMinSelectionIndex();
1338:   }
1339: 
1340:   /**
1341:    * Returns <code>true</code> if the model's selection is empty, otherwise
1342:    * <code>false</code>.
1343:    *
1344:    * @return The return value of {@link ListSelectionModel#isSelectionEmpty}
1345:    */
1346:   public boolean isSelectionEmpty()
1347:   {
1348:     return selectionModel.isSelectionEmpty();
1349:   }
1350: 
1351:   /**
1352:    * Returns the list index of the upper left or upper right corner of the
1353:    * visible rectangle of this list, depending on the {@link
1354:    * Component#getComponentOrientation} property.
1355:    *
1356:    * @return The index of the first visible list cell, or <code>-1</code>
1357:    * if none is visible.
1358:    */
1359:   public int getFirstVisibleIndex()
1360:   {
1361:     ComponentOrientation or = getComponentOrientation();
1362:     Rectangle r = getVisibleRect();
1363:     if (or == ComponentOrientation.RIGHT_TO_LEFT)
1364:       r.translate((int) r.getWidth() - 1, 0);
1365:     return getUI().locationToIndex(this, r.getLocation());
1366:   }
1367: 
1368: 
1369:   /**
1370:    * Returns index of the cell to which specified location is closest to. If
1371:    * the location is outside the bounds of the list, then the greatest index
1372:    * in the list model is returned. If the list model is empty, then
1373:    * <code>-1</code> is returned.
1374:    *
1375:    * @param location for which to look for in the list
1376:    *
1377:    * @return index of the cell to which specified location is closest to.
1378:    */
1379:    public int locationToIndex(Point location)
1380:    {
1381:      return getUI().locationToIndex(this, location);
1382:    }
1383: 
1384:   /**
1385:    * Returns location of the cell located at the specified index in the list.
1386:    * @param index of the cell for which location will be determined
1387:    *
1388:    * @return location of the cell located at the specified index in the list.
1389:    */
1390:    public Point indexToLocation(int index)
1391:    {
1392:      return getUI().indexToLocation(this, index);
1393:    }
1394: 
1395:   /**
1396:    * Returns the list index of the lower right or lower left corner of the
1397:    * visible rectangle of this list, depending on the {@link
1398:    * Component#getComponentOrientation} property.
1399:    *
1400:    * @return The index of the last visible list cell, or <code>-1</code>
1401:    * if none is visible.
1402:    */
1403:   public int getLastVisibleIndex()
1404:   {
1405:     ComponentOrientation or = getComponentOrientation();
1406:     Rectangle r = getVisibleRect();
1407:     r.translate(0, (int) r.getHeight() - 1);
1408:     if (or == ComponentOrientation.LEFT_TO_RIGHT)
1409:       r.translate((int) r.getWidth() - 1, 0);
1410:     if (getUI().locationToIndex(this, r.getLocation()) == -1
1411:         && indexToLocation(getModel().getSize() - 1).y < r.y)
1412:       return getModel().getSize() - 1;
1413:     return getUI().locationToIndex(this, r.getLocation());
1414:   }
1415: 
1416:   /**
1417:    * Returns the indices of values in the {@link #model} property which are
1418:    * selected.
1419:    *
1420:    * @return An array of model indices, each of which is selected according
1421:    *         to the {@link #getSelectedValues} property
1422:    */
1423:   public int[] getSelectedIndices()
1424:   {
1425:     int lo, hi, n, i, j;
1426:     if (selectionModel.isSelectionEmpty())
1427:       return new int[0];
1428:     lo = selectionModel.getMinSelectionIndex();
1429:     hi = selectionModel.getMaxSelectionIndex();
1430:     n = 0;
1431:     for (i = lo; i <= hi; ++i)
1432:       if (selectionModel.isSelectedIndex(i))
1433:         n++;
1434:     int [] v = new int[n];
1435:     j = 0;
1436:     for (i = lo; i <= hi; ++i)
1437:       if (selectionModel.isSelectedIndex(i))
1438:         v[j++] = i;
1439:     return v;
1440:   }
1441: 
1442:   /**
1443:    * Indicates whether the list element at a given index value is
1444:    * currently selected.
1445:    *
1446:    * @param a The index to check
1447:    * @return <code>true</code> if <code>a</code> is the index of a selected
1448:    * list element
1449:    */
1450:   public boolean isSelectedIndex(int a)
1451:   {
1452:     return selectionModel.isSelectedIndex(a);
1453:   }
1454: 
1455:   /**
1456:    * Returns the first value in the list's {@link #model} property which is
1457:    * selected, according to the list's {@link #selectionModel} property.
1458:    * This is equivalent to calling
1459:    * <code>getModel()getElementAt(getSelectedIndex())</code>, with a check
1460:    * for the special index value of <code>-1</code> which returns null
1461:    * <code>null</code>.
1462:    *
1463:    * @return The first selected element, or <code>null</code> if no element
1464:    * is selected.
1465:    *
1466:    * @see #getSelectedValues
1467:    */
1468:   public Object getSelectedValue()
1469:   {
1470:     int index = getSelectedIndex();
1471:     if (index == -1)
1472:       return null;
1473:     return getModel().getElementAt(index);
1474:   }
1475: 
1476:   /**
1477:    * Returns all the values in the list's {@link #model} property which are
1478:    * selected, according to the list's {@link #selectionModel} property.
1479:    *
1480:    * @return An array containing all the selected values
1481:    * @see #setSelectedValue
1482:    */
1483:   public Object[] getSelectedValues()
1484:   {
1485:     int[] idx = getSelectedIndices();
1486:     Object[] v = new Object[idx.length];
1487:     for (int i = 0; i < idx.length; ++i)
1488:       v[i] = getModel().getElementAt(idx[i]);
1489:     return v;
1490:   }
1491: 
1492:   /**
1493:    * Gets the value of the {@link #selectionBackground} property.
1494:    *
1495:    * @return The current value of the property
1496:    */
1497:   public Color getSelectionBackground()
1498:   {
1499:     return selectionBackground;
1500:   }
1501: 
1502:   /**
1503:    * Sets the value of the {@link #selectionBackground} property.
1504:    *
1505:    * @param c The new value of the property
1506:    */
1507:   public void setSelectionBackground(Color c)
1508:   {
1509:     if (selectionBackground == c)
1510:       return;
1511: 
1512:     Color old = selectionBackground;
1513:     selectionBackground = c;
1514:     firePropertyChange("selectionBackground", old, c);
1515:     repaint();
1516:   }
1517: 
1518:   /**
1519:    * Gets the value of the {@link #selectionForeground} property.
1520:    *
1521:    * @return The current value of the property
1522:    */
1523:   public Color getSelectionForeground()
1524:   {
1525:     return selectionForeground;
1526:   }
1527: 
1528:   /**
1529:    * Sets the value of the {@link #selectionForeground} property.
1530:    *
1531:    * @param c The new value of the property
1532:    */
1533:   public void setSelectionForeground(Color c)
1534:   {
1535:     if (selectionForeground == c)
1536:       return;
1537: 
1538:     Color old = selectionForeground;
1539:     selectionForeground = c;
1540:     firePropertyChange("selectionForeground", old, c);
1541:   }
1542: 
1543:   /**
1544:    * Sets the selection to cover only the specified value, if it
1545:    * exists in the model.
1546:    *
1547:    * @param obj The object to select
1548:    * @param scroll Whether to scroll the list to make the newly selected
1549:    * value visible
1550:    *
1551:    * @see #ensureIndexIsVisible
1552:    */
1553: 
1554:   public void setSelectedValue(Object obj, boolean scroll)
1555:   {
1556:     for (int i = 0; i < model.getSize(); ++i)
1557:       {
1558:         if (model.getElementAt(i).equals(obj))
1559:           {
1560:             setSelectedIndex(i);
1561:             if (scroll)
1562:               ensureIndexIsVisible(i);
1563:             break;
1564:           }
1565:       }
1566:   }
1567: 
1568:   /**
1569:    * Scrolls this list to make the specified cell visible. This
1570:    * only works if the list is contained within a viewport.
1571:    *
1572:    * @param i The list index to make visible
1573:    *
1574:    * @see JComponent#scrollRectToVisible
1575:    */
1576:   public void ensureIndexIsVisible(int i)
1577:   {
1578:     Rectangle r = getUI().getCellBounds(this, i, i);
1579:     if (r != null)
1580:       scrollRectToVisible(r);
1581:   }
1582: 
1583:   /**
1584:    * Sets the {@link #model} property of the list to a new anonymous
1585:    * {@link AbstractListModel} subclass which accesses the provided Object
1586:    * array directly.
1587:    *
1588:    * @param listData The object array to build a new list model on
1589:    * @see #setModel
1590:    */
1591:   public void setListData(Object[] listData)
1592:   {
1593:     setModel(createListModel(listData));
1594:   }
1595: 
1596:   /**
1597:    * Returns a {@link ListModel} backed by the specified array.
1598:    *
1599:    * @param items  the list items (don't use <code>null</code>).
1600:    *
1601:    * @return A list model containing the specified items.
1602:    */
1603:   private ListModel createListModel(final Object[] items)
1604:   {
1605:     return new AbstractListModel()
1606:       {
1607:         public int getSize()
1608:         {
1609:           return items.length;
1610:         }
1611:         public Object getElementAt(int i)
1612:         {
1613:           return items[i];
1614:         }
1615:       };
1616:   }
1617: 
1618:   /**
1619:    * Returns a {@link ListModel} backed by the specified vector.
1620:    *
1621:    * @param items  the list items (don't use <code>null</code>).
1622:    *
1623:    * @return A list model containing the specified items.
1624:    */
1625:   private ListModel createListModel(final Vector items)
1626:   {
1627:     return new AbstractListModel()
1628:       {
1629:         public int getSize()
1630:         {
1631:           return items.size();
1632:         }
1633:         public Object getElementAt(int i)
1634:         {
1635:           return items.get(i);
1636:         }
1637:       };
1638:   }
1639: 
1640:   /**
1641:    * Sets the {@link #model} property of the list to a new anonymous {@link
1642:    * AbstractListModel} subclass which accesses the provided vector
1643:    * directly.
1644:    *
1645:    * @param listData The object array to build a new list model on
1646:    * @see #setModel
1647:    */
1648:   public void setListData(final Vector<?> listData)
1649:   {
1650:     setModel(new AbstractListModel()
1651:       {
1652:         public int getSize()
1653:         {
1654:           return listData.size();
1655:         }
1656: 
1657:         public Object getElementAt(int i)
1658:         {
1659:           return listData.elementAt(i);
1660:         }
1661:       });
1662:   }
1663: 
1664:   /**
1665:    * Gets the value of the {@link #cellRenderer} property.
1666:    *
1667:    * @return The current value of the property
1668:    */
1669:   public ListCellRenderer getCellRenderer()
1670:   {
1671:     return cellRenderer;
1672:   }
1673: 
1674:   /**
1675:    * Sets the value of the {@link #getCellRenderer} property.
1676:    *
1677:    * @param renderer The new property value
1678:    */
1679:   public void setCellRenderer(ListCellRenderer renderer)
1680:   {
1681:     if (cellRenderer == renderer)
1682:       return;
1683: 
1684:     ListCellRenderer old = cellRenderer;
1685:     cellRenderer = renderer;
1686:     firePropertyChange("cellRenderer", old, renderer);
1687:     revalidate();
1688:     repaint();
1689:   }
1690: 
1691:   /**
1692:    * Gets the value of the {@link #model} property.
1693:    *
1694:    * @return The current value of the property
1695:    */
1696:   public ListModel getModel()
1697:   {
1698:     return model;
1699:   }
1700: 
1701:   /**
1702:    * Sets the value of the {@link #model} property. The list's {@link
1703:    * #listListener} is unsubscribed from the existing model, if it exists,
1704:    * and re-subscribed to the new model.
1705:    *
1706:    * @param model  the new model (<code>null</code> not permitted).
1707:    *
1708:    * @throws IllegalArgumentException if <code>model</code> is
1709:    *         <code>null</code>.
1710:    */
1711:   public void setModel(ListModel model)
1712:   {
1713:     if (model == null)
1714:       throw new IllegalArgumentException("Null 'model' argument.");
1715:     if (this.model == model)
1716:       return;
1717: 
1718:     if (this.model != null)
1719:       this.model.removeListDataListener(listListener);
1720: 
1721:     ListModel old = this.model;
1722:     this.model = model;
1723: 
1724:     if (this.model != null)
1725:       this.model.addListDataListener(listListener);
1726: 
1727:     firePropertyChange("model", old, model);
1728:     revalidate();
1729:     repaint();
1730:   }
1731: 
1732:   /**
1733:    * Returns the selection model for the {@link JList} component.  Note that
1734:    * this class contains a range of convenience methods for configuring the
1735:    * selection model:<br>
1736:    * <ul>
1737:    *   <li>{@link #clearSelection()};</li>
1738:    *   <li>{@link #setSelectionMode(int)};</li>
1739:    *   <li>{@link #addSelectionInterval(int, int)};</li>
1740:    *   <li>{@link #setSelectedIndex(int)};</li>
1741:    *   <li>{@link #setSelectedIndices(int[])};</li>
1742:    *   <li>{@link #setSelectionInterval(int, int)}.</li>
1743:    * </ul>
1744:    *
1745:    * @return The selection model.
1746:    */
1747:   public ListSelectionModel getSelectionModel()
1748:   {
1749:     return selectionModel;
1750:   }
1751: 
1752:   /**
1753:    * Sets the value of the {@link #selectionModel} property. The list's
1754:    * {@link #listListener} is unsubscribed from the existing selection
1755:    * model, if it exists, and re-subscribed to the new selection model.
1756:    *
1757:    * @param model The new property value
1758:    */
1759:   public void setSelectionModel(ListSelectionModel model)
1760:   {
1761:     if (selectionModel == model)
1762:       return;
1763: 
1764:     if (selectionModel != null)
1765:       selectionModel.removeListSelectionListener(listListener);
1766: 
1767:     ListSelectionModel old = selectionModel;
1768:     selectionModel = model;
1769: 
1770:     if (selectionModel != null)
1771:       selectionModel.addListSelectionListener(listListener);
1772: 
1773:     firePropertyChange("selectionModel", old, model);
1774:     revalidate();
1775:     repaint();
1776:   }
1777: 
1778:   /**
1779:    * Gets the value of the UI property.
1780:    *
1781:    * @return The current property value
1782:    */
1783:   public ListUI getUI()
1784:   {
1785:     return (ListUI) ui;
1786:   }
1787: 
1788:   /**
1789:    * Sets the value of the UI property.
1790:    *
1791:    * @param ui The new property value
1792:    */
1793:   public void setUI(ListUI ui)
1794:   {
1795:     super.setUI(ui);
1796:   }
1797: 
1798:   /**
1799:    * Calls {@link #setUI} with the {@link ListUI} subclass
1800:    * returned from calling {@link UIManager#getUI}.
1801:    */
1802:   public void updateUI()
1803:   {
1804:     setUI((ListUI) UIManager.getUI(this));
1805:   }
1806: 
1807:   /**
1808:    * Return the class identifier for the list's UI property.  This should
1809:    * be the constant string <code>"ListUI"</code>, and map to an
1810:    * appropriate UI class in the {@link UIManager}.
1811:    *
1812:    * @return The class identifier
1813:    */
1814:   public String getUIClassID()
1815:   {
1816:     return "ListUI";
1817:   }
1818: 
1819: 
1820:   /**
1821:    * Returns the current value of the {@link #prototypeCellValue}
1822:    * property. This property holds a reference to a "prototype" data value
1823:    * -- typically a String -- which is used to calculate the {@link
1824:    * #fixedCellWidth} and {@link #fixedCellHeight} properties, using the
1825:    * {@link #cellRenderer} property to acquire a component to render the
1826:    * prototype.
1827:    *
1828:    * @return The current prototype cell value
1829:    * @see #setPrototypeCellValue
1830:    */
1831:   public Object getPrototypeCellValue()
1832:   {
1833:     return prototypeCellValue;
1834:   }
1835: 
1836:   /**
1837:    * <p>Set the {@link #prototypeCellValue} property. This property holds a
1838:    * reference to a "prototype" data value -- typically a String -- which
1839:    * is used to calculate the {@link #fixedCellWidth} and {@link
1840:    * #fixedCellHeight} properties, using the {@link #cellRenderer} property
1841:    * to acquire a component to render the prototype.</p>
1842:    *
1843:    * <p>It is important that you <em>not</em> set this value to a
1844:    * component. It has to be a <em>data value</em> such as the objects you
1845:    * would find in the list's model. Setting it to a component will have
1846:    * undefined (and undesirable) affects. </p>
1847:    *
1848:    * @param obj The new prototype cell value
1849:    * @see #getPrototypeCellValue
1850:    */
1851:   public void setPrototypeCellValue(Object obj)
1852:   {
1853:     if (prototypeCellValue == obj)
1854:       return;
1855: 
1856:     Object old = prototypeCellValue;
1857:     Component comp = getCellRenderer()
1858:       .getListCellRendererComponent(this, obj, 0, false, false);
1859:     Dimension d = comp.getPreferredSize();
1860:     fixedCellWidth = d.width;
1861:     fixedCellHeight = d.height;
1862:     prototypeCellValue = obj;
1863:     firePropertyChange("prototypeCellValue", old, obj);
1864:   }
1865: 
1866:   public AccessibleContext getAccessibleContext()
1867:   {
1868:     return new AccessibleJList();
1869:   }
1870: 
1871:   /**
1872:    * Returns a size indicating how much space this list would like to
1873:    * consume, when contained in a scrollable viewport. This is part of the
1874:    * {@link Scrollable} interface, which interacts with {@link
1875:    * ScrollPaneLayout} and {@link JViewport} to define scrollable objects.
1876:    *
1877:    * @return The preferred size
1878:    */
1879:   public Dimension getPreferredScrollableViewportSize()
1880:   {
1881:     //If the layout orientation is not VERTICAL, then this will
1882:     //return the value from getPreferredSize. The current ListUI is
1883:     //expected to override getPreferredSize to return an appropriate value.
1884:     if (getLayoutOrientation() != VERTICAL)
1885:       return getPreferredSize();
1886: 
1887:     int size = getModel().getSize();
1888: 
1889:     // Trivial case: if fixedCellWidth and fixedCellHeight were set
1890:     // just use them
1891:     if (fixedCellHeight != -1 && fixedCellWidth != -1)
1892:       return new Dimension(fixedCellWidth, size * fixedCellHeight);
1893: 
1894:     // If the model is empty we use 16 * the number of visible rows
1895:     // for the height and either fixedCellWidth (if set) or 256
1896:     // for the width
1897:     if (size == 0)
1898:       {
1899:         if (fixedCellWidth == -1)
1900:           return new Dimension(256, 16 * getVisibleRowCount());
1901:         else
1902:           return new Dimension(fixedCellWidth, 16 * getVisibleRowCount());
1903:       }
1904: 
1905:     // Calculate the width: if fixedCellWidth was set use that, otherwise
1906:     // use the preferredWidth
1907:     int prefWidth;
1908:     if (fixedCellWidth != -1)
1909:       prefWidth = fixedCellWidth;
1910:     else
1911:       prefWidth = getPreferredSize().width;
1912: 
1913:     // Calculate the height: if fixedCellHeight was set use that, otherwise
1914:     // use the height of the first row multiplied by the number of visible
1915:     // rows
1916:     int prefHeight;
1917:     if (fixedCellHeight != -1)
1918:       prefHeight = fixedCellHeight;
1919:     else
1920:       prefHeight = getVisibleRowCount() * getCellBounds(0, 0).height;
1921: 
1922:     return new Dimension (prefWidth, prefHeight);
1923:   }
1924: 
1925:   /**
1926:    * <p>Return the number of pixels the list must scroll in order to move a
1927:    * "unit" of the list into the provided visible rectangle. When the
1928:    * provided direction is positive, the call describes a "downwards"
1929:    * scroll, which will be exposing a cell at a <em>greater</em> index in
1930:    * the list than those elements currently showing. Then the provided
1931:    * direction is negative, the call describes an "upwards" scroll, which
1932:    * will be exposing a cell at a <em>lesser</em> index in the list than
1933:    * those elements currently showing.</p>
1934:    *
1935:    * <p>If the provided orientation is <code>HORIZONTAL</code>, the above
1936:    * comments refer to "rightwards" for positive direction, and "leftwards"
1937:    * for negative.</p>
1938:    *
1939:    *
1940:    * @param visibleRect The rectangle to scroll an element into
1941:    * @param orientation One of the numeric consants <code>VERTICAL</code>
1942:    * or <code>HORIZONTAL</code>
1943:    * @param direction An integer indicating the scroll direction: positive means
1944:    * forwards (down, right), negative means backwards (up, left)
1945:    *
1946:    * @return The scrollable unit increment, in pixels
1947:    */
1948:   public int getScrollableUnitIncrement(Rectangle visibleRect,
1949:                                         int orientation, int direction)
1950:   {
1951:     int unit = -1;
1952:     if (orientation == SwingConstants.VERTICAL)
1953:       {
1954:         int row = getFirstVisibleIndex();
1955:         if (row == -1)
1956:           unit = 0;
1957:         else if (direction > 0)
1958:           {
1959:             // Scrolling down.
1960:             Rectangle bounds = getCellBounds(row, row);
1961:             if (bounds != null)
1962:               unit = bounds.height - (visibleRect.y - bounds.y);
1963:             else
1964:               unit = 0;
1965:           }
1966:         else
1967:           {
1968:             // Scrolling up.
1969:             Rectangle bounds = getCellBounds(row, row);
1970:             // First row.
1971:             if (row == 0 && bounds.y == visibleRect.y)
1972:               unit = 0; // No need to scroll.
1973:             else if (bounds.y == visibleRect.y)
1974:               {
1975:                 // Scroll to previous row.
1976:                 Point loc = bounds.getLocation();
1977:                 loc.y--;
1978:                 int prev = locationToIndex(loc);
1979:                 Rectangle prevR = getCellBounds(prev, prev);
1980:                 if (prevR == null || prevR.y >= bounds.y)
1981:                   unit = 0; // For multicolumn lists.
1982:                 else
1983:                   unit = prevR.height;
1984:               }
1985:             else
1986:               unit = visibleRect.y - bounds.y;
1987:           }
1988:       }
1989:     else if (orientation == SwingConstants.HORIZONTAL && getLayoutOrientation() != VERTICAL)
1990:       {
1991:         // Horizontal scrolling.
1992:         int i = locationToIndex(visibleRect.getLocation());
1993:         if (i != -1)
1994:           {
1995:             Rectangle b = getCellBounds(i, i);
1996:             if (b != null)
1997:               {
1998:                 if (b.x != visibleRect.x)
1999:                   {
2000:                     if (direction < 0)
2001:                       unit = Math.abs(b.x - visibleRect.x);
2002:                     else
2003:                       unit = b.width + b.x - visibleRect.x;
2004:                   }
2005:                 else
2006:                   unit = b.width;
2007:               }
2008:           }
2009:       }
2010: 
2011:     if (unit == -1)
2012:       {
2013:         // This fallback seems to be used by the RI for the degenerate cases
2014:         // not covered above.
2015:         Font f = getFont();
2016:         unit = f != null ? f.getSize() : 1;
2017:       }
2018:     return unit;
2019:   }
2020: 
2021:   /**
2022:    * <p>Return the number of pixels the list must scroll in order to move a
2023:    * "block" of the list into the provided visible rectangle. When the
2024:    * provided direction is positive, the call describes a "downwards"
2025:    * scroll, which will be exposing a cell at a <em>greater</em> index in
2026:    * the list than those elements currently showing. Then the provided
2027:    * direction is negative, the call describes an "upwards" scroll, which
2028:    * will be exposing a cell at a <em>lesser</em> index in the list than
2029:    * those elements currently showing.</p>
2030:    *
2031:    * <p>If the provided orientation is <code>HORIZONTAL</code>, the above
2032:    * comments refer to "rightwards" for positive direction, and "leftwards"
2033:    * for negative.</p>
2034:    *
2035:    *
2036:    * @param visibleRect The rectangle to scroll an element into
2037:    * @param orientation One of the numeric consants <code>VERTICAL</code>
2038:    * or <code>HORIZONTAL</code>
2039:    * @param direction An integer indicating the scroll direction: positive means
2040:    * forwards (down, right), negative means backwards (up, left)
2041:    *
2042:    * @return The scrollable unit increment, in pixels
2043:    */
2044:   public int getScrollableBlockIncrement(Rectangle visibleRect,
2045:                                          int orientation, int direction)
2046:   {
2047:     int block = -1;
2048:     if (orientation == SwingConstants.VERTICAL)
2049:       {
2050:         // Default block scroll. Special cases are handled below for
2051:         // better usability.
2052:         block = visibleRect.height;
2053:         if (direction > 0)
2054:           {
2055:             // Scroll down.
2056:             // Scroll so that after scrolling the last line aligns with
2057:             // the lower boundary of the visible area.
2058:             Point p = new Point(visibleRect.x,
2059:                                 visibleRect.y + visibleRect.height - 1);
2060:             int last = locationToIndex(p);
2061:             if (last != -1)
2062:               {
2063:                 Rectangle lastR = getCellBounds(last, last);
2064:                 if (lastR != null)
2065:                   {
2066:                     block = lastR.y - visibleRect.y;
2067:                     if (block == 0&& last < getModel().getSize() - 1)
2068:                       block = lastR.height;
2069:                   }
2070:               }
2071:           }
2072:         else
2073:           {
2074:             // Scroll up.
2075:             // Scroll so that after scrolling the first line aligns with
2076:             // the upper boundary of the visible area.
2077:             Point p = new Point(visibleRect.x,
2078:                                 visibleRect.y - visibleRect.height);
2079:             int newFirst = locationToIndex(p);
2080:             if (newFirst != -1)
2081:               {
2082:                 int first = getFirstVisibleIndex();
2083:                 if (first == -1)
2084:                   first = locationToIndex(visibleRect.getLocation());
2085:                 Rectangle newFirstR = getCellBounds(newFirst, newFirst);
2086:                 Rectangle firstR = getCellBounds(first, first);
2087:                 if (newFirstR != null && firstR != null)
2088:                   {
2089:                     // Search first item that would left the current first
2090:                     // item visible when scrolled to.
2091:                     while (newFirstR.y + visibleRect.height
2092:                            < firstR.y + firstR.height
2093:                            && newFirstR.y < firstR.y)
2094:                       {
2095:                         newFirst++;
2096:                         newFirstR = getCellBounds(newFirst, newFirst);
2097:                       }
2098:                     block = visibleRect.y - newFirstR.y;
2099:                     if (block <= 0 && newFirstR.y > 0)
2100:                       {
2101:                         newFirst--;
2102:                         newFirstR = getCellBounds(newFirst, newFirst);
2103:                         if (newFirstR != null)
2104:                           block = visibleRect.y - newFirstR.y;
2105:                       }
2106:                   }
2107:               }
2108:           }
2109:       }
2110:     else if (orientation == SwingConstants.HORIZONTAL
2111:              && getLayoutOrientation() != VERTICAL)
2112:       {
2113:         // Default block increment. Special cases are handled below for
2114:         // better usability.
2115:         block = visibleRect.width;
2116:         if (direction > 0)
2117:           {
2118:             // Scroll right.
2119:             Point p = new Point(visibleRect.x + visibleRect.width + 1,
2120:                                 visibleRect.y);
2121:             int last = locationToIndex(p);
2122:             if (last != -1)
2123:               {
2124:                 Rectangle lastR = getCellBounds(last, last);
2125:                 if (lastR != null)
2126:                   {
2127:                     block = lastR.x  - visibleRect.x;
2128:                     if (block < 0)
2129:                       block += lastR.width;
2130:                     else if (block == 0 && last < getModel().getSize() - 1)
2131:                       block = lastR.width;
2132:                   }
2133:               }
2134:           }
2135:         else
2136:           {
2137:             // Scroll left.
2138:             Point p = new Point(visibleRect.x - visibleRect.width,
2139:                                 visibleRect.y);
2140:             int first = locationToIndex(p);
2141:             if (first != -1)
2142:               {
2143:                 Rectangle firstR = getCellBounds(first, first);
2144:                 if (firstR != null)
2145:                   {
2146:                     if (firstR.x < visibleRect.x - visibleRect.width)
2147:                       {
2148:                         if (firstR.x + firstR.width > visibleRect.x)
2149:                           block = visibleRect.x - firstR.x;
2150:                         else
2151:                           block = visibleRect.x - firstR.x - firstR.width;
2152:                       }
2153:                     else
2154:                       block = visibleRect.x - firstR.x;
2155:                   }
2156:               }
2157:           }
2158:       }
2159: 
2160:     return block;
2161:   }
2162: 
2163:   /**
2164:    * Gets the value of the <code>scrollableTracksViewportWidth</code> property.
2165:    *
2166:    * @return <code>true</code> if the viewport is larger (horizontally)
2167:    * than the list and the list should be expanded to fit the viewport;
2168:    * <code>false</code> if the viewport is smaller than the list and the
2169:    * list should scroll (horizontally) within the viewport
2170:    */
2171:   public boolean getScrollableTracksViewportWidth()
2172:   {
2173:     Component parent = getParent();
2174:     boolean retVal = false;
2175:     if (parent instanceof JViewport)
2176:       {
2177:         JViewport viewport = (JViewport) parent;
2178:         Dimension pref = getPreferredSize();
2179:         if (viewport.getSize().width > pref.width)
2180:           retVal = true;
2181:         if ((getLayoutOrientation() == HORIZONTAL_WRAP)
2182:             && (getVisibleRowCount() <= 0))
2183:           retVal = true;
2184:       }
2185:     return retVal;
2186:   }
2187: 
2188:   /**
2189:    * Gets the value of the </code>scrollableTracksViewportWidth</code> property.
2190:    *
2191:    * @return <code>true</code> if the viewport is larger (vertically)
2192:    * than the list and the list should be expanded to fit the viewport;
2193:    * <code>false</code> if the viewport is smaller than the list and the
2194:    * list should scroll (vertically) within the viewport
2195:    */
2196:   public boolean getScrollableTracksViewportHeight()
2197:   {
2198:     Component parent = getParent();
2199:     boolean retVal = false;
2200:     if (parent instanceof JViewport)
2201:       {
2202:         JViewport viewport = (JViewport) parent;
2203:         Dimension pref = getPreferredSize();
2204:         if (viewport.getSize().height > pref.height)
2205:           retVal = true;
2206:         if ((getLayoutOrientation() == VERTICAL_WRAP)
2207:             && (getVisibleRowCount() <= 0))
2208:           retVal = true;
2209:       }
2210:     return retVal;
2211:   }
2212: 
2213:   /**
2214:    * Returns the index of the anchor item in the current selection, or
2215:    * <code>-1</code> if there is no anchor item.
2216:    *
2217:    * @return The item index.
2218:    */
2219:   public int getAnchorSelectionIndex()
2220:   {
2221:     return selectionModel.getAnchorSelectionIndex();
2222:   }
2223: 
2224:   /**
2225:    * Returns the index of the lead item in the current selection, or
2226:    * <code>-1</code> if there is no lead item.
2227:    *
2228:    * @return The item index.
2229:    */
2230:   public int getLeadSelectionIndex()
2231:   {
2232:     return selectionModel.getLeadSelectionIndex();
2233:   }
2234: 
2235:   /**
2236:    * Returns the lowest item index in the current selection, or <code>-1</code>
2237:    * if there is no selection.
2238:    *
2239:    * @return The index.
2240:    *
2241:    * @see #getMaxSelectionIndex()
2242:    */
2243:   public int getMinSelectionIndex()
2244:   {
2245:     return selectionModel.getMinSelectionIndex();
2246:   }
2247: 
2248:   /**
2249:    * Returns the highest item index in the current selection, or
2250:    * <code>-1</code> if there is no selection.
2251:    *
2252:    * @return The index.
2253:    *
2254:    * @see #getMinSelectionIndex()
2255:    */
2256:   public int getMaxSelectionIndex()
2257:   {
2258:     return selectionModel.getMaxSelectionIndex();
2259:   }
2260: 
2261:   /**
2262:    * Clears the current selection.
2263:    */
2264:   public void clearSelection()
2265:   {
2266:     selectionModel.clearSelection();
2267:   }
2268: 
2269:   /**
2270:    * Sets the current selection to the items in the specified range (inclusive).
2271:    * Note that <code>anchor</code> can be less than, equal to, or greater than
2272:    * <code>lead</code>.
2273:    *
2274:    * @param anchor  the index of the anchor item.
2275:    * @param lead  the index of the anchor item.
2276:    */
2277:   public void setSelectionInterval(int anchor, int lead)
2278:   {
2279:     selectionModel.setSelectionInterval(anchor, lead);
2280:   }
2281: 
2282:   /**
2283:    * Adds the specified interval to the current selection.  Note that
2284:    * <code>anchor</code> can be less than, equal to, or greater than
2285:    * <code>lead</code>.
2286:    *
2287:    * @param anchor  the index of the anchor item.
2288:    * @param lead  the index of the lead item.
2289:    */
2290:   public void addSelectionInterval(int anchor, int lead)
2291:   {
2292:     selectionModel.addSelectionInterval(anchor, lead);
2293:   }
2294: 
2295:   /**
2296:    * Removes the specified interval from the current selection.  Note that
2297:    * <code>index0</code> can be less than, equal to, or greater than
2298:    * <code>index1</code>.
2299:    *
2300:    * @param index0  an index for one end of the range.
2301:    * @param index1  an index for the other end of the range.
2302:    */
2303:   public void removeSelectionInterval(int index0, int index1)
2304:   {
2305:     selectionModel.removeSelectionInterval(index0, index1);
2306:   }
2307: 
2308:   /**
2309:    * Returns the <code>valueIsAdjusting</code> flag from the list's selection
2310:    * model.
2311:    *
2312:    * @return the value
2313:    */
2314:   public boolean getValueIsAdjusting()
2315:   {
2316:     return selectionModel.getValueIsAdjusting();
2317:   }
2318: 
2319:   /**
2320:    * Sets the <code>valueIsAdjusting</code> flag in the list's selection
2321:    * model.
2322:    *
2323:    * @param isAdjusting the new value
2324:    */
2325:   public void setValueIsAdjusting(boolean isAdjusting)
2326:   {
2327:     selectionModel.setValueIsAdjusting(isAdjusting);
2328:   }
2329: 
2330:   /**
2331:    * Return the value of the <code>dragEnabled</code> property.
2332:    *
2333:    * @return the value
2334:    *
2335:    * @since 1.4
2336:    */
2337:   public boolean getDragEnabled()
2338:   {
2339:     return dragEnabled;
2340:   }
2341: 
2342:   /**
2343:    * Set the <code>dragEnabled</code> property.
2344:    *
2345:    * @param enabled new value
2346:    *
2347:    * @since 1.4
2348:    */
2349:   public void setDragEnabled(boolean enabled)
2350:   {
2351:     dragEnabled = enabled;
2352:   }
2353: 
2354:   /**
2355:    * Returns the layout orientation, which will be one of {@link #VERTICAL},
2356:    * {@link #VERTICAL_WRAP} and {@link #HORIZONTAL_WRAP}.  The default value
2357:    * is {@link #VERTICAL}.
2358:    *
2359:    * @return the orientation.
2360:    *
2361:    * @see #setLayoutOrientation(int)
2362:    * @since 1.4
2363:    */
2364:   public int getLayoutOrientation()
2365:   {
2366:     return layoutOrientation;
2367:   }
2368: 
2369:   /**
2370:    * Sets the layout orientation (this is a bound property with the name
2371:    * 'layoutOrientation').  Valid orientations are {@link #VERTICAL},
2372:    * {@link #VERTICAL_WRAP} and {@link #HORIZONTAL_WRAP}.
2373:    *
2374:    * @param orientation the orientation.
2375:    *
2376:    * @throws IllegalArgumentException if <code>orientation</code> is not one
2377:    *     of the specified values.
2378:    * @since 1.4
2379:    * @see #getLayoutOrientation()
2380:    */
2381:   public void setLayoutOrientation(int orientation)
2382:   {
2383:     if (orientation < JList.VERTICAL || orientation > JList.HORIZONTAL_WRAP)
2384:       throw new IllegalArgumentException();
2385:     if (layoutOrientation == orientation)
2386:       return;
2387: 
2388:     int old = layoutOrientation;
2389:     layoutOrientation = orientation;
2390:     firePropertyChange("layoutOrientation", old, orientation);
2391:   }
2392: 
2393:   /**
2394:    * Returns the bounds of the rectangle that encloses both list cells
2395:    * with index0 and index1.
2396:    *
2397:    * @param index0 the index of the first cell
2398:    * @param index1 the index of the second cell
2399:    *
2400:    * @return  the bounds of the rectangle that encloses both list cells
2401:    *     with index0 and index1, <code>null</code> if one of the indices is
2402:    *     not valid
2403:    */
2404:   public Rectangle getCellBounds(int index0, int index1)
2405:   {
2406:     ListUI ui = getUI();
2407:     Rectangle bounds = null;
2408:     if (ui != null)
2409:       {
2410:         bounds = ui.getCellBounds(this, index0, index1);
2411:       }
2412:     // When the UI is null, this method also returns null in the RI.
2413:     return bounds;
2414:   }
2415: 
2416:   /**
2417:    * Returns the index of the next list element (beginning at
2418:    * <code>startIndex</code> and moving in the specified direction through the
2419:    * list, looping around if necessary) that starts with <code>prefix</code>
2420:    * (ignoring case).
2421:    *
2422:    * @param prefix the prefix to search for in the cell values
2423:    * @param startIndex the index where to start searching from
2424:    * @param direction the search direction, either {@link Position.Bias#Forward}
2425:    *     or {@link Position.Bias#Backward} (<code>null</code> is interpreted
2426:    *     as {@link Position.Bias#Backward}.
2427:    *
2428:    * @return the index of the found element or -1 if no such element has
2429:    *     been found
2430:    *
2431:    * @throws IllegalArgumentException if prefix is <code>null</code> or
2432:    *     startIndex is not valid
2433:    *
2434:    * @since 1.4
2435:    */
2436:   public int getNextMatch(String prefix, int startIndex,
2437:                           Position.Bias direction)
2438:   {
2439:     if (prefix == null)
2440:       throw new IllegalArgumentException("The argument 'prefix' must not be"
2441:                                          + " null.");
2442:     if (startIndex < 0)
2443:       throw new IllegalArgumentException("The argument 'startIndex' must not"
2444:                                          + " be less than zero.");
2445: 
2446:     int size = model.getSize();
2447:     if (startIndex >= model.getSize())
2448:       throw new IllegalArgumentException("The argument 'startIndex' must not"
2449:                                          + " be greater than the number of"
2450:                                          + " elements in the ListModel.");
2451: 
2452:     int result = -1;
2453:     int current = startIndex;
2454:     int delta = -1;
2455:     int itemCount = model.getSize();
2456:     boolean finished = false;
2457:     prefix = prefix.toUpperCase();
2458: 
2459:     if (direction == Position.Bias.Forward)
2460:       delta = 1;
2461:     while (!finished)
2462:       {
2463:         String itemStr = model.getElementAt(current).toString().toUpperCase();
2464:         if (itemStr.startsWith(prefix))
2465:           return current;
2466:         current = (current + delta);
2467:         if (current == -1)
2468:           current += itemCount;
2469:         else
2470:           current = current % itemCount;
2471:         finished = current == startIndex;
2472:       }
2473:     return result;
2474:   }
2475: 
2476:   /**
2477:    * Returns a string describing the attributes for the <code>JList</code>
2478:    * component, for use in debugging.  The return value is guaranteed to be
2479:    * non-<code>null</code>, but the format of the string may vary between
2480:    * implementations.
2481:    *
2482:    * @return A string describing the attributes of the <code>JList</code>.
2483:    */
2484:   protected String paramString()
2485:   {
2486:     CPStringBuilder sb = new CPStringBuilder(super.paramString());
2487:     sb.append(",fixedCellHeight=").append(getFixedCellHeight());
2488:     sb.append(",fixedCellWidth=").append(getFixedCellWidth());
2489:     sb.append(",selectionBackground=");
2490:     if (getSelectionBackground() != null)
2491:       sb.append(getSelectionBackground());
2492:     sb.append(",selectionForeground=");
2493:     if (getSelectionForeground() != null)
2494:       sb.append(getSelectionForeground());
2495:     sb.append(",visibleRowCount=").append(getVisibleRowCount());
2496:     sb.append(",layoutOrientation=").append(getLayoutOrientation());
2497:     return sb.toString();
2498:   }
2499: }