|  | /* JList.java -- | 
|  | Copyright (C) 2002, 2003, 2004, 2005, 2006,  Free Software Foundation, Inc. | 
|  |  | 
|  | This file is part of GNU Classpath. | 
|  |  | 
|  | GNU Classpath is free software; you can redistribute it and/or modify | 
|  | it under the terms of the GNU General Public License as published by | 
|  | the Free Software Foundation; either version 2, or (at your option) | 
|  | any later version. | 
|  |  | 
|  | GNU Classpath is distributed in the hope that it will be useful, but | 
|  | WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | General Public License for more details. | 
|  |  | 
|  | You should have received a copy of the GNU General Public License | 
|  | along with GNU Classpath; see the file COPYING.  If not, write to the | 
|  | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | 
|  | 02110-1301 USA. | 
|  |  | 
|  | Linking this library statically or dynamically with other modules is | 
|  | making a combined work based on this library.  Thus, the terms and | 
|  | conditions of the GNU General Public License cover the whole | 
|  | combination. | 
|  |  | 
|  | As a special exception, the copyright holders of this library give you | 
|  | permission to link this library with independent modules to produce an | 
|  | executable, regardless of the license terms of these independent | 
|  | modules, and to copy and distribute the resulting executable under | 
|  | terms of your choice, provided that you also meet, for each linked | 
|  | independent module, the terms and conditions of the license of that | 
|  | module.  An independent module is a module which is not derived from | 
|  | or based on this library.  If you modify this library, you may extend | 
|  | this exception to your version of the library, but you are not | 
|  | obligated to do so.  If you do not wish to do so, delete this | 
|  | exception statement from your version. */ | 
|  |  | 
|  |  | 
|  | package javax.swing; | 
|  |  | 
|  | import java.awt.Color; | 
|  | import java.awt.Component; | 
|  | import java.awt.ComponentOrientation; | 
|  | import java.awt.Cursor; | 
|  | import java.awt.Dimension; | 
|  | import java.awt.Font; | 
|  | import java.awt.FontMetrics; | 
|  | import java.awt.Point; | 
|  | import java.awt.Rectangle; | 
|  | import java.awt.event.FocusListener; | 
|  | import java.beans.PropertyChangeEvent; | 
|  | import java.beans.PropertyChangeListener; | 
|  | import java.util.Locale; | 
|  | import java.util.Vector; | 
|  |  | 
|  | import javax.accessibility.Accessible; | 
|  | import javax.accessibility.AccessibleComponent; | 
|  | import javax.accessibility.AccessibleContext; | 
|  | import javax.accessibility.AccessibleRole; | 
|  | import javax.accessibility.AccessibleSelection; | 
|  | import javax.accessibility.AccessibleState; | 
|  | import javax.accessibility.AccessibleStateSet; | 
|  | import javax.swing.event.ListDataEvent; | 
|  | import javax.swing.event.ListDataListener; | 
|  | import javax.swing.event.ListSelectionEvent; | 
|  | import javax.swing.event.ListSelectionListener; | 
|  | import javax.swing.plaf.ListUI; | 
|  | import javax.swing.text.Position; | 
|  |  | 
|  | /** | 
|  | * <p>This class is a facade over three separate objects: {@link | 
|  | * javax.swing.ListModel}, {@link javax.swing.ListSelectionModel} and | 
|  | * {@link javax.swing.plaf.ListUI}. The facade represents a unified "list" | 
|  | * concept, with independently replacable (possibly client-provided) models | 
|  | * for its contents and its current selection. In addition, each element in | 
|  | * the list is rendered via a strategy class {@link | 
|  | * javax.swing.ListCellRenderer}.</p> | 
|  | * | 
|  | * <p>Lists have many properties, some of which are stored in this class | 
|  | * while others are delegated to the list's model or selection. The | 
|  | * following properties are available:</p> | 
|  | * | 
|  | * <table> | 
|  | * <tr><th>Property                       </th><th>Stored in</th><th>Bound?</th></tr> | 
|  | * <tr><td>accessibleContext              </td><td>list     </td><td>no    </td></tr> | 
|  | * <tr><td>anchorSelectionIndex           </td><td>selection</td><td>no    </td></tr> | 
|  | * <tr><td>cellRenderer                   </td><td>list     </td><td>yes   </td></tr> | 
|  | * <tr><td>dragEnabled                    </td><td>list     </td><td>no    </td></tr> | 
|  | * <tr><td>firstVisibleIndex              </td><td>list     </td><td>no    </td></tr> | 
|  | * <tr><td>fixedCellHeight                </td><td>list     </td><td>yes   </td></tr> | 
|  | * <tr><td>fixedCellWidth                 </td><td>list     </td><td>yes   </td></tr> | 
|  | * <tr><td>lastVisibleIndex               </td><td>list     </td><td>no    </td></tr> | 
|  | * <tr><td>layoutOrientation              </td><td>list     </td><td>yes   </td></tr> | 
|  | * <tr><td>leadSelectionIndex             </td><td>selection</td><td>no    </td></tr> | 
|  | * <tr><td>maxSelectionIndex              </td><td>selection</td><td>no    </td></tr> | 
|  | * <tr><td>minSelectionIndex              </td><td>selection</td><td>no    </td></tr> | 
|  | * <tr><td>model                          </td><td>list     </td><td>yes   </td></tr> | 
|  | * <tr><td>opaque                         </td><td>list     </td><td>no    </td></tr> | 
|  | * <tr><td>preferredScrollableViewportSize</td><td>list     </td><td>no    </td></tr> | 
|  | * <tr><td>prototypeCellValue             </td><td>list     </td><td>yes   </td></tr> | 
|  | * <tr><td>scrollableTracksViewportHeight </td><td>list     </td><td>no    </td></tr> | 
|  | * <tr><td>scrollableTracksViewportWidth  </td><td>list     </td><td>no    </td></tr> | 
|  | * <tr><td>selectedIndex                  </td><td>selection</td><td>no    </td></tr> | 
|  | * <tr><td>selectedIndices                </td><td>selection</td><td>no    </td></tr> | 
|  | * <tr><td>selectedValue                  </td><td>model    </td><td>no    </td></tr> | 
|  | * <tr><td>selectedValues                 </td><td>model    </td><td>no    </td></tr> | 
|  | * <tr><td>selectionBackground            </td><td>list     </td><td>yes   </td></tr> | 
|  | * <tr><td>selectionEmpty                 </td><td>selection</td><td>no    </td></tr> | 
|  | * <tr><td>selectionForeground            </td><td>list     </td><td>yes   </td></tr> | 
|  | * <tr><td>selectionMode                  </td><td>selection</td><td>no    </td></tr> | 
|  | * <tr><td>selectionModel                 </td><td>list     </td><td>yes   </td></tr> | 
|  | * <tr><td>UI                             </td><td>list     </td><td>yes   </td></tr> | 
|  | * <tr><td>UIClassID                      </td><td>list     </td><td>no    </td></tr> | 
|  | * <tr><td>valueIsAdjusting               </td><td>list     </td><td>no    </td></tr> | 
|  | * <tr><td>visibleRowCount                </td><td>list     </td><td>no    </td></tr> | 
|  | * </table> | 
|  | * | 
|  | * @author Graydon Hoare (graydon@redhat.com) | 
|  | */ | 
|  |  | 
|  | public class JList extends JComponent implements Accessible, Scrollable | 
|  | { | 
|  |  | 
|  | /** | 
|  | * Provides accessibility support for <code>JList</code>. | 
|  | */ | 
|  | protected class AccessibleJList extends AccessibleJComponent | 
|  | implements AccessibleSelection, PropertyChangeListener, | 
|  | ListSelectionListener, ListDataListener | 
|  | { | 
|  |  | 
|  | /** | 
|  | * Provides accessibility support for list elements in <code>JList</code>s. | 
|  | */ | 
|  | protected class AccessibleJListChild extends AccessibleContext | 
|  | implements Accessible, AccessibleComponent | 
|  | { | 
|  |  | 
|  | /** | 
|  | * The parent list. | 
|  | */ | 
|  | JList parent; | 
|  |  | 
|  | /** | 
|  | * The index in the list for that child. | 
|  | */ | 
|  | int listIndex; | 
|  |  | 
|  | /** | 
|  | * The cursor for this list child. | 
|  | */ | 
|  | // TODO: Testcases show that this class somehow stores state about the | 
|  | // cursor. I cannot make up though how that could affect | 
|  | // the actual list. | 
|  | Cursor cursor = Cursor.getDefaultCursor(); | 
|  |  | 
|  | /** | 
|  | * Creates a new instance of <code>AccessibleJListChild</code>. | 
|  | * | 
|  | * @param list the list of which this is an accessible child | 
|  | * @param index the list index for this child | 
|  | */ | 
|  | public AccessibleJListChild(JList list, int index) | 
|  | { | 
|  | parent = list; | 
|  | listIndex = index; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the accessible context of this object. Returns | 
|  | * <code>this</code> since <code>AccessibleJListChild</code>s are their | 
|  | * own accessible contexts. | 
|  | * | 
|  | * @return the accessible context of this object, <code>this</code> | 
|  | */ | 
|  | public AccessibleContext getAccessibleContext() | 
|  | { | 
|  | return this; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the background color for this list child. This returns the | 
|  | * background of the <code>JList</code> itself since the background | 
|  | * cannot be set on list children individually | 
|  | * | 
|  | * @return the background color for this list child | 
|  | */ | 
|  | public Color getBackground() | 
|  | { | 
|  | return parent.getBackground(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Calling this method has no effect, since the background color cannot be | 
|  | * set on list children individually. | 
|  | * | 
|  | * @param color not used here. | 
|  | */ | 
|  | public void setBackground(Color color) | 
|  | { | 
|  | // Calling this method has no effect, since the background color cannot | 
|  | // be set on list children individually. | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the foreground color for this list child. This returns the | 
|  | * background of the <code>JList</code> itself since the foreground | 
|  | * cannot be set on list children individually. | 
|  | * | 
|  | * @return the background color for this list child | 
|  | */ | 
|  | public Color getForeground() | 
|  | { | 
|  | return parent.getForeground(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Calling this method has no effect, since the foreground color cannot be | 
|  | * set on list children individually. | 
|  | * | 
|  | * @param color not used here. | 
|  | */ | 
|  | public void setForeground(Color color) | 
|  | { | 
|  | // Calling this method has no effect, since the foreground color cannot | 
|  | // be set on list children individually. | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the cursor for this list child. | 
|  | * | 
|  | * @return the cursor for this list child | 
|  | */ | 
|  | public Cursor getCursor() | 
|  | { | 
|  | // TODO: Testcases show that this method returns the cursor that has | 
|  | // been set by setCursor. I cannot make up though how that could affect | 
|  | // the actual list. | 
|  | return cursor; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Sets the cursor for this list child. | 
|  | */ | 
|  | public void setCursor(Cursor cursor) | 
|  | { | 
|  | this.cursor = cursor; | 
|  | // TODO: Testcases show that this method returns the cursor that has | 
|  | // been set by setCursor. I cannot make up though how that could affect | 
|  | // the actual list. | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the font of the <code>JList</code> since it is not possible to | 
|  | * set fonts for list children individually. | 
|  | * | 
|  | * @return the font of the <code>JList</code> | 
|  | */ | 
|  | public Font getFont() | 
|  | { | 
|  | return parent.getFont(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Does nothing since it is not possible to set the font on list children | 
|  | * individually. | 
|  | * | 
|  | * @param font not used here | 
|  | */ | 
|  | public void setFont(Font font) | 
|  | { | 
|  | // Does nothing since it is not possible to set the font on list | 
|  | // children individually. | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the font metrics for the specified font. This method forwards | 
|  | * to the parent <code>JList</code>. | 
|  | * | 
|  | * @param font the font for which the font metrics is queried | 
|  | * | 
|  | * @return the font metrics for the specified font | 
|  | */ | 
|  | public FontMetrics getFontMetrics(Font font) | 
|  | { | 
|  | return parent.getFontMetrics(font); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns <code>true</code> if the parent <code>JList</code> is enabled, | 
|  | * <code>false</code> otherwise. The list children cannot have an enabled | 
|  | * flag set individually. | 
|  | * | 
|  | * @return <code>true</code> if the parent <code>JList</code> is enabled, | 
|  | *         <code>false</code> otherwise | 
|  | */ | 
|  | public boolean isEnabled() | 
|  | { | 
|  | return parent.isEnabled(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Does nothing since the enabled flag cannot be set for list children | 
|  | * individually. | 
|  | * | 
|  | * @param b not used here | 
|  | */ | 
|  | public void setEnabled(boolean b) | 
|  | { | 
|  | // Does nothing since the enabled flag cannot be set for list children | 
|  | // individually. | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns <code>true</code> if this list child is visible, | 
|  | * <code>false</code> otherwise. The value of this property depends | 
|  | * on {@link JList#getFirstVisibleIndex()} and | 
|  | * {@link JList#getLastVisibleIndex()}. | 
|  | * | 
|  | * @return <code>true</code> if this list child is visible, | 
|  | *         <code>false</code> otherwise | 
|  | */ | 
|  | public boolean isVisible() | 
|  | { | 
|  | return listIndex >= parent.getFirstVisibleIndex() | 
|  | && listIndex <= parent.getLastVisibleIndex(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * The value of the visible property cannot be modified, so this method | 
|  | * does nothing. | 
|  | * | 
|  | * @param b not used here | 
|  | */ | 
|  | public void setVisible(boolean b) | 
|  | { | 
|  | // The value of the visible property cannot be modified, so this method | 
|  | // does nothing. | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns <code>true</code> if this list child is currently showing on | 
|  | * screen and <code>false</code> otherwise. The list child is showing if | 
|  | * it is visible and if it's parent JList is currently showing. | 
|  | * | 
|  | * @return <code>true</code> if this list child is currently showing on | 
|  | *         screen and <code>false</code> otherwise | 
|  | */ | 
|  | public boolean isShowing() | 
|  | { | 
|  | return isVisible() && parent.isShowing(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns <code>true</code> if this list child covers the screen location | 
|  | * <code>point</code> (relative to the <code>JList</code> coordinate | 
|  | * system, <code>false</code> otherwise. | 
|  | * | 
|  | * @return <code>true</code> if this list child covers the screen location | 
|  | *         <code>point</code> , <code>false</code> otherwise | 
|  | */ | 
|  | public boolean contains(Point point) | 
|  | { | 
|  | return getBounds().contains(point); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the absolute screen location of this list child. | 
|  | * | 
|  | * @return the absolute screen location of this list child | 
|  | */ | 
|  | public Point getLocationOnScreen() | 
|  | { | 
|  | Point loc = getLocation(); | 
|  | SwingUtilities.convertPointToScreen(loc, parent); | 
|  | return loc; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the screen location of this list child relative to it's parent. | 
|  | * | 
|  | * @return the location of this list child relative to it's parent | 
|  | * | 
|  | * @see JList#indexToLocation(int) | 
|  | */ | 
|  | public Point getLocation() | 
|  | { | 
|  | return parent.indexToLocation(listIndex); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Does nothing since the screen location cannot be set on list children | 
|  | * explictitly. | 
|  | * | 
|  | * @param point not used here | 
|  | */ | 
|  | public void setLocation(Point point) | 
|  | { | 
|  | // Does nothing since the screen location cannot be set on list children | 
|  | // explictitly. | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the bounds of this list child. | 
|  | * | 
|  | * @return the bounds of this list child | 
|  | * | 
|  | * @see JList#getCellBounds(int, int) | 
|  | */ | 
|  | public Rectangle getBounds() | 
|  | { | 
|  | return parent.getCellBounds(listIndex, listIndex); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Does nothing since the bounds cannot be set on list children | 
|  | * individually. | 
|  | * | 
|  | * @param rectangle not used here | 
|  | */ | 
|  | public void setBounds(Rectangle rectangle) | 
|  | { | 
|  | // Does nothing since the bounds cannot be set on list children | 
|  | // individually. | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the size of this list child. | 
|  | * | 
|  | * @return the size of this list child | 
|  | */ | 
|  | public Dimension getSize() | 
|  | { | 
|  | Rectangle b = getBounds(); | 
|  | return b.getSize(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Does nothing since the size cannot be set on list children | 
|  | * individually. | 
|  | * | 
|  | * @param dimension not used here | 
|  | */ | 
|  | public void setSize(Dimension dimension) | 
|  | { | 
|  | // Does nothing since the size cannot be set on list children | 
|  | // individually. | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns <code>null</code> because list children do not have children | 
|  | * themselves | 
|  | * | 
|  | * @return <code>null</code> | 
|  | */ | 
|  | public Accessible getAccessibleAt(Point point) | 
|  | { | 
|  | return null; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns <code>true</code> since list children are focus traversable. | 
|  | * | 
|  | * @return true | 
|  | */ | 
|  | public boolean isFocusTraversable() | 
|  | { | 
|  | // TODO: Is this 100% ok? | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Requests focus on the parent list. List children cannot request focus | 
|  | * individually. | 
|  | */ | 
|  | public void requestFocus() | 
|  | { | 
|  | // TODO: Is this 100% ok? | 
|  | parent.requestFocus(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Adds a focus listener to the parent list. List children do not have | 
|  | * their own focus management. | 
|  | * | 
|  | * @param listener the focus listener to add | 
|  | */ | 
|  | public void addFocusListener(FocusListener listener) | 
|  | { | 
|  | // TODO: Is this 100% ok? | 
|  | parent.addFocusListener(listener); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Removes a focus listener from the parent list. List children do not | 
|  | * have their own focus management. | 
|  | * | 
|  | * @param listener the focus listener to remove | 
|  | */ | 
|  | public void removeFocusListener(FocusListener listener) | 
|  | { | 
|  | // TODO: Is this 100% | 
|  | parent.removeFocusListener(listener); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the accessible role of this list item, which is | 
|  | * {@link AccessibleRole#LABEL}. | 
|  | * | 
|  | * @return {@link AccessibleRole#LABEL} | 
|  | */ | 
|  | public AccessibleRole getAccessibleRole() | 
|  | { | 
|  | return AccessibleRole.LABEL; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the accessible state set of this list item. | 
|  | * | 
|  | * @return the accessible state set of this list item | 
|  | */ | 
|  | public AccessibleStateSet getAccessibleStateSet() | 
|  | { | 
|  | AccessibleStateSet states = new AccessibleStateSet(); | 
|  | if (isVisible()) | 
|  | states.add(AccessibleState.VISIBLE); | 
|  | if (isShowing()) | 
|  | states.add(AccessibleState.SHOWING); | 
|  | if (isFocusTraversable()) | 
|  | states.add(AccessibleState.FOCUSABLE); | 
|  | // TODO: How should the active state be handled? The API docs | 
|  | // suggest that this state is set on the activated list child, | 
|  | // that is the one that is drawn with a box. However, I don't know how | 
|  | // to implement this. | 
|  |  | 
|  | // TODO: We set the selectable state here because list children are | 
|  | // selectable. Is there a way to disable single children? | 
|  | if (parent.isEnabled()) | 
|  | states.add(AccessibleState.SELECTABLE); | 
|  |  | 
|  | if (parent.isSelectedIndex(listIndex)) | 
|  | states.add(AccessibleState.SELECTED); | 
|  |  | 
|  | // TODO: Handle more states here? | 
|  | return states; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the index of this list child within it's parent list. | 
|  | * | 
|  | * @return the index of this list child within it's parent list | 
|  | */ | 
|  | public int getAccessibleIndexInParent() | 
|  | { | 
|  | return listIndex; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns <code>0</code> since list children don't have children | 
|  | * themselves. | 
|  | * | 
|  | * @return <code>0</code> | 
|  | */ | 
|  | public int getAccessibleChildrenCount() | 
|  | { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns <code>null</code> since list children don't have children | 
|  | * themselves. | 
|  | * | 
|  | * @return <code>null</code> | 
|  | */ | 
|  | public Accessible getAccessibleChild(int i) | 
|  | { | 
|  | return null; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the locale of this component. This call is forwarded to the | 
|  | * parent list since list children don't have a separate locale setting. | 
|  | * | 
|  | * @return the locale of this component | 
|  | */ | 
|  | public Locale getLocale() | 
|  | { | 
|  | return parent.getLocale(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * This method does | 
|  | * nothing, list children are transient accessible objects which means | 
|  | * that they don't fire property change events. | 
|  | * | 
|  | * @param l not used here | 
|  | */ | 
|  | public void addPropertyChangeListener(PropertyChangeListener l) | 
|  | { | 
|  | // Do nothing here. | 
|  | } | 
|  |  | 
|  | /** | 
|  | * This method does | 
|  | * nothing, list children are transient accessible objects which means | 
|  | * that they don't fire property change events. | 
|  | * | 
|  | * @param l not used here | 
|  | */ | 
|  | public void removePropertyChangeListener(PropertyChangeListener l) | 
|  | { | 
|  | // Do nothing here. | 
|  | } | 
|  |  | 
|  | // TODO: Implement the remaining methods of this class. | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Create a new AccessibleJList. | 
|  | */ | 
|  | public AccessibleJList() | 
|  | { | 
|  | // Nothing to do here. | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the number of selected accessible children. | 
|  | * | 
|  | * @return the number of selected accessible children | 
|  | */ | 
|  | public int getAccessibleSelectionCount() | 
|  | { | 
|  | return getSelectedIndices().length; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the n-th selected accessible child. | 
|  | * | 
|  | * @param n the index of the selected child to return | 
|  | * | 
|  | * @return the n-th selected accessible child | 
|  | */ | 
|  | public Accessible getAccessibleSelection(int n) | 
|  | { | 
|  | return new AccessibleJListChild(JList.this, getSelectedIndices()[n]); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns <code>true</code> if the n-th child is selected, | 
|  | * <code>false</code> otherwise. | 
|  | * | 
|  | * @param n the index of the child of which the selected state is queried | 
|  | * | 
|  | * @return <code>true</code> if the n-th child is selected, | 
|  | *         <code>false</code> otherwise | 
|  | */ | 
|  | public boolean isAccessibleChildSelected(int n) | 
|  | { | 
|  | return isSelectedIndex(n); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Adds the accessible item with the specified index to the selected items. | 
|  | * If multiple selections are supported, the item is added to the selection, | 
|  | * otherwise the item replaces the current selection. | 
|  | * | 
|  | * @param i the index of the item to add to the selection | 
|  | */ | 
|  | public void addAccessibleSelection(int i) | 
|  | { | 
|  | addSelectionInterval(i, i); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Removes the accessible item with the specified index to the selection. | 
|  | * | 
|  | * @param i the index of the item to be removed from the selection | 
|  | */ | 
|  | public void removeAccessibleSelection(int i) | 
|  | { | 
|  | removeSelectionInterval(i, i); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Remove all selection items from the selection. | 
|  | */ | 
|  | public void clearAccessibleSelection() | 
|  | { | 
|  | clearSelection(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Selects all items if multiple selections are supported. | 
|  | * Otherwise do nothing. | 
|  | */ | 
|  | public void selectAllAccessibleSelection() | 
|  | { | 
|  | addSelectionInterval(0, getModel().getSize()); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Receices notification when the list selection is changed. This method | 
|  | * fires two property change events, the first with | 
|  | * {@link AccessibleContext#ACCESSIBLE_VISIBLE_DATA_PROPERTY} and the second | 
|  | * with {@link AccessibleContext#ACCESSIBLE_SELECTION_PROPERTY}. | 
|  | * | 
|  | * @param event the list selection event | 
|  | */ | 
|  | public void valueChanged(ListSelectionEvent event) | 
|  | { | 
|  | firePropertyChange(ACCESSIBLE_VISIBLE_DATA_PROPERTY, Boolean.FALSE, | 
|  | Boolean.TRUE); | 
|  | firePropertyChange(ACCESSIBLE_SELECTION_PROPERTY, Boolean.FALSE, | 
|  | Boolean.TRUE); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Receives notification when items have changed in the | 
|  | * <code>JList</code>. This method fires a property change event with | 
|  | * {@link AccessibleContext#ACCESSIBLE_VISIBLE_DATA_PROPERTY}. | 
|  | * | 
|  | * @param event the list data event | 
|  | */ | 
|  | public void contentsChanged(ListDataEvent event) | 
|  | { | 
|  | firePropertyChange(ACCESSIBLE_VISIBLE_DATA_PROPERTY, Boolean.FALSE, | 
|  | Boolean.TRUE); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Receives notification when items are inserted into the | 
|  | * <code>JList</code>. This method fires a property change event with | 
|  | * {@link AccessibleContext#ACCESSIBLE_VISIBLE_DATA_PROPERTY}. | 
|  | * | 
|  | * @param event the list data event | 
|  | */ | 
|  | public void intervalAdded(ListDataEvent event) | 
|  | { | 
|  | firePropertyChange(ACCESSIBLE_VISIBLE_DATA_PROPERTY, Boolean.FALSE, | 
|  | Boolean.TRUE); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Receives notification when items are removed from the | 
|  | * <code>JList</code>. This method fires a property change event with | 
|  | * {@link AccessibleContext#ACCESSIBLE_VISIBLE_DATA_PROPERTY}. | 
|  | * | 
|  | * @param event the list data event | 
|  | */ | 
|  | public void intervalRemoved(ListDataEvent event) | 
|  | { | 
|  | firePropertyChange(ACCESSIBLE_VISIBLE_DATA_PROPERTY, Boolean.FALSE, | 
|  | Boolean.TRUE); | 
|  | } | 
|  |  | 
|  |  | 
|  | /** | 
|  | * Receives notification about changes of the <code>JList</code>'s | 
|  | * properties. This is used to re-register this object as listener to | 
|  | * the data model and selection model when the data model or selection model | 
|  | * changes. | 
|  | * | 
|  | * @param e the property change event | 
|  | */ | 
|  | public void propertyChange(PropertyChangeEvent e) | 
|  | { | 
|  | String propertyName = e.getPropertyName(); | 
|  | if (propertyName.equals("model")) | 
|  | { | 
|  | ListModel oldModel = (ListModel) e.getOldValue(); | 
|  | oldModel.removeListDataListener(this); | 
|  | ListModel newModel = (ListModel) e.getNewValue(); | 
|  | newModel.addListDataListener(this); | 
|  | } | 
|  | else if (propertyName.equals("selectionModel")) | 
|  | { | 
|  | ListSelectionModel oldModel = (ListSelectionModel) e.getOldValue(); | 
|  | oldModel.removeListSelectionListener(this); | 
|  | ListSelectionModel newModel = (ListSelectionModel) e.getNewValue(); | 
|  | oldModel.addListSelectionListener(this); | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Return the state set of the <code>JList</code>. | 
|  | * | 
|  | * @return the state set of the <code>JList</code> | 
|  | */ | 
|  | public AccessibleStateSet getAccessibleStateSet() | 
|  | { | 
|  | // TODO: Figure out if there is possibly more state that must be | 
|  | // handled here. | 
|  | AccessibleStateSet s = super.getAccessibleStateSet(); | 
|  | if (getSelectionMode() != ListSelectionModel.SINGLE_SELECTION) | 
|  | s.add(AccessibleState.MULTISELECTABLE); | 
|  | return s; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the accessible role for <code>JList</code>, | 
|  | * {@link AccessibleRole#LIST}. | 
|  | * | 
|  | * @return the accessible role for <code>JList</code> | 
|  | */ | 
|  | public AccessibleRole getAccessibleRole() | 
|  | { | 
|  | return AccessibleRole.LIST; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the accessible child at the visual location <code>p</code> | 
|  | * (relative to the upper left corner of the <code>JList</code>). If there | 
|  | * is no child at that location, this returns <code>null</code>. | 
|  | * | 
|  | * @param p the screen location for which to return the accessible child | 
|  | * | 
|  | * @return the accessible child at the specified location, or | 
|  | *         <code>null</code> if there is no child at that location | 
|  | */ | 
|  | public Accessible getAccessibleAt(Point p) | 
|  | { | 
|  | int childIndex = locationToIndex(p); | 
|  | return getAccessibleChild(childIndex); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the number of accessible children in the <code>JList</code>. | 
|  | * | 
|  | * @return the number of accessible children in the <code>JList</code> | 
|  | */ | 
|  | public int getAccessibleChildrenCount() | 
|  | { | 
|  | return getModel().getSize(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the n-th accessible child of this <code>JList</code>. This will | 
|  | * be an instance of {@link AccessibleJListChild}. If there is no child | 
|  | * at that index, <code>null</code> is returned. | 
|  | * | 
|  | * @param n the index of the child to return | 
|  | * | 
|  | * @return the n-th accessible child of this <code>JList</code> | 
|  | */ | 
|  | public Accessible getAccessibleChild(int n) | 
|  | { | 
|  | if (getModel().getSize() <= n) | 
|  | return null; | 
|  | return new AccessibleJListChild(JList.this, n); | 
|  | } | 
|  | } | 
|  |  | 
|  | private static final long serialVersionUID = 4406629526391098046L; | 
|  |  | 
|  | /** | 
|  | * Constant value used in "layoutOrientation" property. This value means | 
|  | * that cells are laid out in a single vertical column. This is the default. | 
|  | */ | 
|  | public static final int VERTICAL = 0; | 
|  |  | 
|  | /** | 
|  | * Constant value used in "layoutOrientation" property. This value means | 
|  | * that cells are laid out in multiple columns "newspaper style", filling | 
|  | * vertically first, then horizontally. | 
|  | */ | 
|  | public static final int VERTICAL_WRAP = 1; | 
|  |  | 
|  | /** | 
|  | * Constant value used in "layoutOrientation" property. This value means | 
|  | * that cells are laid out in multiple columns "newspaper style", | 
|  | * filling horizontally first, then vertically. | 
|  | */ | 
|  | public static final int HORIZONTAL_WRAP = 2; | 
|  |  | 
|  | /** | 
|  | * This property indicates whether "drag and drop" functions are enabled | 
|  | * on the list. | 
|  | */ | 
|  | boolean dragEnabled; | 
|  |  | 
|  | /** This property provides a strategy for rendering cells in the list. */ | 
|  | ListCellRenderer cellRenderer; | 
|  |  | 
|  | /** | 
|  | * This property indicates an fixed width to assign to all cells in the | 
|  | * list. If its value is <code>-1</code>, no width has been | 
|  | * assigned. This value can be set explicitly, or implicitly by setting | 
|  | * the {@link #prototypeCellValue} property. | 
|  | */ | 
|  | int fixedCellWidth; | 
|  |  | 
|  | /** | 
|  | * This property indicates an fixed height to assign to all cells in the | 
|  | * list. If its value is <code>-1</code>, no height has been | 
|  | * assigned. This value can be set explicitly, or implicitly by setting | 
|  | * the {@link #prototypeCellValue} property. | 
|  | */ | 
|  | int fixedCellHeight; | 
|  |  | 
|  | /** | 
|  | * This property holds the current layout orientation of the list, which | 
|  | * is one of the integer constants {@link #VERTICAL}, {@link | 
|  | * #VERTICAL_WRAP}, or {@link #HORIZONTAL_WRAP}. | 
|  | */ | 
|  | int layoutOrientation; | 
|  |  | 
|  | /** This property holds the data elements displayed by the list. */ | 
|  | ListModel model; | 
|  |  | 
|  | /** | 
|  | * <p>This property holds a reference to a "prototype" data value -- | 
|  | * typically a String -- which is used to calculate the {@link | 
|  | * #fixedCellWidth} and {@link #fixedCellHeight} properties, using the | 
|  | * {@link #cellRenderer} property to acquire a component to render the | 
|  | * prototype.</p> | 
|  | * | 
|  | * <p>It is important that you <em>not</em> set this value to a | 
|  | * component. It has to be a <em>data value</em> such as the objects you | 
|  | * would find in the list's model. Setting it to a component will have | 
|  | * undefined (and undesirable) affects. </p> | 
|  | */ | 
|  | Object prototypeCellValue; | 
|  |  | 
|  | /** | 
|  | * This property specifies a foreground color for the selected cells in | 
|  | * the list. When {@link ListCellRenderer#getListCellRendererComponent} | 
|  | * is called with a selected cell object, the component returned will | 
|  | * have its "foreground" set to this color. | 
|  | */ | 
|  | Color selectionBackground; | 
|  |  | 
|  | /** | 
|  | * This property specifies a background color for the selected cells in | 
|  | * the list. When {@link ListCellRenderer#getListCellRendererComponent} | 
|  | * is called with a selected cell object, the component returned will | 
|  | * have its "background" property set to this color. | 
|  | */ | 
|  | Color selectionForeground; | 
|  |  | 
|  | /** | 
|  | * This property holds a description of which data elements in the {@link | 
|  | * #model} property should be considered "selected", when displaying and | 
|  | * interacting with the list. | 
|  | */ | 
|  | ListSelectionModel selectionModel; | 
|  |  | 
|  | /** | 
|  | * This property indicates a <em>preference</em> for the number of rows | 
|  | * displayed in the list, and will scale the | 
|  | * {@link #getPreferredScrollableViewportSize} property accordingly. The actual | 
|  | * number of displayed rows, when the list is placed in a real {@link | 
|  | * JViewport} or other component, may be greater or less than this number. | 
|  | */ | 
|  | int visibleRowCount; | 
|  |  | 
|  | /** | 
|  | * Fire a {@link ListSelectionEvent} to all the registered | 
|  | * ListSelectionListeners. | 
|  | * | 
|  | * @param firstIndex  the lowest index covering the selection change. | 
|  | * @param lastIndex  the highest index covering the selection change. | 
|  | * @param isAdjusting  a flag indicating if this event is one in a series | 
|  | *     of events updating the selection. | 
|  | */ | 
|  | protected void fireSelectionValueChanged(int firstIndex, int lastIndex, | 
|  | boolean isAdjusting) | 
|  | { | 
|  | ListSelectionEvent evt = new ListSelectionEvent(this, firstIndex, | 
|  | lastIndex, isAdjusting); | 
|  | ListSelectionListener listeners[] = getListSelectionListeners(); | 
|  | for (int i = 0; i < listeners.length; ++i) | 
|  | { | 
|  | listeners[i].valueChanged(evt); | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * This private listener propagates {@link ListSelectionEvent} events | 
|  | * from the list's "selectionModel" property to the list's {@link | 
|  | * ListSelectionListener} listeners. It also listens to {@link | 
|  | * ListDataEvent} events from the list's {@link #model} property. If this | 
|  | * class receives either type of event, it triggers repainting of the | 
|  | * list. | 
|  | */ | 
|  | private class ListListener | 
|  | implements ListSelectionListener, ListDataListener | 
|  | { | 
|  | // ListDataListener events | 
|  | public void contentsChanged(ListDataEvent event) | 
|  | { | 
|  | JList.this.revalidate(); | 
|  | JList.this.repaint(); | 
|  | } | 
|  | public void intervalAdded(ListDataEvent event) | 
|  | { | 
|  | JList.this.revalidate(); | 
|  | JList.this.repaint(); | 
|  | } | 
|  | public void intervalRemoved(ListDataEvent event) | 
|  | { | 
|  | JList.this.revalidate(); | 
|  | JList.this.repaint(); | 
|  | } | 
|  | // ListSelectionListener events | 
|  | public void valueChanged(ListSelectionEvent event) | 
|  | { | 
|  | JList.this.fireSelectionValueChanged(event.getFirstIndex(), | 
|  | event.getLastIndex(), | 
|  | event.getValueIsAdjusting()); | 
|  | JList.this.repaint(); | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Shared ListListener instance, subscribed to both the current {@link | 
|  | * #model} and {@link #selectionModel} properties of the list. | 
|  | */ | 
|  | ListListener listListener; | 
|  |  | 
|  |  | 
|  | /** | 
|  | * Creates a new <code>JList</code> object. | 
|  | */ | 
|  | public JList() | 
|  | { | 
|  | init(new DefaultListModel()); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Creates a new <code>JList</code> object. | 
|  | * | 
|  | * @param items  the initial list items. | 
|  | */ | 
|  | public JList(Object[] items) | 
|  | { | 
|  | init(createListModel(items)); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Creates a new <code>JList</code> object. | 
|  | * | 
|  | * @param items  the initial list items. | 
|  | */ | 
|  | public JList(Vector items) | 
|  | { | 
|  | init(createListModel(items)); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Creates a new <code>JList</code> object. | 
|  | * | 
|  | * @param model  a model containing the list items (<code>null</code> not | 
|  | *     permitted). | 
|  | * | 
|  | * @throws IllegalArgumentException if <code>model</code> is | 
|  | *     <code>null</code>. | 
|  | */ | 
|  | public JList(ListModel model) | 
|  | { | 
|  | init(model); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Initializes the list. | 
|  | * | 
|  | * @param m  the list model (<code>null</code> not permitted). | 
|  | */ | 
|  | private void init(ListModel m) | 
|  | { | 
|  | if (m == null) | 
|  | throw new IllegalArgumentException("Null model not permitted."); | 
|  | dragEnabled = false; | 
|  | fixedCellHeight = -1; | 
|  | fixedCellWidth = -1; | 
|  | layoutOrientation = VERTICAL; | 
|  | opaque = true; | 
|  | visibleRowCount = 8; | 
|  |  | 
|  | cellRenderer = new DefaultListCellRenderer(); | 
|  | listListener = new ListListener(); | 
|  |  | 
|  | model = m; | 
|  | if (model != null) | 
|  | model.addListDataListener(listListener); | 
|  |  | 
|  | selectionModel = createSelectionModel(); | 
|  | if (selectionModel != null) | 
|  | { | 
|  | selectionModel.addListSelectionListener(listListener); | 
|  | selectionModel.setSelectionMode | 
|  | (ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); | 
|  | } | 
|  | setLayout(null); | 
|  |  | 
|  | updateUI(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Creates the default <code>ListSelectionModel</code>. | 
|  | * | 
|  | * @return the <code>ListSelectionModel</code> | 
|  | */ | 
|  | protected ListSelectionModel createSelectionModel() | 
|  | { | 
|  | return new DefaultListSelectionModel(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Gets the value of the {@link #fixedCellHeight} property. This property | 
|  | * may be <code>-1</code> to indicate that no cell height has been | 
|  | * set. This property is also set implicitly when the | 
|  | * {@link #prototypeCellValue} property is set. | 
|  | * | 
|  | * @return The current value of the property | 
|  | * | 
|  | * @see #fixedCellHeight | 
|  | * @see #setFixedCellHeight | 
|  | * @see #setPrototypeCellValue | 
|  | */ | 
|  | public int getFixedCellHeight() | 
|  | { | 
|  | return fixedCellHeight; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Sets the value of the {@link #fixedCellHeight} property. This property | 
|  | * may be <code>-1</code> to indicate that no cell height has been | 
|  | * set. This property is also set implicitly when the {@link | 
|  | * #prototypeCellValue} property is set, but setting it explicitly | 
|  | * overrides the height computed from {@link #prototypeCellValue}. | 
|  | * | 
|  | * @param h  the height. | 
|  | * | 
|  | * @see #getFixedCellHeight | 
|  | * @see #getPrototypeCellValue | 
|  | */ | 
|  | public void setFixedCellHeight(int h) | 
|  | { | 
|  | if (fixedCellHeight == h) | 
|  | return; | 
|  |  | 
|  | int old = fixedCellHeight; | 
|  | fixedCellHeight = h; | 
|  | firePropertyChange("fixedCellHeight", old, h); | 
|  | } | 
|  |  | 
|  |  | 
|  | /** | 
|  | * Gets the value of the {@link #fixedCellWidth} property. This property | 
|  | * may be <code>-1</code> to indicate that no cell width has been | 
|  | * set. This property is also set implicitly when the {@link | 
|  | * #prototypeCellValue} property is set. | 
|  | * | 
|  | * @return The current value of the property | 
|  | * | 
|  | * @see #setFixedCellWidth | 
|  | * @see #setPrototypeCellValue | 
|  | */ | 
|  | public int getFixedCellWidth() | 
|  | { | 
|  | return fixedCellWidth; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Sets the value of the {@link #fixedCellWidth} property. This property | 
|  | * may be <code>-1</code> to indicate that no cell width has been | 
|  | * set. This property is also set implicitly when the {@link | 
|  | * #prototypeCellValue} property is set, but setting it explicitly | 
|  | * overrides the width computed from {@link #prototypeCellValue}. | 
|  | * | 
|  | * @param w  the width. | 
|  | * | 
|  | * @see #getFixedCellHeight | 
|  | * @see #getPrototypeCellValue | 
|  | */ | 
|  | public void setFixedCellWidth(int w) | 
|  | { | 
|  | if (fixedCellWidth == w) | 
|  | return; | 
|  |  | 
|  | int old = fixedCellWidth; | 
|  | fixedCellWidth = w; | 
|  | firePropertyChange("fixedCellWidth", old, w); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Gets the value of the {@link #visibleRowCount} property.  The default | 
|  | * value is 8. | 
|  | * | 
|  | * @return the current value of the property. | 
|  | * | 
|  | * @see #setVisibleRowCount(int) | 
|  | */ | 
|  | public int getVisibleRowCount() | 
|  | { | 
|  | return visibleRowCount; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Sets the value of the {@link #visibleRowCount} property. | 
|  | * | 
|  | * @param vc The new property value | 
|  | * | 
|  | * @see #getVisibleRowCount() | 
|  | */ | 
|  | public void setVisibleRowCount(int vc) | 
|  | { | 
|  | if (visibleRowCount != vc) | 
|  | { | 
|  | int oldValue = visibleRowCount; | 
|  | visibleRowCount = Math.max(vc, 0); | 
|  | firePropertyChange("visibleRowCount", oldValue, vc); | 
|  | revalidate(); | 
|  | repaint(); | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Adds a {@link ListSelectionListener} to the listener list for this | 
|  | * list. The listener will be called back with a {@link | 
|  | * ListSelectionEvent} any time the list's {@link #selectionModel} | 
|  | * property changes. The source of such events will be the JList, | 
|  | * not the selection model. | 
|  | * | 
|  | * @param listener The new listener to add | 
|  | */ | 
|  | public void addListSelectionListener(ListSelectionListener listener) | 
|  | { | 
|  | listenerList.add (ListSelectionListener.class, listener); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Removes a {@link ListSelectionListener} from the listener list for | 
|  | * this list. The listener will no longer be called when the list's | 
|  | * {@link #selectionModel} changes. | 
|  | * | 
|  | * @param listener The listener to remove | 
|  | */ | 
|  | public void removeListSelectionListener(ListSelectionListener listener) | 
|  | { | 
|  | listenerList.remove(ListSelectionListener.class, listener); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns an array of all ListSelectionListeners subscribed to this | 
|  | * list. | 
|  | * | 
|  | * @return The current subscribed listeners | 
|  | * | 
|  | * @since 1.4 | 
|  | */ | 
|  | public ListSelectionListener[] getListSelectionListeners() | 
|  | { | 
|  | return (ListSelectionListener[]) getListeners(ListSelectionListener.class); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the selection mode for the list (one of: | 
|  | * {@link ListSelectionModel#SINGLE_SELECTION}, | 
|  | * {@link ListSelectionModel#SINGLE_INTERVAL_SELECTION} and | 
|  | * {@link ListSelectionModel#MULTIPLE_INTERVAL_SELECTION}). | 
|  | * | 
|  | * @return The selection mode. | 
|  | * | 
|  | * @see #setSelectionMode(int) | 
|  | */ | 
|  | public int getSelectionMode() | 
|  | { | 
|  | return selectionModel.getSelectionMode(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Sets the list's "selectionMode" property, which simply mirrors the | 
|  | * same property on the list's {@link #selectionModel} property. This | 
|  | * property should be one of the integer constants | 
|  | * <code>SINGLE_SELECTION</code>, <code>SINGLE_INTERVAL_SELECTION</code>, | 
|  | * or <code>MULTIPLE_INTERVAL_SELECTION</code> from the {@link | 
|  | * ListSelectionModel} interface. | 
|  | * | 
|  | * @param a The new selection mode | 
|  | */ | 
|  | public void setSelectionMode(int a) | 
|  | { | 
|  | selectionModel.setSelectionMode(a); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Adds the interval <code>[a,a]</code> to the set of selections managed | 
|  | * by this list's {@link #selectionModel} property. Depending on the | 
|  | * selection mode, this may cause existing selections to become invalid, | 
|  | * or may simply expand the set of selections. | 
|  | * | 
|  | * @param a A number in the half-open range <code>[0, x)</code> where | 
|  | * <code>x = getModel.getSize()</code>, indicating the index of an | 
|  | * element in the list to select. When < 0 the selection is cleared. | 
|  | * | 
|  | * @see #setSelectionMode | 
|  | * @see #selectionModel | 
|  | */ | 
|  | public void setSelectedIndex(int a) | 
|  | { | 
|  | if (a < 0) | 
|  | selectionModel.clearSelection(); | 
|  | else | 
|  | selectionModel.setSelectionInterval(a, a); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * For each element <code>a[i]</code> of the provided array | 
|  | * <code>a</code>, calls {@link #setSelectedIndex} on <code>a[i]</code>. | 
|  | * | 
|  | * @param a  an array of selected indices (<code>null</code> not permitted). | 
|  | * | 
|  | * @throws NullPointerException if <code>a</code> is <code>null</code>. | 
|  | * @see #setSelectionMode | 
|  | * @see #selectionModel | 
|  | */ | 
|  | public void setSelectedIndices(int [] a) | 
|  | { | 
|  | for (int i = 0; i < a.length; ++i) | 
|  | setSelectedIndex(a[i]); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the minimum index of an element in the list which is currently | 
|  | * selected. | 
|  | * | 
|  | * @return A number in the half-open range <code>[0, x)</code> where | 
|  | * <code>x = getModel.getSize()</code>, indicating the minimum index of | 
|  | * an element in the list for which the element is selected, or | 
|  | * <code>-1</code> if no elements are selected | 
|  | */ | 
|  | public int getSelectedIndex() | 
|  | { | 
|  | return selectionModel.getMinSelectionIndex(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns <code>true</code> if the model's selection is empty, otherwise | 
|  | * <code>false</code>. | 
|  | * | 
|  | * @return The return value of {@link ListSelectionModel#isSelectionEmpty} | 
|  | */ | 
|  | public boolean isSelectionEmpty() | 
|  | { | 
|  | return selectionModel.isSelectionEmpty(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the list index of the upper left or upper right corner of the | 
|  | * visible rectangle of this list, depending on the {@link | 
|  | * Component#getComponentOrientation} property. | 
|  | * | 
|  | * @return The index of the first visible list cell, or <code>-1</code> | 
|  | * if none is visible. | 
|  | */ | 
|  | public int getFirstVisibleIndex() | 
|  | { | 
|  | ComponentOrientation or = getComponentOrientation(); | 
|  | Rectangle r = getVisibleRect(); | 
|  | if (or == ComponentOrientation.RIGHT_TO_LEFT) | 
|  | r.translate((int) r.getWidth() - 1, 0); | 
|  | return getUI().locationToIndex(this, r.getLocation()); | 
|  | } | 
|  |  | 
|  |  | 
|  | /** | 
|  | * Returns index of the cell to which specified location is closest to. If | 
|  | * the location is outside the bounds of the list, then the greatest index | 
|  | * in the list model is returned. If the list model is empty, then | 
|  | * <code>-1</code> is returned. | 
|  | * | 
|  | * @param location for which to look for in the list | 
|  | * | 
|  | * @return index of the cell to which specified location is closest to. | 
|  | */ | 
|  | public int locationToIndex(Point location) | 
|  | { | 
|  | return getUI().locationToIndex(this, location); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns location of the cell located at the specified index in the list. | 
|  | * @param index of the cell for which location will be determined | 
|  | * | 
|  | * @return location of the cell located at the specified index in the list. | 
|  | */ | 
|  | public Point indexToLocation(int index) | 
|  | { | 
|  | return getUI().indexToLocation(this, index); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the list index of the lower right or lower left corner of the | 
|  | * visible rectangle of this list, depending on the {@link | 
|  | * Component#getComponentOrientation} property. | 
|  | * | 
|  | * @return The index of the last visible list cell, or <code>-1</code> | 
|  | * if none is visible. | 
|  | */ | 
|  | public int getLastVisibleIndex() | 
|  | { | 
|  | ComponentOrientation or = getComponentOrientation(); | 
|  | Rectangle r = getVisibleRect(); | 
|  | r.translate(0, (int) r.getHeight() - 1); | 
|  | if (or == ComponentOrientation.LEFT_TO_RIGHT) | 
|  | r.translate((int) r.getWidth() - 1, 0); | 
|  | if (getUI().locationToIndex(this, r.getLocation()) == -1 | 
|  | && indexToLocation(getModel().getSize() - 1).y < r.y) | 
|  | return getModel().getSize() - 1; | 
|  | return getUI().locationToIndex(this, r.getLocation()); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the indices of values in the {@link #model} property which are | 
|  | * selected. | 
|  | * | 
|  | * @return An array of model indices, each of which is selected according | 
|  | *         to the {@link #getSelectedValues} property | 
|  | */ | 
|  | public int[] getSelectedIndices() | 
|  | { | 
|  | int lo, hi, n, i, j; | 
|  | if (selectionModel.isSelectionEmpty()) | 
|  | return new int[0]; | 
|  | lo = selectionModel.getMinSelectionIndex(); | 
|  | hi = selectionModel.getMaxSelectionIndex(); | 
|  | n = 0; | 
|  | for (i = lo; i <= hi; ++i) | 
|  | if (selectionModel.isSelectedIndex(i)) | 
|  | n++; | 
|  | int [] v = new int[n]; | 
|  | j = 0; | 
|  | for (i = lo; i <= hi; ++i) | 
|  | if (selectionModel.isSelectedIndex(i)) | 
|  | v[j++] = i; | 
|  | return v; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Indicates whether the list element at a given index value is | 
|  | * currently selected. | 
|  | * | 
|  | * @param a The index to check | 
|  | * @return <code>true</code> if <code>a</code> is the index of a selected | 
|  | * list element | 
|  | */ | 
|  | public boolean isSelectedIndex(int a) | 
|  | { | 
|  | return selectionModel.isSelectedIndex(a); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the first value in the list's {@link #model} property which is | 
|  | * selected, according to the list's {@link #selectionModel} property. | 
|  | * This is equivalent to calling | 
|  | * <code>getModel()getElementAt(getSelectedIndex())</code>, with a check | 
|  | * for the special index value of <code>-1</code> which returns null | 
|  | * <code>null</code>. | 
|  | * | 
|  | * @return The first selected element, or <code>null</code> if no element | 
|  | * is selected. | 
|  | * | 
|  | * @see #getSelectedValues | 
|  | */ | 
|  | public Object getSelectedValue() | 
|  | { | 
|  | int index = getSelectedIndex(); | 
|  | if (index == -1) | 
|  | return null; | 
|  | return getModel().getElementAt(index); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns all the values in the list's {@link #model} property which are | 
|  | * selected, according to the list's {@link #selectionModel} property. | 
|  | * | 
|  | * @return An array containing all the selected values | 
|  | * @see #setSelectedValue | 
|  | */ | 
|  | public Object[] getSelectedValues() | 
|  | { | 
|  | int[] idx = getSelectedIndices(); | 
|  | Object[] v = new Object[idx.length]; | 
|  | for (int i = 0; i < idx.length; ++i) | 
|  | v[i] = getModel().getElementAt(idx[i]); | 
|  | return v; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Gets the value of the {@link #selectionBackground} property. | 
|  | * | 
|  | * @return The current value of the property | 
|  | */ | 
|  | public Color getSelectionBackground() | 
|  | { | 
|  | return selectionBackground; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Sets the value of the {@link #selectionBackground} property. | 
|  | * | 
|  | * @param c The new value of the property | 
|  | */ | 
|  | public void setSelectionBackground(Color c) | 
|  | { | 
|  | if (selectionBackground == c) | 
|  | return; | 
|  |  | 
|  | Color old = selectionBackground; | 
|  | selectionBackground = c; | 
|  | firePropertyChange("selectionBackground", old, c); | 
|  | repaint(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Gets the value of the {@link #selectionForeground} property. | 
|  | * | 
|  | * @return The current value of the property | 
|  | */ | 
|  | public Color getSelectionForeground() | 
|  | { | 
|  | return selectionForeground; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Sets the value of the {@link #selectionForeground} property. | 
|  | * | 
|  | * @param c The new value of the property | 
|  | */ | 
|  | public void setSelectionForeground(Color c) | 
|  | { | 
|  | if (selectionForeground == c) | 
|  | return; | 
|  |  | 
|  | Color old = selectionForeground; | 
|  | selectionForeground = c; | 
|  | firePropertyChange("selectionForeground", old, c); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Sets the selection to cover only the specified value, if it | 
|  | * exists in the model. | 
|  | * | 
|  | * @param obj The object to select | 
|  | * @param scroll Whether to scroll the list to make the newly selected | 
|  | * value visible | 
|  | * | 
|  | * @see #ensureIndexIsVisible | 
|  | */ | 
|  |  | 
|  | public void setSelectedValue(Object obj, boolean scroll) | 
|  | { | 
|  | for (int i = 0; i < model.getSize(); ++i) | 
|  | { | 
|  | if (model.getElementAt(i).equals(obj)) | 
|  | { | 
|  | setSelectedIndex(i); | 
|  | if (scroll) | 
|  | ensureIndexIsVisible(i); | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Scrolls this list to make the specified cell visible. This | 
|  | * only works if the list is contained within a viewport. | 
|  | * | 
|  | * @param i The list index to make visible | 
|  | * | 
|  | * @see JComponent#scrollRectToVisible | 
|  | */ | 
|  | public void ensureIndexIsVisible(int i) | 
|  | { | 
|  | Rectangle r = getUI().getCellBounds(this, i, i); | 
|  | if (r != null) | 
|  | scrollRectToVisible(r); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Sets the {@link #model} property of the list to a new anonymous | 
|  | * {@link AbstractListModel} subclass which accesses the provided Object | 
|  | * array directly. | 
|  | * | 
|  | * @param listData The object array to build a new list model on | 
|  | * @see #setModel | 
|  | */ | 
|  | public void setListData(Object[] listData) | 
|  | { | 
|  | setModel(createListModel(listData)); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns a {@link ListModel} backed by the specified array. | 
|  | * | 
|  | * @param items  the list items (don't use <code>null</code>). | 
|  | * | 
|  | * @return A list model containing the specified items. | 
|  | */ | 
|  | private ListModel createListModel(final Object[] items) | 
|  | { | 
|  | return new AbstractListModel() | 
|  | { | 
|  | public int getSize() | 
|  | { | 
|  | return items.length; | 
|  | } | 
|  | public Object getElementAt(int i) | 
|  | { | 
|  | return items[i]; | 
|  | } | 
|  | }; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns a {@link ListModel} backed by the specified vector. | 
|  | * | 
|  | * @param items  the list items (don't use <code>null</code>). | 
|  | * | 
|  | * @return A list model containing the specified items. | 
|  | */ | 
|  | private ListModel createListModel(final Vector items) | 
|  | { | 
|  | return new AbstractListModel() | 
|  | { | 
|  | public int getSize() | 
|  | { | 
|  | return items.size(); | 
|  | } | 
|  | public Object getElementAt(int i) | 
|  | { | 
|  | return items.get(i); | 
|  | } | 
|  | }; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Sets the {@link #model} property of the list to a new anonymous {@link | 
|  | * AbstractListModel} subclass which accesses the provided vector | 
|  | * directly. | 
|  | * | 
|  | * @param listData The object array to build a new list model on | 
|  | * @see #setModel | 
|  | */ | 
|  | public void setListData(Vector listData) | 
|  | { | 
|  | setModel(createListModel(listData)); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Gets the value of the {@link #cellRenderer} property. | 
|  | * | 
|  | * @return The current value of the property | 
|  | */ | 
|  | public ListCellRenderer getCellRenderer() | 
|  | { | 
|  | return cellRenderer; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Sets the value of the {@link #getCellRenderer} property. | 
|  | * | 
|  | * @param renderer The new property value | 
|  | */ | 
|  | public void setCellRenderer(ListCellRenderer renderer) | 
|  | { | 
|  | if (cellRenderer == renderer) | 
|  | return; | 
|  |  | 
|  | ListCellRenderer old = cellRenderer; | 
|  | cellRenderer = renderer; | 
|  | firePropertyChange("cellRenderer", old, renderer); | 
|  | revalidate(); | 
|  | repaint(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Gets the value of the {@link #model} property. | 
|  | * | 
|  | * @return The current value of the property | 
|  | */ | 
|  | public ListModel getModel() | 
|  | { | 
|  | return model; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Sets the value of the {@link #model} property. The list's {@link | 
|  | * #listListener} is unsubscribed from the existing model, if it exists, | 
|  | * and re-subscribed to the new model. | 
|  | * | 
|  | * @param model  the new model (<code>null</code> not permitted). | 
|  | * | 
|  | * @throws IllegalArgumentException if <code>model</code> is | 
|  | *         <code>null</code>. | 
|  | */ | 
|  | public void setModel(ListModel model) | 
|  | { | 
|  | if (model == null) | 
|  | throw new IllegalArgumentException("Null 'model' argument."); | 
|  | if (this.model == model) | 
|  | return; | 
|  |  | 
|  | if (this.model != null) | 
|  | this.model.removeListDataListener(listListener); | 
|  |  | 
|  | ListModel old = this.model; | 
|  | this.model = model; | 
|  |  | 
|  | if (this.model != null) | 
|  | this.model.addListDataListener(listListener); | 
|  |  | 
|  | firePropertyChange("model", old, model); | 
|  | revalidate(); | 
|  | repaint(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the selection model for the {@link JList} component.  Note that | 
|  | * this class contains a range of convenience methods for configuring the | 
|  | * selection model:<br> | 
|  | * <ul> | 
|  | *   <li>{@link #clearSelection()};</li> | 
|  | *   <li>{@link #setSelectionMode(int)};</li> | 
|  | *   <li>{@link #addSelectionInterval(int, int)};</li> | 
|  | *   <li>{@link #setSelectedIndex(int)};</li> | 
|  | *   <li>{@link #setSelectedIndices(int[])};</li> | 
|  | *   <li>{@link #setSelectionInterval(int, int)}.</li> | 
|  | * </ul> | 
|  | * | 
|  | * @return The selection model. | 
|  | */ | 
|  | public ListSelectionModel getSelectionModel() | 
|  | { | 
|  | return selectionModel; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Sets the value of the {@link #selectionModel} property. The list's | 
|  | * {@link #listListener} is unsubscribed from the existing selection | 
|  | * model, if it exists, and re-subscribed to the new selection model. | 
|  | * | 
|  | * @param model The new property value | 
|  | */ | 
|  | public void setSelectionModel(ListSelectionModel model) | 
|  | { | 
|  | if (selectionModel == model) | 
|  | return; | 
|  |  | 
|  | if (selectionModel != null) | 
|  | selectionModel.removeListSelectionListener(listListener); | 
|  |  | 
|  | ListSelectionModel old = selectionModel; | 
|  | selectionModel = model; | 
|  |  | 
|  | if (selectionModel != null) | 
|  | selectionModel.addListSelectionListener(listListener); | 
|  |  | 
|  | firePropertyChange("selectionModel", old, model); | 
|  | revalidate(); | 
|  | repaint(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Gets the value of the UI property. | 
|  | * | 
|  | * @return The current property value | 
|  | */ | 
|  | public ListUI getUI() | 
|  | { | 
|  | return (ListUI) ui; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Sets the value of the UI property. | 
|  | * | 
|  | * @param ui The new property value | 
|  | */ | 
|  | public void setUI(ListUI ui) | 
|  | { | 
|  | super.setUI(ui); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Calls {@link #setUI} with the {@link ListUI} subclass | 
|  | * returned from calling {@link UIManager#getUI}. | 
|  | */ | 
|  | public void updateUI() | 
|  | { | 
|  | setUI((ListUI) UIManager.getUI(this)); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Return the class identifier for the list's UI property.  This should | 
|  | * be the constant string <code>"ListUI"</code>, and map to an | 
|  | * appropriate UI class in the {@link UIManager}. | 
|  | * | 
|  | * @return The class identifier | 
|  | */ | 
|  | public String getUIClassID() | 
|  | { | 
|  | return "ListUI"; | 
|  | } | 
|  |  | 
|  |  | 
|  | /** | 
|  | * Returns the current value of the {@link #prototypeCellValue} | 
|  | * property. This property holds a reference to a "prototype" data value | 
|  | * -- typically a String -- which is used to calculate the {@link | 
|  | * #fixedCellWidth} and {@link #fixedCellHeight} properties, using the | 
|  | * {@link #cellRenderer} property to acquire a component to render the | 
|  | * prototype. | 
|  | * | 
|  | * @return The current prototype cell value | 
|  | * @see #setPrototypeCellValue | 
|  | */ | 
|  | public Object getPrototypeCellValue() | 
|  | { | 
|  | return prototypeCellValue; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * <p>Set the {@link #prototypeCellValue} property. This property holds a | 
|  | * reference to a "prototype" data value -- typically a String -- which | 
|  | * is used to calculate the {@link #fixedCellWidth} and {@link | 
|  | * #fixedCellHeight} properties, using the {@link #cellRenderer} property | 
|  | * to acquire a component to render the prototype.</p> | 
|  | * | 
|  | * <p>It is important that you <em>not</em> set this value to a | 
|  | * component. It has to be a <em>data value</em> such as the objects you | 
|  | * would find in the list's model. Setting it to a component will have | 
|  | * undefined (and undesirable) affects. </p> | 
|  | * | 
|  | * @param obj The new prototype cell value | 
|  | * @see #getPrototypeCellValue | 
|  | */ | 
|  | public void setPrototypeCellValue(Object obj) | 
|  | { | 
|  | if (prototypeCellValue == obj) | 
|  | return; | 
|  |  | 
|  | Object old = prototypeCellValue; | 
|  | Component comp = getCellRenderer() | 
|  | .getListCellRendererComponent(this, obj, 0, false, false); | 
|  | Dimension d = comp.getPreferredSize(); | 
|  | fixedCellWidth = d.width; | 
|  | fixedCellHeight = d.height; | 
|  | prototypeCellValue = obj; | 
|  | firePropertyChange("prototypeCellValue", old, obj); | 
|  | } | 
|  |  | 
|  | public AccessibleContext getAccessibleContext() | 
|  | { | 
|  | return new AccessibleJList(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns a size indicating how much space this list would like to | 
|  | * consume, when contained in a scrollable viewport. This is part of the | 
|  | * {@link Scrollable} interface, which interacts with {@link | 
|  | * ScrollPaneLayout} and {@link JViewport} to define scrollable objects. | 
|  | * | 
|  | * @return The preferred size | 
|  | */ | 
|  | public Dimension getPreferredScrollableViewportSize() | 
|  | { | 
|  | //If the layout orientation is not VERTICAL, then this will | 
|  | //return the value from getPreferredSize. The current ListUI is | 
|  | //expected to override getPreferredSize to return an appropriate value. | 
|  | if (getLayoutOrientation() != VERTICAL) | 
|  | return getPreferredSize(); | 
|  |  | 
|  | int size = getModel().getSize(); | 
|  |  | 
|  | // Trivial case: if fixedCellWidth and fixedCellHeight were set | 
|  | // just use them | 
|  | if (fixedCellHeight != -1 && fixedCellWidth != -1) | 
|  | return new Dimension(fixedCellWidth, size * fixedCellHeight); | 
|  |  | 
|  | // If the model is empty we use 16 * the number of visible rows | 
|  | // for the height and either fixedCellWidth (if set) or 256 | 
|  | // for the width | 
|  | if (size == 0) | 
|  | { | 
|  | if (fixedCellWidth == -1) | 
|  | return new Dimension(256, 16 * getVisibleRowCount()); | 
|  | else | 
|  | return new Dimension(fixedCellWidth, 16 * getVisibleRowCount()); | 
|  | } | 
|  |  | 
|  | // Calculate the width: if fixedCellWidth was set use that, otherwise | 
|  | // use the preferredWidth | 
|  | int prefWidth; | 
|  | if (fixedCellWidth != -1) | 
|  | prefWidth = fixedCellWidth; | 
|  | else | 
|  | prefWidth = getPreferredSize().width; | 
|  |  | 
|  | // Calculate the height: if fixedCellHeight was set use that, otherwise | 
|  | // use the height of the first row multiplied by the number of visible | 
|  | // rows | 
|  | int prefHeight; | 
|  | if (fixedCellHeight != -1) | 
|  | prefHeight = fixedCellHeight; | 
|  | else | 
|  | prefHeight = getVisibleRowCount() * getCellBounds(0, 0).height; | 
|  |  | 
|  | return new Dimension (prefWidth, prefHeight); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * <p>Return the number of pixels the list must scroll in order to move a | 
|  | * "unit" of the list into the provided visible rectangle. When the | 
|  | * provided direction is positive, the call describes a "downwards" | 
|  | * scroll, which will be exposing a cell at a <em>greater</em> index in | 
|  | * the list than those elements currently showing. Then the provided | 
|  | * direction is negative, the call describes an "upwards" scroll, which | 
|  | * will be exposing a cell at a <em>lesser</em> index in the list than | 
|  | * those elements currently showing.</p> | 
|  | * | 
|  | * <p>If the provided orientation is <code>HORIZONTAL</code>, the above | 
|  | * comments refer to "rightwards" for positive direction, and "leftwards" | 
|  | * for negative.</p> | 
|  | * | 
|  | * | 
|  | * @param visibleRect The rectangle to scroll an element into | 
|  | * @param orientation One of the numeric consants <code>VERTICAL</code> | 
|  | * or <code>HORIZONTAL</code> | 
|  | * @param direction An integer indicating the scroll direction: positive means | 
|  | * forwards (down, right), negative means backwards (up, left) | 
|  | * | 
|  | * @return The scrollable unit increment, in pixels | 
|  | */ | 
|  | public int getScrollableUnitIncrement(Rectangle visibleRect, | 
|  | int orientation, int direction) | 
|  | { | 
|  | ListUI lui = this.getUI(); | 
|  | if (orientation == SwingConstants.VERTICAL) | 
|  | { | 
|  | if (direction > 0) | 
|  | { | 
|  | // Scrolling down | 
|  | Point bottomLeft = new Point(visibleRect.x, | 
|  | visibleRect.y + visibleRect.height); | 
|  | int curIdx = lui.locationToIndex(this, bottomLeft); | 
|  | Rectangle curBounds = lui.getCellBounds(this, curIdx, curIdx); | 
|  | if (curBounds.y + curBounds.height == bottomLeft.y) | 
|  | { | 
|  | // we are at the exact bottom of the current cell, so we | 
|  | // are being asked to scroll to the end of the next one | 
|  | if (curIdx + 1 < model.getSize()) | 
|  | { | 
|  | // there *is* a next item in the list | 
|  | Rectangle nxtBounds = lui.getCellBounds(this, curIdx + 1, curIdx + 1); | 
|  | return nxtBounds.height; | 
|  | } | 
|  | else | 
|  | { | 
|  | // no next item, no advance possible | 
|  | return 0; | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | // we are part way through an existing cell, so we are being | 
|  | // asked to scroll to the bottom of it | 
|  | return (curBounds.y + curBounds.height) - bottomLeft.y; | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | // scrolling up | 
|  | Point topLeft = new Point(visibleRect.x, visibleRect.y); | 
|  | int curIdx = lui.locationToIndex(this, topLeft); | 
|  | Rectangle curBounds = lui.getCellBounds(this, curIdx, curIdx); | 
|  | if (curBounds.y == topLeft.y) | 
|  | { | 
|  | // we are at the exact top of the current cell, so we | 
|  | // are being asked to scroll to the top of the previous one | 
|  | if (curIdx > 0) | 
|  | { | 
|  | // there *is* a previous item in the list | 
|  | Rectangle nxtBounds = lui.getCellBounds(this, curIdx - 1, curIdx - 1); | 
|  | return -nxtBounds.height; | 
|  | } | 
|  | else | 
|  | { | 
|  | // no previous item, no advance possible | 
|  | return 0; | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | // we are part way through an existing cell, so we are being | 
|  | // asked to scroll to the top of it | 
|  | return curBounds.y - topLeft.y; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // FIXME: handle horizontal scrolling (also wrapping?) | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * <p>Return the number of pixels the list must scroll in order to move a | 
|  | * "block" of the list into the provided visible rectangle. When the | 
|  | * provided direction is positive, the call describes a "downwards" | 
|  | * scroll, which will be exposing a cell at a <em>greater</em> index in | 
|  | * the list than those elements currently showing. Then the provided | 
|  | * direction is negative, the call describes an "upwards" scroll, which | 
|  | * will be exposing a cell at a <em>lesser</em> index in the list than | 
|  | * those elements currently showing.</p> | 
|  | * | 
|  | * <p>If the provided orientation is <code>HORIZONTAL</code>, the above | 
|  | * comments refer to "rightwards" for positive direction, and "leftwards" | 
|  | * for negative.</p> | 
|  | * | 
|  | * | 
|  | * @param visibleRect The rectangle to scroll an element into | 
|  | * @param orientation One of the numeric consants <code>VERTICAL</code> | 
|  | * or <code>HORIZONTAL</code> | 
|  | * @param direction An integer indicating the scroll direction: positive means | 
|  | * forwards (down, right), negative means backwards (up, left) | 
|  | * | 
|  | * @return The scrollable unit increment, in pixels | 
|  | */ | 
|  | public int getScrollableBlockIncrement(Rectangle visibleRect, | 
|  | int orientation, int direction) | 
|  | { | 
|  | if (orientation == VERTICAL) | 
|  | return visibleRect.height * direction; | 
|  | else | 
|  | return visibleRect.width * direction; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Gets the value of the <code>scrollableTracksViewportWidth</code> property. | 
|  | * | 
|  | * @return <code>true</code> if the viewport is larger (horizontally) | 
|  | * than the list and the list should be expanded to fit the viewport; | 
|  | * <code>false</code> if the viewport is smaller than the list and the | 
|  | * list should scroll (horizontally) within the viewport | 
|  | */ | 
|  | public boolean getScrollableTracksViewportWidth() | 
|  | { | 
|  | Component parent = getParent(); | 
|  | boolean retVal = false; | 
|  | if (parent instanceof JViewport) | 
|  | { | 
|  | JViewport viewport = (JViewport) parent; | 
|  | Dimension pref = getPreferredSize(); | 
|  | if (viewport.getSize().width > pref.width) | 
|  | retVal = true; | 
|  | if ((getLayoutOrientation() == HORIZONTAL_WRAP) | 
|  | && (getVisibleRowCount() <= 0)) | 
|  | retVal = true; | 
|  | } | 
|  | return retVal; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Gets the value of the </code>scrollableTracksViewportWidth</code> property. | 
|  | * | 
|  | * @return <code>true</code> if the viewport is larger (vertically) | 
|  | * than the list and the list should be expanded to fit the viewport; | 
|  | * <code>false</code> if the viewport is smaller than the list and the | 
|  | * list should scroll (vertically) within the viewport | 
|  | */ | 
|  | public boolean getScrollableTracksViewportHeight() | 
|  | { | 
|  | Component parent = getParent(); | 
|  | boolean retVal = false; | 
|  | if (parent instanceof JViewport) | 
|  | { | 
|  | JViewport viewport = (JViewport) parent; | 
|  | Dimension pref = getPreferredSize(); | 
|  | if (viewport.getSize().height > pref.height) | 
|  | retVal = true; | 
|  | if ((getLayoutOrientation() == VERTICAL_WRAP) | 
|  | && (getVisibleRowCount() <= 0)) | 
|  | retVal = true; | 
|  | } | 
|  | return retVal; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the index of the anchor item in the current selection, or | 
|  | * <code>-1</code> if there is no anchor item. | 
|  | * | 
|  | * @return The item index. | 
|  | */ | 
|  | public int getAnchorSelectionIndex() | 
|  | { | 
|  | return selectionModel.getAnchorSelectionIndex(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the index of the lead item in the current selection, or | 
|  | * <code>-1</code> if there is no lead item. | 
|  | * | 
|  | * @return The item index. | 
|  | */ | 
|  | public int getLeadSelectionIndex() | 
|  | { | 
|  | return selectionModel.getLeadSelectionIndex(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the lowest item index in the current selection, or <code>-1</code> | 
|  | * if there is no selection. | 
|  | * | 
|  | * @return The index. | 
|  | * | 
|  | * @see #getMaxSelectionIndex() | 
|  | */ | 
|  | public int getMinSelectionIndex() | 
|  | { | 
|  | return selectionModel.getMinSelectionIndex(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the highest item index in the current selection, or | 
|  | * <code>-1</code> if there is no selection. | 
|  | * | 
|  | * @return The index. | 
|  | * | 
|  | * @see #getMinSelectionIndex() | 
|  | */ | 
|  | public int getMaxSelectionIndex() | 
|  | { | 
|  | return selectionModel.getMaxSelectionIndex(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Clears the current selection. | 
|  | */ | 
|  | public void clearSelection() | 
|  | { | 
|  | selectionModel.clearSelection(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Sets the current selection to the items in the specified range (inclusive). | 
|  | * Note that <code>anchor</code> can be less than, equal to, or greater than | 
|  | * <code>lead</code>. | 
|  | * | 
|  | * @param anchor  the index of the anchor item. | 
|  | * @param lead  the index of the anchor item. | 
|  | */ | 
|  | public void setSelectionInterval(int anchor, int lead) | 
|  | { | 
|  | selectionModel.setSelectionInterval(anchor, lead); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Adds the specified interval to the current selection.  Note that | 
|  | * <code>anchor</code> can be less than, equal to, or greater than | 
|  | * <code>lead</code>. | 
|  | * | 
|  | * @param anchor  the index of the anchor item. | 
|  | * @param lead  the index of the lead item. | 
|  | */ | 
|  | public void addSelectionInterval(int anchor, int lead) | 
|  | { | 
|  | selectionModel.addSelectionInterval(anchor, lead); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Removes the specified interval from the current selection.  Note that | 
|  | * <code>index0</code> can be less than, equal to, or greater than | 
|  | * <code>index1</code>. | 
|  | * | 
|  | * @param index0  an index for one end of the range. | 
|  | * @param index1  an index for the other end of the range. | 
|  | */ | 
|  | public void removeSelectionInterval(int index0, int index1) | 
|  | { | 
|  | selectionModel.removeSelectionInterval(index0, index1); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the <code>valueIsAdjusting</code> flag from the list's selection | 
|  | * model. | 
|  | * | 
|  | * @return the value | 
|  | */ | 
|  | public boolean getValueIsAdjusting() | 
|  | { | 
|  | return selectionModel.getValueIsAdjusting(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Sets the <code>valueIsAdjusting</code> flag in the list's selection | 
|  | * model. | 
|  | * | 
|  | * @param isAdjusting the new value | 
|  | */ | 
|  | public void setValueIsAdjusting(boolean isAdjusting) | 
|  | { | 
|  | selectionModel.setValueIsAdjusting(isAdjusting); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Return the value of the <code>dragEnabled</code> property. | 
|  | * | 
|  | * @return the value | 
|  | * | 
|  | * @since 1.4 | 
|  | */ | 
|  | public boolean getDragEnabled() | 
|  | { | 
|  | return dragEnabled; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Set the <code>dragEnabled</code> property. | 
|  | * | 
|  | * @param enabled new value | 
|  | * | 
|  | * @since 1.4 | 
|  | */ | 
|  | public void setDragEnabled(boolean enabled) | 
|  | { | 
|  | dragEnabled = enabled; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the layout orientation, which will be one of {@link #VERTICAL}, | 
|  | * {@link #VERTICAL_WRAP} and {@link #HORIZONTAL_WRAP}.  The default value | 
|  | * is {@link #VERTICAL}. | 
|  | * | 
|  | * @return the orientation. | 
|  | * | 
|  | * @see #setLayoutOrientation(int) | 
|  | * @since 1.4 | 
|  | */ | 
|  | public int getLayoutOrientation() | 
|  | { | 
|  | return layoutOrientation; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Sets the layout orientation (this is a bound property with the name | 
|  | * 'layoutOrientation').  Valid orientations are {@link #VERTICAL}, | 
|  | * {@link #VERTICAL_WRAP} and {@link #HORIZONTAL_WRAP}. | 
|  | * | 
|  | * @param orientation the orientation. | 
|  | * | 
|  | * @throws IllegalArgumentException if <code>orientation</code> is not one | 
|  | *     of the specified values. | 
|  | * @since 1.4 | 
|  | * @see #getLayoutOrientation() | 
|  | */ | 
|  | public void setLayoutOrientation(int orientation) | 
|  | { | 
|  | if (orientation < JList.VERTICAL || orientation > JList.HORIZONTAL_WRAP) | 
|  | throw new IllegalArgumentException(); | 
|  | if (layoutOrientation == orientation) | 
|  | return; | 
|  |  | 
|  | int old = layoutOrientation; | 
|  | layoutOrientation = orientation; | 
|  | firePropertyChange("layoutOrientation", old, orientation); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the bounds of the rectangle that encloses both list cells | 
|  | * with index0 and index1. | 
|  | * | 
|  | * @param index0 the index of the first cell | 
|  | * @param index1 the index of the second cell | 
|  | * | 
|  | * @return  the bounds of the rectangle that encloses both list cells | 
|  | *     with index0 and index1, <code>null</code> if one of the indices is | 
|  | *     not valid | 
|  | */ | 
|  | public Rectangle getCellBounds(int index0, int index1) | 
|  | { | 
|  | ListUI ui = getUI(); | 
|  | Rectangle bounds = null; | 
|  | if (ui != null) | 
|  | { | 
|  | bounds = ui.getCellBounds(this, index0, index1); | 
|  | } | 
|  | // When the UI is null, this method also returns null in the RI. | 
|  | return bounds; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the index of the next list element (beginning at | 
|  | * <code>startIndex</code> and moving in the specified direction through the | 
|  | * list, looping around if necessary) that starts with <code>prefix</code> | 
|  | * (ignoring case). | 
|  | * | 
|  | * @param prefix the prefix to search for in the cell values | 
|  | * @param startIndex the index where to start searching from | 
|  | * @param direction the search direction, either {@link Position.Bias#Forward} | 
|  | *     or {@link Position.Bias#Backward} (<code>null</code> is interpreted | 
|  | *     as {@link Position.Bias#Backward}. | 
|  | * | 
|  | * @return the index of the found element or -1 if no such element has | 
|  | *     been found | 
|  | * | 
|  | * @throws IllegalArgumentException if prefix is <code>null</code> or | 
|  | *     startIndex is not valid | 
|  | * | 
|  | * @since 1.4 | 
|  | */ | 
|  | public int getNextMatch(String prefix, int startIndex, | 
|  | Position.Bias direction) | 
|  | { | 
|  | if (prefix == null) | 
|  | throw new IllegalArgumentException("The argument 'prefix' must not be" | 
|  | + " null."); | 
|  | if (startIndex < 0) | 
|  | throw new IllegalArgumentException("The argument 'startIndex' must not" | 
|  | + " be less than zero."); | 
|  |  | 
|  | int size = model.getSize(); | 
|  | if (startIndex >= model.getSize()) | 
|  | throw new IllegalArgumentException("The argument 'startIndex' must not" | 
|  | + " be greater than the number of" | 
|  | + " elements in the ListModel."); | 
|  |  | 
|  | int result = -1; | 
|  | int current = startIndex; | 
|  | int delta = -1; | 
|  | int itemCount = model.getSize(); | 
|  | boolean finished = false; | 
|  | prefix = prefix.toUpperCase(); | 
|  |  | 
|  | if (direction == Position.Bias.Forward) | 
|  | delta = 1; | 
|  | while (!finished) | 
|  | { | 
|  | String itemStr = model.getElementAt(current).toString().toUpperCase(); | 
|  | if (itemStr.startsWith(prefix)) | 
|  | return current; | 
|  | current = (current + delta); | 
|  | if (current == -1) | 
|  | current += itemCount; | 
|  | else | 
|  | current = current % itemCount; | 
|  | finished = current == startIndex; | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns a string describing the attributes for the <code>JList</code> | 
|  | * component, for use in debugging.  The return value is guaranteed to be | 
|  | * non-<code>null</code>, but the format of the string may vary between | 
|  | * implementations. | 
|  | * | 
|  | * @return A string describing the attributes of the <code>JList</code>. | 
|  | */ | 
|  | protected String paramString() | 
|  | { | 
|  | StringBuffer sb = new StringBuffer(super.paramString()); | 
|  | sb.append(",fixedCellHeight=").append(getFixedCellHeight()); | 
|  | sb.append(",fixedCellWidth=").append(getFixedCellWidth()); | 
|  | sb.append(",selectionBackground="); | 
|  | if (getSelectionBackground() != null) | 
|  | sb.append(getSelectionBackground()); | 
|  | sb.append(",selectionForeground="); | 
|  | if (getSelectionForeground() != null) | 
|  | sb.append(getSelectionForeground()); | 
|  | sb.append(",visibleRowCount=").append(getVisibleRowCount()); | 
|  | sb.append(",layoutOrientation=").append(getLayoutOrientation()); | 
|  | return sb.toString(); | 
|  | } | 
|  | } |