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