Home » openjdk-7 » javax » swing » [javadoc | source]

    1   /*
    2    * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22    * or visit www.oracle.com if you need additional information or have any
   23    * questions.
   24    */
   25   
   26   package javax.swing;
   27   
   28   import java.awt;
   29   import java.awt.event;
   30   
   31   import java.util.Vector;
   32   import java.util.Locale;
   33   import java.util.ArrayList;
   34   import java.util.Collections;
   35   import java.util.List;
   36   
   37   import java.beans.PropertyChangeEvent;
   38   import java.beans.PropertyChangeListener;
   39   import java.beans.Transient;
   40   
   41   import javax.swing.event;
   42   import javax.accessibility;
   43   import javax.swing.plaf;
   44   import javax.swing.text.Position;
   45   
   46   import java.io.ObjectOutputStream;
   47   import java.io.ObjectInputStream;
   48   import java.io.IOException;
   49   import java.io.Serializable;
   50   
   51   import sun.swing.SwingUtilities2;
   52   import sun.swing.SwingUtilities2.Section;
   53   import static sun.swing.SwingUtilities2.Section.*;
   54   
   55   
   56   /**
   57    * A component that displays a list of objects and allows the user to select
   58    * one or more items. A separate model, {@code ListModel}, maintains the
   59    * contents of the list.
   60    * <p>
   61    * It's easy to display an array or Vector of objects, using the {@code JList}
   62    * constructor that automatically builds a read-only {@code ListModel} instance
   63    * for you:
   64    * <pre>
   65    * {@code
   66    * // Create a JList that displays strings from an array
   67    *
   68    * String[] data = {"one", "two", "three", "four"};
   69    * JList<String> myList = new JList<String>(data);
   70    *
   71    * // Create a JList that displays the superclasses of JList.class, by
   72    * // creating it with a Vector populated with this data
   73    *
   74    * Vector<Class<?>> superClasses = new Vector<Class<?>>();
   75    * Class<JList> rootClass = javax.swing.JList.class;
   76    * for(Class<?> cls = rootClass; cls != null; cls = cls.getSuperclass()) {
   77    *     superClasses.addElement(cls);
   78    * }
   79    * JList<Class<?>> myList = new JList<Class<?>>(superClasses);
   80    *
   81    * // The automatically created model is stored in JList's "model"
   82    * // property, which you can retrieve
   83    *
   84    * ListModel<Class<?>> model = myList.getModel();
   85    * for(int i = 0; i < model.getSize(); i++) {
   86    *     System.out.println(model.getElementAt(i));
   87    * }
   88    * }
   89    * </pre>
   90    * <p>
   91    * A {@code ListModel} can be supplied directly to a {@code JList} by way of a
   92    * constructor or the {@code setModel} method. The contents need not be static -
   93    * the number of items, and the values of items can change over time. A correct
   94    * {@code ListModel} implementation notifies the set of
   95    * {@code javax.swing.event.ListDataListener}s that have been added to it, each
   96    * time a change occurs. These changes are characterized by a
   97    * {@code javax.swing.event.ListDataEvent}, which identifies the range of list
   98    * indices that have been modified, added, or removed. {@code JList}'s
   99    * {@code ListUI} is responsible for keeping the visual representation up to
  100    * date with changes, by listening to the model.
  101    * <p>
  102    * Simple, dynamic-content, {@code JList} applications can use the
  103    * {@code DefaultListModel} class to maintain list elements. This class
  104    * implements the {@code ListModel} interface and also provides a
  105    * <code>java.util.Vector</code>-like API. Applications that need a more
  106    * custom <code>ListModel</code> implementation may instead wish to subclass
  107    * {@code AbstractListModel}, which provides basic support for managing and
  108    * notifying listeners. For example, a read-only implementation of
  109    * {@code AbstractListModel}:
  110    * <pre>
  111    * {@code
  112    * // This list model has about 2^16 elements.  Enjoy scrolling.
  113    *
  114    * ListModel<String> bigData = new AbstractListModel<String>() {
  115    *     public int getSize() { return Short.MAX_VALUE; }
  116    *     public String getElementAt(int index) { return "Index " + index; }
  117    * };
  118    * }
  119    * </pre>
  120    * <p>
  121    * The selection state of a {@code JList} is managed by another separate
  122    * model, an instance of {@code ListSelectionModel}. {@code JList} is
  123    * initialized with a selection model on construction, and also contains
  124    * methods to query or set this selection model. Additionally, {@code JList}
  125    * provides convenient methods for easily managing the selection. These methods,
  126    * such as {@code setSelectedIndex} and {@code getSelectedValue}, are cover
  127    * methods that take care of the details of interacting with the selection
  128    * model. By default, {@code JList}'s selection model is configured to allow any
  129    * combination of items to be selected at a time; selection mode
  130    * {@code MULTIPLE_INTERVAL_SELECTION}. The selection mode can be changed
  131    * on the selection model directly, or via {@code JList}'s cover method.
  132    * Responsibility for updating the selection model in response to user gestures
  133    * lies with the list's {@code ListUI}.
  134    * <p>
  135    * A correct {@code ListSelectionModel} implementation notifies the set of
  136    * {@code javax.swing.event.ListSelectionListener}s that have been added to it
  137    * each time a change to the selection occurs. These changes are characterized
  138    * by a {@code javax.swing.event.ListSelectionEvent}, which identifies the range
  139    * of the selection change.
  140    * <p>
  141    * The preferred way to listen for changes in list selection is to add
  142    * {@code ListSelectionListener}s directly to the {@code JList}. {@code JList}
  143    * then takes care of listening to the the selection model and notifying your
  144    * listeners of change.
  145    * <p>
  146    * Responsibility for listening to selection changes in order to keep the list's
  147    * visual representation up to date lies with the list's {@code ListUI}.
  148    * <p>
  149    * <a name="renderer">
  150    * Painting of cells in a {@code JList} is handled by a delegate called a
  151    * cell renderer, installed on the list as the {@code cellRenderer} property.
  152    * The renderer provides a {@code java.awt.Component} that is used
  153    * like a "rubber stamp" to paint the cells. Each time a cell needs to be
  154    * painted, the list's {@code ListUI} asks the cell renderer for the component,
  155    * moves it into place, and has it paint the contents of the cell by way of its
  156    * {@code paint} method. A default cell renderer, which uses a {@code JLabel}
  157    * component to render, is installed by the lists's {@code ListUI}. You can
  158    * substitute your own renderer using code like this:
  159    * <pre>
  160    * {@code
  161    *  // Display an icon and a string for each object in the list.
  162    *
  163    * class MyCellRenderer extends JLabel implements ListCellRenderer<Object> {
  164    *     final static ImageIcon longIcon = new ImageIcon("long.gif");
  165    *     final static ImageIcon shortIcon = new ImageIcon("short.gif");
  166    *
  167    *     // This is the only method defined by ListCellRenderer.
  168    *     // We just reconfigure the JLabel each time we're called.
  169    *
  170    *     public Component getListCellRendererComponent(
  171    *       JList<?> list,           // the list
  172    *       Object value,            // value to display
  173    *       int index,               // cell index
  174    *       boolean isSelected,      // is the cell selected
  175    *       boolean cellHasFocus)    // does the cell have focus
  176    *     {
  177    *         String s = value.toString();
  178    *         setText(s);
  179    *         setIcon((s.length() > 10) ? longIcon : shortIcon);
  180    *         if (isSelected) {
  181    *             setBackground(list.getSelectionBackground());
  182    *             setForeground(list.getSelectionForeground());
  183    *         } else {
  184    *             setBackground(list.getBackground());
  185    *             setForeground(list.getForeground());
  186    *         }
  187    *         setEnabled(list.isEnabled());
  188    *         setFont(list.getFont());
  189    *         setOpaque(true);
  190    *         return this;
  191    *     }
  192    * }
  193    *
  194    * myList.setCellRenderer(new MyCellRenderer());
  195    * }
  196    * </pre>
  197    * <p>
  198    * Another job for the cell renderer is in helping to determine sizing
  199    * information for the list. By default, the list's {@code ListUI} determines
  200    * the size of cells by asking the cell renderer for its preferred
  201    * size for each list item. This can be expensive for large lists of items.
  202    * To avoid these calculations, you can set a {@code fixedCellWidth} and
  203    * {@code fixedCellHeight} on the list, or have these values calculated
  204    * automatically based on a single prototype value:
  205    * <a name="prototype_example">
  206    * <pre>
  207    * {@code
  208    * JList<String> bigDataList = new JList<String>(bigData);
  209    *
  210    * // We don't want the JList implementation to compute the width
  211    * // or height of all of the list cells, so we give it a string
  212    * // that's as big as we'll need for any cell.  It uses this to
  213    * // compute values for the fixedCellWidth and fixedCellHeight
  214    * // properties.
  215    *
  216    * bigDataList.setPrototypeCellValue("Index 1234567890");
  217    * }
  218    * </pre>
  219    * <p>
  220    * {@code JList} doesn't implement scrolling directly. To create a list that
  221    * scrolls, make it the viewport view of a {@code JScrollPane}. For example:
  222    * <pre>
  223    * JScrollPane scrollPane = new JScrollPane(myList);
  224    *
  225    * // Or in two steps:
  226    * JScrollPane scrollPane = new JScrollPane();
  227    * scrollPane.getViewport().setView(myList);
  228    * </pre>
  229    * <p>
  230    * {@code JList} doesn't provide any special handling of double or triple
  231    * (or N) mouse clicks, but it's easy to add a {@code MouseListener} if you
  232    * wish to take action on these events. Use the {@code locationToIndex}
  233    * method to determine what cell was clicked. For example:
  234    * <pre>
  235    * MouseListener mouseListener = new MouseAdapter() {
  236    *     public void mouseClicked(MouseEvent e) {
  237    *         if (e.getClickCount() == 2) {
  238    *             int index = list.locationToIndex(e.getPoint());
  239    *             System.out.println("Double clicked on Item " + index);
  240    *          }
  241    *     }
  242    * };
  243    * list.addMouseListener(mouseListener);
  244    * </pre>
  245    * <p>
  246    * <strong>Warning:</strong> Swing is not thread safe. For more
  247    * information see <a
  248    * href="package-summary.html#threading">Swing's Threading
  249    * Policy</a>.
  250    * <p>
  251    * <strong>Warning:</strong>
  252    * Serialized objects of this class will not be compatible with
  253    * future Swing releases. The current serialization support is
  254    * appropriate for short term storage or RMI between applications running
  255    * the same version of Swing.  As of 1.4, support for long term storage
  256    * of all JavaBeans<sup><font size="-2">TM</font></sup>
  257    * has been added to the <code>java.beans</code> package.
  258    * Please see {@link java.beans.XMLEncoder}.
  259    * <p>
  260    * See <a href="http://java.sun.com/docs/books/tutorial/uiswing/components/list.html">How to Use Lists</a>
  261    * in <a href="http://java.sun.com/Series/Tutorial/index.html"><em>The Java Tutorial</em></a>
  262    * for further documentation.
  263    * Also see the article <a href="http://java.sun.com/products/jfc/tsc/tech_topics/jlist_1/jlist.html">Advanced JList Programming</a>
  264    * in <a href="http://java.sun.com/products/jfc/tsc"><em>The Swing Connection</em></a>.
  265    * <p>
  266    * @see ListModel
  267    * @see AbstractListModel
  268    * @see DefaultListModel
  269    * @see ListSelectionModel
  270    * @see DefaultListSelectionModel
  271    * @see ListCellRenderer
  272    * @see DefaultListCellRenderer
  273    *
  274    * @param <E> the type of the elements of this list
  275    *
  276    * @beaninfo
  277    *   attribute: isContainer false
  278    * description: A component which allows for the selection of one or more objects from a list.
  279    *
  280    * @author Hans Muller
  281    */
  282   public class JList<E> extends JComponent implements Scrollable, Accessible
  283   {
  284       /**
  285        * @see #getUIClassID
  286        * @see #readObject
  287        */
  288       private static final String uiClassID = "ListUI";
  289   
  290       /**
  291        * Indicates a vertical layout of cells, in a single column;
  292        * the default layout.
  293        * @see #setLayoutOrientation
  294        * @since 1.4
  295        */
  296       public static final int VERTICAL = 0;
  297   
  298       /**
  299        * Indicates a "newspaper style" layout with cells flowing vertically
  300        * then horizontally.
  301        * @see #setLayoutOrientation
  302        * @since 1.4
  303        */
  304       public static final int VERTICAL_WRAP = 1;
  305   
  306       /**
  307        * Indicates a "newspaper style" layout with cells flowing horizontally
  308        * then vertically.
  309        * @see #setLayoutOrientation
  310        * @since 1.4
  311        */
  312       public static final int HORIZONTAL_WRAP = 2;
  313   
  314       private int fixedCellWidth = -1;
  315       private int fixedCellHeight = -1;
  316       private int horizontalScrollIncrement = -1;
  317       private E prototypeCellValue;
  318       private int visibleRowCount = 8;
  319       private Color selectionForeground;
  320       private Color selectionBackground;
  321       private boolean dragEnabled;
  322   
  323       private ListSelectionModel selectionModel;
  324       private ListModel<E> dataModel;
  325       private ListCellRenderer<? super E> cellRenderer;
  326       private ListSelectionListener selectionListener;
  327   
  328       /**
  329        * How to lay out the cells; defaults to <code>VERTICAL</code>.
  330        */
  331       private int layoutOrientation;
  332   
  333       /**
  334        * The drop mode for this component.
  335        */
  336       private DropMode dropMode = DropMode.USE_SELECTION;
  337   
  338       /**
  339        * The drop location.
  340        */
  341       private transient DropLocation dropLocation;
  342   
  343       /**
  344        * A subclass of <code>TransferHandler.DropLocation</code> representing
  345        * a drop location for a <code>JList</code>.
  346        *
  347        * @see #getDropLocation
  348        * @since 1.6
  349        */
  350       public static final class DropLocation extends TransferHandler.DropLocation {
  351           private final int index;
  352           private final boolean isInsert;
  353   
  354           private DropLocation(Point p, int index, boolean isInsert) {
  355               super(p);
  356               this.index = index;
  357               this.isInsert = isInsert;
  358           }
  359   
  360           /**
  361            * Returns the index where dropped data should be placed in the
  362            * list. Interpretation of the value depends on the drop mode set on
  363            * the associated component. If the drop mode is either
  364            * <code>DropMode.USE_SELECTION</code> or <code>DropMode.ON</code>,
  365            * the return value is an index of a row in the list. If the drop mode is
  366            * <code>DropMode.INSERT</code>, the return value refers to the index
  367            * where the data should be inserted. If the drop mode is
  368            * <code>DropMode.ON_OR_INSERT</code>, the value of
  369            * <code>isInsert()</code> indicates whether the index is an index
  370            * of a row, or an insert index.
  371            * <p>
  372            * <code>-1</code> indicates that the drop occurred over empty space,
  373            * and no index could be calculated.
  374            *
  375            * @return the drop index
  376            */
  377           public int getIndex() {
  378               return index;
  379           }
  380   
  381           /**
  382            * Returns whether or not this location represents an insert
  383            * location.
  384            *
  385            * @return whether or not this is an insert location
  386            */
  387           public boolean isInsert() {
  388               return isInsert;
  389           }
  390   
  391           /**
  392            * Returns a string representation of this drop location.
  393            * This method is intended to be used for debugging purposes,
  394            * and the content and format of the returned string may vary
  395            * between implementations.
  396            *
  397            * @return a string representation of this drop location
  398            */
  399           public String toString() {
  400               return getClass().getName()
  401                      + "[dropPoint=" + getDropPoint() + ","
  402                      + "index=" + index + ","
  403                      + "insert=" + isInsert + "]";
  404           }
  405       }
  406   
  407       /**
  408        * Constructs a {@code JList} that displays elements from the specified,
  409        * {@code non-null}, model. All {@code JList} constructors delegate to
  410        * this one.
  411        * <p>
  412        * This constructor registers the list with the {@code ToolTipManager},
  413        * allowing for tooltips to be provided by the cell renderers.
  414        *
  415        * @param dataModel the model for the list
  416        * @exception IllegalArgumentException if the model is {@code null}
  417        */
  418       public JList(ListModel<E> dataModel)
  419       {
  420           if (dataModel == null) {
  421               throw new IllegalArgumentException("dataModel must be non null");
  422           }
  423   
  424           // Register with the ToolTipManager so that tooltips from the
  425           // renderer show through.
  426           ToolTipManager toolTipManager = ToolTipManager.sharedInstance();
  427           toolTipManager.registerComponent(this);
  428   
  429           layoutOrientation = VERTICAL;
  430   
  431           this.dataModel = dataModel;
  432           selectionModel = createSelectionModel();
  433           setAutoscrolls(true);
  434           setOpaque(true);
  435           updateUI();
  436       }
  437   
  438   
  439       /**
  440        * Constructs a <code>JList</code> that displays the elements in
  441        * the specified array. This constructor creates a read-only model
  442        * for the given array, and then delegates to the constructor that
  443        * takes a {@code ListModel}.
  444        * <p>
  445        * Attempts to pass a {@code null} value to this method results in
  446        * undefined behavior and, most likely, exceptions. The created model
  447        * references the given array directly. Attempts to modify the array
  448        * after constructing the list results in undefined behavior.
  449        *
  450        * @param  listData  the array of Objects to be loaded into the data model,
  451        *                   {@code non-null}
  452        */
  453       public JList(final E[] listData)
  454       {
  455           this (
  456               new AbstractListModel<E>() {
  457                   public int getSize() { return listData.length; }
  458                   public E getElementAt(int i) { return listData[i]; }
  459               }
  460           );
  461       }
  462   
  463   
  464       /**
  465        * Constructs a <code>JList</code> that displays the elements in
  466        * the specified <code>Vector</code>. This constructor creates a read-only
  467        * model for the given {@code Vector}, and then delegates to the constructor
  468        * that takes a {@code ListModel}.
  469        * <p>
  470        * Attempts to pass a {@code null} value to this method results in
  471        * undefined behavior and, most likely, exceptions. The created model
  472        * references the given {@code Vector} directly. Attempts to modify the
  473        * {@code Vector} after constructing the list results in undefined behavior.
  474        *
  475        * @param  listData  the <code>Vector</code> to be loaded into the
  476        *                   data model, {@code non-null}
  477        */
  478       public JList(final Vector<? extends E> listData) {
  479           this (
  480               new AbstractListModel<E>() {
  481                   public int getSize() { return listData.size(); }
  482                   public E getElementAt(int i) { return listData.elementAt(i); }
  483               }
  484           );
  485       }
  486   
  487   
  488       /**
  489        * Constructs a <code>JList</code> with an empty, read-only, model.
  490        */
  491       public JList() {
  492           this (
  493               new AbstractListModel<E>() {
  494                 public int getSize() { return 0; }
  495                 public E getElementAt(int i) { throw new IndexOutOfBoundsException("No Data Model"); }
  496               }
  497           );
  498       }
  499   
  500   
  501       /**
  502        * Returns the {@code ListUI}, the look and feel object that
  503        * renders this component.
  504        *
  505        * @return the <code>ListUI</code> object that renders this component
  506        */
  507       public ListUI getUI() {
  508           return (ListUI)ui;
  509       }
  510   
  511   
  512       /**
  513        * Sets the {@code ListUI}, the look and feel object that
  514        * renders this component.
  515        *
  516        * @param ui  the <code>ListUI</code> object
  517        * @see UIDefaults#getUI
  518        * @beaninfo
  519        *        bound: true
  520        *       hidden: true
  521        *    attribute: visualUpdate true
  522        *  description: The UI object that implements the Component's LookAndFeel.
  523        */
  524       public void setUI(ListUI ui) {
  525           super.setUI(ui);
  526       }
  527   
  528   
  529       /**
  530        * Resets the {@code ListUI} property by setting it to the value provided
  531        * by the current look and feel. If the current cell renderer was installed
  532        * by the developer (rather than the look and feel itself), this also causes
  533        * the cell renderer and its children to be updated, by calling
  534        * {@code SwingUtilities.updateComponentTreeUI} on it.
  535        *
  536        * @see UIManager#getUI
  537        * @see SwingUtilities#updateComponentTreeUI
  538        */
  539       public void updateUI() {
  540           setUI((ListUI)UIManager.getUI(this));
  541   
  542           ListCellRenderer<? super E> renderer = getCellRenderer();
  543           if (renderer instanceof Component) {
  544               SwingUtilities.updateComponentTreeUI((Component)renderer);
  545           }
  546       }
  547   
  548   
  549       /**
  550        * Returns {@code "ListUI"}, the <code>UIDefaults</code> key used to look
  551        * up the name of the {@code javax.swing.plaf.ListUI} class that defines
  552        * the look and feel for this component.
  553        *
  554        * @return the string "ListUI"
  555        * @see JComponent#getUIClassID
  556        * @see UIDefaults#getUI
  557        */
  558       public String getUIClassID() {
  559           return uiClassID;
  560       }
  561   
  562   
  563       /* -----private-----
  564        * This method is called by setPrototypeCellValue and setCellRenderer
  565        * to update the fixedCellWidth and fixedCellHeight properties from the
  566        * current value of prototypeCellValue (if it's non null).
  567        * <p>
  568        * This method sets fixedCellWidth and fixedCellHeight but does <b>not</b>
  569        * generate PropertyChangeEvents for them.
  570        *
  571        * @see #setPrototypeCellValue
  572        * @see #setCellRenderer
  573        */
  574       private void updateFixedCellSize()
  575       {
  576           ListCellRenderer<? super E> cr = getCellRenderer();
  577           E value = getPrototypeCellValue();
  578   
  579           if ((cr != null) && (value != null)) {
  580               Component c = cr.getListCellRendererComponent(this, value, 0, false, false);
  581   
  582               /* The ListUI implementation will add Component c to its private
  583                * CellRendererPane however we can't assume that's already
  584                * been done here.  So we temporarily set the one "inherited"
  585                * property that may affect the renderer components preferred size:
  586                * its font.
  587                */
  588               Font f = c.getFont();
  589               c.setFont(getFont());
  590   
  591               Dimension d = c.getPreferredSize();
  592               fixedCellWidth = d.width;
  593               fixedCellHeight = d.height;
  594   
  595               c.setFont(f);
  596           }
  597       }
  598   
  599   
  600       /**
  601        * Returns the "prototypical" cell value -- a value used to calculate a
  602        * fixed width and height for cells. This can be {@code null} if there
  603        * is no such value.
  604        *
  605        * @return the value of the {@code prototypeCellValue} property
  606        * @see #setPrototypeCellValue
  607        */
  608       public E getPrototypeCellValue() {
  609           return prototypeCellValue;
  610       }
  611   
  612       /**
  613        * Sets the {@code prototypeCellValue} property, and then (if the new value
  614        * is {@code non-null}), computes the {@code fixedCellWidth} and
  615        * {@code fixedCellHeight} properties by requesting the cell renderer
  616        * component for the given value (and index 0) from the cell renderer, and
  617        * using that component's preferred size.
  618        * <p>
  619        * This method is useful when the list is too long to allow the
  620        * {@code ListUI} to compute the width/height of each cell, and there is a
  621        * single cell value that is known to occupy as much space as any of the
  622        * others, a so-called prototype.
  623        * <p>
  624        * While all three of the {@code prototypeCellValue},
  625        * {@code fixedCellHeight}, and {@code fixedCellWidth} properties may be
  626        * modified by this method, {@code PropertyChangeEvent} notifications are
  627        * only sent when the {@code prototypeCellValue} property changes.
  628        * <p>
  629        * To see an example which sets this property, see the
  630        * <a href="#prototype_example">class description</a> above.
  631        * <p>
  632        * The default value of this property is <code>null</code>.
  633        * <p>
  634        * This is a JavaBeans bound property.
  635        *
  636        * @param prototypeCellValue  the value on which to base
  637        *                          <code>fixedCellWidth</code> and
  638        *                          <code>fixedCellHeight</code>
  639        * @see #getPrototypeCellValue
  640        * @see #setFixedCellWidth
  641        * @see #setFixedCellHeight
  642        * @see JComponent#addPropertyChangeListener
  643        * @beaninfo
  644        *       bound: true
  645        *   attribute: visualUpdate true
  646        * description: The cell prototype value, used to compute cell width and height.
  647        */
  648       public void setPrototypeCellValue(E prototypeCellValue) {
  649           E oldValue = this.prototypeCellValue;
  650           this.prototypeCellValue = prototypeCellValue;
  651   
  652           /* If the prototypeCellValue has changed and is non-null,
  653            * then recompute fixedCellWidth and fixedCellHeight.
  654            */
  655   
  656           if ((prototypeCellValue != null) && !prototypeCellValue.equals(oldValue)) {
  657               updateFixedCellSize();
  658           }
  659   
  660           firePropertyChange("prototypeCellValue", oldValue, prototypeCellValue);
  661       }
  662   
  663   
  664       /**
  665        * Returns the value of the {@code fixedCellWidth} property.
  666        *
  667        * @return the fixed cell width
  668        * @see #setFixedCellWidth
  669        */
  670       public int getFixedCellWidth() {
  671           return fixedCellWidth;
  672       }
  673   
  674       /**
  675        * Sets a fixed value to be used for the width of every cell in the list.
  676        * If {@code width} is -1, cell widths are computed in the {@code ListUI}
  677        * by applying <code>getPreferredSize</code> to the cell renderer component
  678        * for each list element.
  679        * <p>
  680        * The default value of this property is {@code -1}.
  681        * <p>
  682        * This is a JavaBeans bound property.
  683        *
  684        * @param width the width to be used for all cells in the list
  685        * @see #setPrototypeCellValue
  686        * @see #setFixedCellWidth
  687        * @see JComponent#addPropertyChangeListener
  688        * @beaninfo
  689        *       bound: true
  690        *   attribute: visualUpdate true
  691        * description: Defines a fixed cell width when greater than zero.
  692        */
  693       public void setFixedCellWidth(int width) {
  694           int oldValue = fixedCellWidth;
  695           fixedCellWidth = width;
  696           firePropertyChange("fixedCellWidth", oldValue, fixedCellWidth);
  697       }
  698   
  699   
  700       /**
  701        * Returns the value of the {@code fixedCellHeight} property.
  702        *
  703        * @return the fixed cell height
  704        * @see #setFixedCellHeight
  705        */
  706       public int getFixedCellHeight() {
  707           return fixedCellHeight;
  708       }
  709   
  710       /**
  711        * Sets a fixed value to be used for the height of every cell in the list.
  712        * If {@code height} is -1, cell heights are computed in the {@code ListUI}
  713        * by applying <code>getPreferredSize</code> to the cell renderer component
  714        * for each list element.
  715        * <p>
  716        * The default value of this property is {@code -1}.
  717        * <p>
  718        * This is a JavaBeans bound property.
  719        *
  720        * @param height the height to be used for for all cells in the list
  721        * @see #setPrototypeCellValue
  722        * @see #setFixedCellWidth
  723        * @see JComponent#addPropertyChangeListener
  724        * @beaninfo
  725        *       bound: true
  726        *   attribute: visualUpdate true
  727        * description: Defines a fixed cell height when greater than zero.
  728        */
  729       public void setFixedCellHeight(int height) {
  730           int oldValue = fixedCellHeight;
  731           fixedCellHeight = height;
  732           firePropertyChange("fixedCellHeight", oldValue, fixedCellHeight);
  733       }
  734   
  735   
  736       /**
  737        * Returns the object responsible for painting list items.
  738        *
  739        * @return the value of the {@code cellRenderer} property
  740        * @see #setCellRenderer
  741        */
  742       @Transient
  743       public ListCellRenderer<? super E> getCellRenderer() {
  744           return cellRenderer;
  745       }
  746   
  747       /**
  748        * Sets the delegate that is used to paint each cell in the list.
  749        * The job of a cell renderer is discussed in detail in the
  750        * <a href="#renderer">class level documentation</a>.
  751        * <p>
  752        * If the {@code prototypeCellValue} property is {@code non-null},
  753        * setting the cell renderer also causes the {@code fixedCellWidth} and
  754        * {@code fixedCellHeight} properties to be re-calculated. Only one
  755        * <code>PropertyChangeEvent</code> is generated however -
  756        * for the <code>cellRenderer</code> property.
  757        * <p>
  758        * The default value of this property is provided by the {@code ListUI}
  759        * delegate, i.e. by the look and feel implementation.
  760        * <p>
  761        * This is a JavaBeans bound property.
  762        *
  763        * @param cellRenderer the <code>ListCellRenderer</code>
  764        *                          that paints list cells
  765        * @see #getCellRenderer
  766        * @beaninfo
  767        *       bound: true
  768        *   attribute: visualUpdate true
  769        * description: The component used to draw the cells.
  770        */
  771       public void setCellRenderer(ListCellRenderer<? super E> cellRenderer) {
  772           ListCellRenderer<? super E> oldValue = this.cellRenderer;
  773           this.cellRenderer = cellRenderer;
  774   
  775           /* If the cellRenderer has changed and prototypeCellValue
  776            * was set, then recompute fixedCellWidth and fixedCellHeight.
  777            */
  778           if ((cellRenderer != null) && !cellRenderer.equals(oldValue)) {
  779               updateFixedCellSize();
  780           }
  781   
  782           firePropertyChange("cellRenderer", oldValue, cellRenderer);
  783       }
  784   
  785   
  786       /**
  787        * Returns the color used to draw the foreground of selected items.
  788        * {@code DefaultListCellRenderer} uses this color to draw the foreground
  789        * of items in the selected state, as do the renderers installed by most
  790        * {@code ListUI} implementations.
  791        *
  792        * @return the color to draw the foreground of selected items
  793        * @see #setSelectionForeground
  794        * @see DefaultListCellRenderer
  795        */
  796       public Color getSelectionForeground() {
  797           return selectionForeground;
  798       }
  799   
  800   
  801       /**
  802        * Sets the color used to draw the foreground of selected items, which
  803        * cell renderers can use to render text and graphics.
  804        * {@code DefaultListCellRenderer} uses this color to draw the foreground
  805        * of items in the selected state, as do the renderers installed by most
  806        * {@code ListUI} implementations.
  807        * <p>
  808        * The default value of this property is defined by the look and feel
  809        * implementation.
  810        * <p>
  811        * This is a JavaBeans bound property.
  812        *
  813        * @param selectionForeground  the {@code Color} to use in the foreground
  814        *                             for selected list items
  815        * @see #getSelectionForeground
  816        * @see #setSelectionBackground
  817        * @see #setForeground
  818        * @see #setBackground
  819        * @see #setFont
  820        * @see DefaultListCellRenderer
  821        * @beaninfo
  822        *       bound: true
  823        *   attribute: visualUpdate true
  824        * description: The foreground color of selected cells.
  825        */
  826       public void setSelectionForeground(Color selectionForeground) {
  827           Color oldValue = this.selectionForeground;
  828           this.selectionForeground = selectionForeground;
  829           firePropertyChange("selectionForeground", oldValue, selectionForeground);
  830       }
  831   
  832   
  833       /**
  834        * Returns the color used to draw the background of selected items.
  835        * {@code DefaultListCellRenderer} uses this color to draw the background
  836        * of items in the selected state, as do the renderers installed by most
  837        * {@code ListUI} implementations.
  838        *
  839        * @return the color to draw the background of selected items
  840        * @see #setSelectionBackground
  841        * @see DefaultListCellRenderer
  842        */
  843       public Color getSelectionBackground() {
  844           return selectionBackground;
  845       }
  846   
  847   
  848       /**
  849        * Sets the color used to draw the background of selected items, which
  850        * cell renderers can use fill selected cells.
  851        * {@code DefaultListCellRenderer} uses this color to fill the background
  852        * of items in the selected state, as do the renderers installed by most
  853        * {@code ListUI} implementations.
  854        * <p>
  855        * The default value of this property is defined by the look
  856        * and feel implementation.
  857        * <p>
  858        * This is a JavaBeans bound property.
  859        *
  860        * @param selectionBackground  the {@code Color} to use for the
  861        *                             background of selected cells
  862        * @see #getSelectionBackground
  863        * @see #setSelectionForeground
  864        * @see #setForeground
  865        * @see #setBackground
  866        * @see #setFont
  867        * @see DefaultListCellRenderer
  868        * @beaninfo
  869        *       bound: true
  870        *   attribute: visualUpdate true
  871        * description: The background color of selected cells.
  872        */
  873       public void setSelectionBackground(Color selectionBackground) {
  874           Color oldValue = this.selectionBackground;
  875           this.selectionBackground = selectionBackground;
  876           firePropertyChange("selectionBackground", oldValue, selectionBackground);
  877       }
  878   
  879   
  880       /**
  881        * Returns the value of the {@code visibleRowCount} property. See the
  882        * documentation for {@link #setVisibleRowCount} for details on how to
  883        * interpret this value.
  884        *
  885        * @return the value of the {@code visibleRowCount} property.
  886        * @see #setVisibleRowCount
  887        */
  888       public int getVisibleRowCount() {
  889           return visibleRowCount;
  890       }
  891   
  892       /**
  893        * Sets the {@code visibleRowCount} property, which has different meanings
  894        * depending on the layout orientation: For a {@code VERTICAL} layout
  895        * orientation, this sets the preferred number of rows to display without
  896        * requiring scrolling; for other orientations, it affects the wrapping of
  897        * cells.
  898        * <p>
  899        * In {@code VERTICAL} orientation:<br>
  900        * Setting this property affects the return value of the
  901        * {@link #getPreferredScrollableViewportSize} method, which is used to
  902        * calculate the preferred size of an enclosing viewport. See that method's
  903        * documentation for more details.
  904        * <p>
  905        * In {@code HORIZONTAL_WRAP} and {@code VERTICAL_WRAP} orientations:<br>
  906        * This affects how cells are wrapped. See the documentation of
  907        * {@link #setLayoutOrientation} for more details.
  908        * <p>
  909        * The default value of this property is {@code 8}.
  910        * <p>
  911        * Calling this method with a negative value results in the property
  912        * being set to {@code 0}.
  913        * <p>
  914        * This is a JavaBeans bound property.
  915        *
  916        * @param visibleRowCount  an integer specifying the preferred number of
  917        *                         rows to display without requiring scrolling
  918        * @see #getVisibleRowCount
  919        * @see #getPreferredScrollableViewportSize
  920        * @see #setLayoutOrientation
  921        * @see JComponent#getVisibleRect
  922        * @see JViewport
  923        * @beaninfo
  924        *       bound: true
  925        *   attribute: visualUpdate true
  926        * description: The preferred number of rows to display without
  927        *              requiring scrolling
  928        */
  929       public void setVisibleRowCount(int visibleRowCount) {
  930           int oldValue = this.visibleRowCount;
  931           this.visibleRowCount = Math.max(0, visibleRowCount);
  932           firePropertyChange("visibleRowCount", oldValue, visibleRowCount);
  933       }
  934   
  935   
  936       /**
  937        * Returns the layout orientation property for the list: {@code VERTICAL}
  938        * if the layout is a single column of cells, {@code VERTICAL_WRAP} if the
  939        * layout is "newspaper style" with the content flowing vertically then
  940        * horizontally, or {@code HORIZONTAL_WRAP} if the layout is "newspaper
  941        * style" with the content flowing horizontally then vertically.
  942        *
  943        * @return the value of the {@code layoutOrientation} property
  944        * @see #setLayoutOrientation
  945        * @since 1.4
  946        */
  947       public int getLayoutOrientation() {
  948           return layoutOrientation;
  949       }
  950   
  951   
  952       /**
  953        * Defines the way list cells are layed out. Consider a {@code JList}
  954        * with five cells. Cells can be layed out in one of the following ways:
  955        * <p>
  956        * <pre>
  957        * VERTICAL:          0
  958        *                    1
  959        *                    2
  960        *                    3
  961        *                    4
  962        *
  963        * HORIZONTAL_WRAP:   0  1  2
  964        *                    3  4
  965        *
  966        * VERTICAL_WRAP:     0  3
  967        *                    1  4
  968        *                    2
  969        * </pre>
  970        * <p>
  971        * A description of these layouts follows:
  972        *
  973        * <table border="1"
  974        *  summary="Describes layouts VERTICAL, HORIZONTAL_WRAP, and VERTICAL_WRAP">
  975        *   <tr><th><p align="left">Value</p></th><th><p align="left">Description</p></th></tr>
  976        *   <tr><td><code>VERTICAL</code>
  977        *       <td>Cells are layed out vertically in a single column.
  978        *   <tr><td><code>HORIZONTAL_WRAP</code>
  979        *       <td>Cells are layed out horizontally, wrapping to a new row as
  980        *           necessary. If the {@code visibleRowCount} property is less than
  981        *           or equal to zero, wrapping is determined by the width of the
  982        *           list; otherwise wrapping is done in such a way as to ensure
  983        *           {@code visibleRowCount} rows in the list.
  984        *   <tr><td><code>VERTICAL_WRAP</code>
  985        *       <td>Cells are layed out vertically, wrapping to a new column as
  986        *           necessary. If the {@code visibleRowCount} property is less than
  987        *           or equal to zero, wrapping is determined by the height of the
  988        *           list; otherwise wrapping is done at {@code visibleRowCount} rows.
  989        *  </table>
  990        * <p>
  991        * The default value of this property is <code>VERTICAL</code>.
  992        *
  993        * @param layoutOrientation the new layout orientation, one of:
  994        *        {@code VERTICAL}, {@code HORIZONTAL_WRAP} or {@code VERTICAL_WRAP}
  995        * @see #getLayoutOrientation
  996        * @see #setVisibleRowCount
  997        * @see #getScrollableTracksViewportHeight
  998        * @see #getScrollableTracksViewportWidth
  999        * @throws IllegalArgumentException if {@code layoutOrientation} isn't one of the
 1000        *         allowable values
 1001        * @since 1.4
 1002        * @beaninfo
 1003        *       bound: true
 1004        *   attribute: visualUpdate true
 1005        * description: Defines the way list cells are layed out.
 1006        *        enum: VERTICAL JList.VERTICAL
 1007        *              HORIZONTAL_WRAP JList.HORIZONTAL_WRAP
 1008        *              VERTICAL_WRAP JList.VERTICAL_WRAP
 1009        */
 1010       public void setLayoutOrientation(int layoutOrientation) {
 1011           int oldValue = this.layoutOrientation;
 1012           switch (layoutOrientation) {
 1013           case VERTICAL:
 1014           case VERTICAL_WRAP:
 1015           case HORIZONTAL_WRAP:
 1016               this.layoutOrientation = layoutOrientation;
 1017               firePropertyChange("layoutOrientation", oldValue, layoutOrientation);
 1018               break;
 1019           default:
 1020               throw new IllegalArgumentException("layoutOrientation must be one of: VERTICAL, HORIZONTAL_WRAP or VERTICAL_WRAP");
 1021           }
 1022       }
 1023   
 1024   
 1025       /**
 1026        * Returns the smallest list index that is currently visible.
 1027        * In a left-to-right {@code componentOrientation}, the first visible
 1028        * cell is found closest to the list's upper-left corner. In right-to-left
 1029        * orientation, it is found closest to the upper-right corner.
 1030        * If nothing is visible or the list is empty, {@code -1} is returned.
 1031        * Note that the returned cell may only be partially visible.
 1032        *
 1033        * @return the index of the first visible cell
 1034        * @see #getLastVisibleIndex
 1035        * @see JComponent#getVisibleRect
 1036        */
 1037       public int getFirstVisibleIndex() {
 1038           Rectangle r = getVisibleRect();
 1039           int first;
 1040           if (this.getComponentOrientation().isLeftToRight()) {
 1041               first = locationToIndex(r.getLocation());
 1042           } else {
 1043               first = locationToIndex(new Point((r.x + r.width) - 1, r.y));
 1044           }
 1045           if (first != -1) {
 1046               Rectangle bounds = getCellBounds(first, first);
 1047               if (bounds != null) {
 1048                   SwingUtilities.computeIntersection(r.x, r.y, r.width, r.height, bounds);
 1049                   if (bounds.width == 0 || bounds.height == 0) {
 1050                       first = -1;
 1051                   }
 1052               }
 1053           }
 1054           return first;
 1055       }
 1056   
 1057   
 1058       /**
 1059        * Returns the largest list index that is currently visible.
 1060        * If nothing is visible or the list is empty, {@code -1} is returned.
 1061        * Note that the returned cell may only be partially visible.
 1062        *
 1063        * @return the index of the last visible cell
 1064        * @see #getFirstVisibleIndex
 1065        * @see JComponent#getVisibleRect
 1066        */
 1067       public int getLastVisibleIndex() {
 1068           boolean leftToRight = this.getComponentOrientation().isLeftToRight();
 1069           Rectangle r = getVisibleRect();
 1070           Point lastPoint;
 1071           if (leftToRight) {
 1072               lastPoint = new Point((r.x + r.width) - 1, (r.y + r.height) - 1);
 1073           } else {
 1074               lastPoint = new Point(r.x, (r.y + r.height) - 1);
 1075           }
 1076           int location = locationToIndex(lastPoint);
 1077   
 1078           if (location != -1) {
 1079               Rectangle bounds = getCellBounds(location, location);
 1080   
 1081               if (bounds != null) {
 1082                   SwingUtilities.computeIntersection(r.x, r.y, r.width, r.height, bounds);
 1083                   if (bounds.width == 0 || bounds.height == 0) {
 1084                       // Try the top left(LTR) or top right(RTL) corner, and
 1085                       // then go across checking each cell for HORIZONTAL_WRAP.
 1086                       // Try the lower left corner, and then go across checking
 1087                       // each cell for other list layout orientation.
 1088                       boolean isHorizontalWrap =
 1089                           (getLayoutOrientation() == HORIZONTAL_WRAP);
 1090                       Point visibleLocation = isHorizontalWrap ?
 1091                           new Point(lastPoint.x, r.y) :
 1092                           new Point(r.x, lastPoint.y);
 1093                       int last;
 1094                       int visIndex = -1;
 1095                       int lIndex = location;
 1096                       location = -1;
 1097   
 1098                       do {
 1099                           last = visIndex;
 1100                           visIndex = locationToIndex(visibleLocation);
 1101   
 1102                           if (visIndex != -1) {
 1103                               bounds = getCellBounds(visIndex, visIndex);
 1104                               if (visIndex != lIndex && bounds != null &&
 1105                                   bounds.contains(visibleLocation)) {
 1106                                   location = visIndex;
 1107                                   if (isHorizontalWrap) {
 1108                                       visibleLocation.y = bounds.y + bounds.height;
 1109                                       if (visibleLocation.y >= lastPoint.y) {
 1110                                           // Past visible region, bail.
 1111                                           last = visIndex;
 1112                                       }
 1113                                   }
 1114                                   else {
 1115                                       visibleLocation.x = bounds.x + bounds.width;
 1116                                       if (visibleLocation.x >= lastPoint.x) {
 1117                                           // Past visible region, bail.
 1118                                           last = visIndex;
 1119                                       }
 1120                                   }
 1121   
 1122                               }
 1123                               else {
 1124                                   last = visIndex;
 1125                               }
 1126                           }
 1127                       } while (visIndex != -1 && last != visIndex);
 1128                   }
 1129               }
 1130           }
 1131           return location;
 1132       }
 1133   
 1134   
 1135       /**
 1136        * Scrolls the list within an enclosing viewport to make the specified
 1137        * cell completely visible. This calls {@code scrollRectToVisible} with
 1138        * the bounds of the specified cell. For this method to work, the
 1139        * {@code JList} must be within a <code>JViewport</code>.
 1140        * <p>
 1141        * If the given index is outside the list's range of cells, this method
 1142        * results in nothing.
 1143        *
 1144        * @param index  the index of the cell to make visible
 1145        * @see JComponent#scrollRectToVisible
 1146        * @see #getVisibleRect
 1147        */
 1148       public void ensureIndexIsVisible(int index) {
 1149           Rectangle cellBounds = getCellBounds(index, index);
 1150           if (cellBounds != null) {
 1151               scrollRectToVisible(cellBounds);
 1152           }
 1153       }
 1154   
 1155       /**
 1156        * Turns on or off automatic drag handling. In order to enable automatic
 1157        * drag handling, this property should be set to {@code true}, and the
 1158        * list's {@code TransferHandler} needs to be {@code non-null}.
 1159        * The default value of the {@code dragEnabled} property is {@code false}.
 1160        * <p>
 1161        * The job of honoring this property, and recognizing a user drag gesture,
 1162        * lies with the look and feel implementation, and in particular, the list's
 1163        * {@code ListUI}. When automatic drag handling is enabled, most look and
 1164        * feels (including those that subclass {@code BasicLookAndFeel}) begin a
 1165        * drag and drop operation whenever the user presses the mouse button over
 1166        * an item and then moves the mouse a few pixels. Setting this property to
 1167        * {@code true} can therefore have a subtle effect on how selections behave.
 1168        * <p>
 1169        * If a look and feel is used that ignores this property, you can still
 1170        * begin a drag and drop operation by calling {@code exportAsDrag} on the
 1171        * list's {@code TransferHandler}.
 1172        *
 1173        * @param b whether or not to enable automatic drag handling
 1174        * @exception HeadlessException if
 1175        *            <code>b</code> is <code>true</code> and
 1176        *            <code>GraphicsEnvironment.isHeadless()</code>
 1177        *            returns <code>true</code>
 1178        * @see java.awt.GraphicsEnvironment#isHeadless
 1179        * @see #getDragEnabled
 1180        * @see #setTransferHandler
 1181        * @see TransferHandler
 1182        * @since 1.4
 1183        *
 1184        * @beaninfo
 1185        *  description: determines whether automatic drag handling is enabled
 1186        *        bound: false
 1187        */
 1188       public void setDragEnabled(boolean b) {
 1189           if (b && GraphicsEnvironment.isHeadless()) {
 1190               throw new HeadlessException();
 1191           }
 1192           dragEnabled = b;
 1193       }
 1194   
 1195       /**
 1196        * Returns whether or not automatic drag handling is enabled.
 1197        *
 1198        * @return the value of the {@code dragEnabled} property
 1199        * @see #setDragEnabled
 1200        * @since 1.4
 1201        */
 1202       public boolean getDragEnabled() {
 1203           return dragEnabled;
 1204       }
 1205   
 1206       /**
 1207        * Sets the drop mode for this component. For backward compatibility,
 1208        * the default for this property is <code>DropMode.USE_SELECTION</code>.
 1209        * Usage of one of the other modes is recommended, however, for an
 1210        * improved user experience. <code>DropMode.ON</code>, for instance,
 1211        * offers similar behavior of showing items as selected, but does so without
 1212        * affecting the actual selection in the list.
 1213        * <p>
 1214        * <code>JList</code> supports the following drop modes:
 1215        * <ul>
 1216        *    <li><code>DropMode.USE_SELECTION</code></li>
 1217        *    <li><code>DropMode.ON</code></li>
 1218        *    <li><code>DropMode.INSERT</code></li>
 1219        *    <li><code>DropMode.ON_OR_INSERT</code></li>
 1220        * </ul>
 1221        * The drop mode is only meaningful if this component has a
 1222        * <code>TransferHandler</code> that accepts drops.
 1223        *
 1224        * @param dropMode the drop mode to use
 1225        * @throws IllegalArgumentException if the drop mode is unsupported
 1226        *         or <code>null</code>
 1227        * @see #getDropMode
 1228        * @see #getDropLocation
 1229        * @see #setTransferHandler
 1230        * @see TransferHandler
 1231        * @since 1.6
 1232        */
 1233       public final void setDropMode(DropMode dropMode) {
 1234           if (dropMode != null) {
 1235               switch (dropMode) {
 1236                   case USE_SELECTION:
 1237                   case ON:
 1238                   case INSERT:
 1239                   case ON_OR_INSERT:
 1240                       this.dropMode = dropMode;
 1241                       return;
 1242               }
 1243           }
 1244   
 1245           throw new IllegalArgumentException(dropMode + ": Unsupported drop mode for list");
 1246       }
 1247   
 1248       /**
 1249        * Returns the drop mode for this component.
 1250        *
 1251        * @return the drop mode for this component
 1252        * @see #setDropMode
 1253        * @since 1.6
 1254        */
 1255       public final DropMode getDropMode() {
 1256           return dropMode;
 1257       }
 1258   
 1259       /**
 1260        * Calculates a drop location in this component, representing where a
 1261        * drop at the given point should insert data.
 1262        *
 1263        * @param p the point to calculate a drop location for
 1264        * @return the drop location, or <code>null</code>
 1265        */
 1266       DropLocation dropLocationForPoint(Point p) {
 1267           DropLocation location = null;
 1268           Rectangle rect = null;
 1269   
 1270           int index = locationToIndex(p);
 1271           if (index != -1) {
 1272               rect = getCellBounds(index, index);
 1273           }
 1274   
 1275           switch(dropMode) {
 1276               case USE_SELECTION:
 1277               case ON:
 1278                   location = new DropLocation(p,
 1279                       (rect != null && rect.contains(p)) ? index : -1,
 1280                       false);
 1281   
 1282                   break;
 1283               case INSERT:
 1284                   if (index == -1) {
 1285                       location = new DropLocation(p, getModel().getSize(), true);
 1286                       break;
 1287                   }
 1288   
 1289                   if (layoutOrientation == HORIZONTAL_WRAP) {
 1290                       boolean ltr = getComponentOrientation().isLeftToRight();
 1291   
 1292                       if (SwingUtilities2.liesInHorizontal(rect, p, ltr, false) == TRAILING) {
 1293                           index++;
 1294                       // special case for below all cells
 1295                       } else if (index == getModel().getSize() - 1 && p.y >= rect.y + rect.height) {
 1296                           index++;
 1297                       }
 1298                   } else {
 1299                       if (SwingUtilities2.liesInVertical(rect, p, false) == TRAILING) {
 1300                           index++;
 1301                       }
 1302                   }
 1303   
 1304                   location = new DropLocation(p, index, true);
 1305   
 1306                   break;
 1307               case ON_OR_INSERT:
 1308                   if (index == -1) {
 1309                       location = new DropLocation(p, getModel().getSize(), true);
 1310                       break;
 1311                   }
 1312   
 1313                   boolean between = false;
 1314   
 1315                   if (layoutOrientation == HORIZONTAL_WRAP) {
 1316                       boolean ltr = getComponentOrientation().isLeftToRight();
 1317   
 1318                       Section section = SwingUtilities2.liesInHorizontal(rect, p, ltr, true);
 1319                       if (section == TRAILING) {
 1320                           index++;
 1321                           between = true;
 1322                       // special case for below all cells
 1323                       } else if (index == getModel().getSize() - 1 && p.y >= rect.y + rect.height) {
 1324                           index++;
 1325                           between = true;
 1326                       } else if (section == LEADING) {
 1327                           between = true;
 1328                       }
 1329                   } else {
 1330                       Section section = SwingUtilities2.liesInVertical(rect, p, true);
 1331                       if (section == LEADING) {
 1332                           between = true;
 1333                       } else if (section == TRAILING) {
 1334                           index++;
 1335                           between = true;
 1336                       }
 1337                   }
 1338   
 1339                   location = new DropLocation(p, index, between);
 1340   
 1341                   break;
 1342               default:
 1343                   assert false : "Unexpected drop mode";
 1344           }
 1345   
 1346           return location;
 1347       }
 1348   
 1349       /**
 1350        * Called to set or clear the drop location during a DnD operation.
 1351        * In some cases, the component may need to use it's internal selection
 1352        * temporarily to indicate the drop location. To help facilitate this,
 1353        * this method returns and accepts as a parameter a state object.
 1354        * This state object can be used to store, and later restore, the selection
 1355        * state. Whatever this method returns will be passed back to it in
 1356        * future calls, as the state parameter. If it wants the DnD system to
 1357        * continue storing the same state, it must pass it back every time.
 1358        * Here's how this is used:
 1359        * <p>
 1360        * Let's say that on the first call to this method the component decides
 1361        * to save some state (because it is about to use the selection to show
 1362        * a drop index). It can return a state object to the caller encapsulating
 1363        * any saved selection state. On a second call, let's say the drop location
 1364        * is being changed to something else. The component doesn't need to
 1365        * restore anything yet, so it simply passes back the same state object
 1366        * to have the DnD system continue storing it. Finally, let's say this
 1367        * method is messaged with <code>null</code>. This means DnD
 1368        * is finished with this component for now, meaning it should restore
 1369        * state. At this point, it can use the state parameter to restore
 1370        * said state, and of course return <code>null</code> since there's
 1371        * no longer anything to store.
 1372        *
 1373        * @param location the drop location (as calculated by
 1374        *        <code>dropLocationForPoint</code>) or <code>null</code>
 1375        *        if there's no longer a valid drop location
 1376        * @param state the state object saved earlier for this component,
 1377        *        or <code>null</code>
 1378        * @param forDrop whether or not the method is being called because an
 1379        *        actual drop occurred
 1380        * @return any saved state for this component, or <code>null</code> if none
 1381        */
 1382       Object setDropLocation(TransferHandler.DropLocation location,
 1383                              Object state,
 1384                              boolean forDrop) {
 1385   
 1386           Object retVal = null;
 1387           DropLocation listLocation = (DropLocation)location;
 1388   
 1389           if (dropMode == DropMode.USE_SELECTION) {
 1390               if (listLocation == null) {
 1391                   if (!forDrop && state != null) {
 1392                       setSelectedIndices(((int[][])state)[0]);
 1393   
 1394                       int anchor = ((int[][])state)[1][0];
 1395                       int lead = ((int[][])state)[1][1];
 1396   
 1397                       SwingUtilities2.setLeadAnchorWithoutSelection(
 1398                               getSelectionModel(), lead, anchor);
 1399                   }
 1400               } else {
 1401                   if (dropLocation == null) {
 1402                       int[] inds = getSelectedIndices();
 1403                       retVal = new int[][] {inds, {getAnchorSelectionIndex(),
 1404                                                    getLeadSelectionIndex()}};
 1405                   } else {
 1406                       retVal = state;
 1407                   }
 1408   
 1409                   int index = listLocation.getIndex();
 1410                   if (index == -1) {
 1411                       clearSelection();
 1412                       getSelectionModel().setAnchorSelectionIndex(-1);
 1413                       getSelectionModel().setLeadSelectionIndex(-1);
 1414                   } else {
 1415                       setSelectionInterval(index, index);
 1416                   }
 1417               }
 1418           }
 1419   
 1420           DropLocation old = dropLocation;
 1421           dropLocation = listLocation;
 1422           firePropertyChange("dropLocation", old, dropLocation);
 1423   
 1424           return retVal;
 1425       }
 1426   
 1427       /**
 1428        * Returns the location that this component should visually indicate
 1429        * as the drop location during a DnD operation over the component,
 1430        * or {@code null} if no location is to currently be shown.
 1431        * <p>
 1432        * This method is not meant for querying the drop location
 1433        * from a {@code TransferHandler}, as the drop location is only
 1434        * set after the {@code TransferHandler}'s <code>canImport</code>
 1435        * has returned and has allowed for the location to be shown.
 1436        * <p>
 1437        * When this property changes, a property change event with
 1438        * name "dropLocation" is fired by the component.
 1439        * <p>
 1440        * By default, responsibility for listening for changes to this property
 1441        * and indicating the drop location visually lies with the list's
 1442        * {@code ListUI}, which may paint it directly and/or install a cell
 1443        * renderer to do so. Developers wishing to implement custom drop location
 1444        * painting and/or replace the default cell renderer, may need to honor
 1445        * this property.
 1446        *
 1447        * @return the drop location
 1448        * @see #setDropMode
 1449        * @see TransferHandler#canImport(TransferHandler.TransferSupport)
 1450        * @since 1.6
 1451        */
 1452       public final DropLocation getDropLocation() {
 1453           return dropLocation;
 1454       }
 1455   
 1456       /**
 1457        * Returns the next list element whose {@code toString} value
 1458        * starts with the given prefix.
 1459        *
 1460        * @param prefix the string to test for a match
 1461        * @param startIndex the index for starting the search
 1462        * @param bias the search direction, either
 1463        * Position.Bias.Forward or Position.Bias.Backward.
 1464        * @return the index of the next list element that
 1465        * starts with the prefix; otherwise {@code -1}
 1466        * @exception IllegalArgumentException if prefix is {@code null}
 1467        * or startIndex is out of bounds
 1468        * @since 1.4
 1469        */
 1470       public int getNextMatch(String prefix, int startIndex, Position.Bias bias) {
 1471           ListModel<E> model = getModel();
 1472           int max = model.getSize();
 1473           if (prefix == null) {
 1474               throw new IllegalArgumentException();
 1475           }
 1476           if (startIndex < 0 || startIndex >= max) {
 1477               throw new IllegalArgumentException();
 1478           }
 1479           prefix = prefix.toUpperCase();
 1480   
 1481           // start search from the next element after the selected element
 1482           int increment = (bias == Position.Bias.Forward) ? 1 : -1;
 1483           int index = startIndex;
 1484           do {
 1485               E element = model.getElementAt(index);
 1486   
 1487               if (element != null) {
 1488                   String string;
 1489   
 1490                   if (element instanceof String) {
 1491                       string = ((String)element).toUpperCase();
 1492                   }
 1493                   else {
 1494                       string = element.toString();
 1495                       if (string != null) {
 1496                           string = string.toUpperCase();
 1497                       }
 1498                   }
 1499   
 1500                   if (string != null && string.startsWith(prefix)) {
 1501                       return index;
 1502                   }
 1503               }
 1504               index = (index + increment + max) % max;
 1505           } while (index != startIndex);
 1506           return -1;
 1507       }
 1508   
 1509       /**
 1510        * Returns the tooltip text to be used for the given event. This overrides
 1511        * {@code JComponent}'s {@code getToolTipText} to first check the cell
 1512        * renderer component for the cell over which the event occurred, returning
 1513        * its tooltip text, if any. This implementation allows you to specify
 1514        * tooltip text on the cell level, by using {@code setToolTipText} on your
 1515        * cell renderer component.
 1516        * <p>
 1517        * <bold>Note:</bold> For <code>JList</code> to properly display the
 1518        * tooltips of its renderers in this manner, <code>JList</code> must be a
 1519        * registered component with the <code>ToolTipManager</code>. This registration
 1520        * is done automatically in the constructor. However, if at a later point
 1521        * <code>JList</code> is unregistered, by way of a call to
 1522        * {@code setToolTipText(null)}, tips from the renderers will no longer display.
 1523        *
 1524        * @param event the {@code MouseEvent} to fetch the tooltip text for
 1525        * @see JComponent#setToolTipText
 1526        * @see JComponent#getToolTipText
 1527        */
 1528       public String getToolTipText(MouseEvent event) {
 1529           if(event != null) {
 1530               Point p = event.getPoint();
 1531               int index = locationToIndex(p);
 1532               ListCellRenderer<? super E> r = getCellRenderer();
 1533               Rectangle cellBounds;
 1534   
 1535               if (index != -1 && r != null && (cellBounds =
 1536                                  getCellBounds(index, index)) != null &&
 1537                                  cellBounds.contains(p.x, p.y)) {
 1538                   ListSelectionModel lsm = getSelectionModel();
 1539                   Component rComponent = r.getListCellRendererComponent(
 1540                              this, getModel().getElementAt(index), index,
 1541                              lsm.isSelectedIndex(index),
 1542                              (hasFocus() && (lsm.getLeadSelectionIndex() ==
 1543                                              index)));
 1544   
 1545                   if(rComponent instanceof JComponent) {
 1546                       MouseEvent      newEvent;
 1547   
 1548                       p.translate(-cellBounds.x, -cellBounds.y);
 1549                       newEvent = new MouseEvent(rComponent, event.getID(),
 1550                                                 event.getWhen(),
 1551                                                 event.getModifiers(),
 1552                                                 p.x, p.y,
 1553                                                 event.getXOnScreen(),
 1554                                                 event.getYOnScreen(),
 1555                                                 event.getClickCount(),
 1556                                                 event.isPopupTrigger(),
 1557                                                 MouseEvent.NOBUTTON);
 1558   
 1559                       String tip = ((JComponent)rComponent).getToolTipText(
 1560                                                 newEvent);
 1561   
 1562                       if (tip != null) {
 1563                           return tip;
 1564                       }
 1565                   }
 1566               }
 1567           }
 1568           return super.getToolTipText();
 1569       }
 1570   
 1571       /**
 1572        * --- ListUI Delegations ---
 1573        */
 1574   
 1575   
 1576       /**
 1577        * Returns the cell index closest to the given location in the list's
 1578        * coordinate system. To determine if the cell actually contains the
 1579        * specified location, compare the point against the cell's bounds,
 1580        * as provided by {@code getCellBounds}. This method returns {@code -1}
 1581        * if the model is empty
 1582        * <p>
 1583        * This is a cover method that delegates to the method of the same name
 1584        * in the list's {@code ListUI}. It returns {@code -1} if the list has
 1585        * no {@code ListUI}.
 1586        *
 1587        * @param location the coordinates of the point
 1588        * @return the cell index closest to the given location, or {@code -1}
 1589        */
 1590       public int locationToIndex(Point location) {
 1591           ListUI ui = getUI();
 1592           return (ui != null) ? ui.locationToIndex(this, location) : -1;
 1593       }
 1594   
 1595   
 1596       /**
 1597        * Returns the origin of the specified item in the list's coordinate
 1598        * system. This method returns {@code null} if the index isn't valid.
 1599        * <p>
 1600        * This is a cover method that delegates to the method of the same name
 1601        * in the list's {@code ListUI}. It returns {@code null} if the list has
 1602        * no {@code ListUI}.
 1603        *
 1604        * @param index the cell index
 1605        * @return the origin of the cell, or {@code null}
 1606        */
 1607       public Point indexToLocation(int index) {
 1608           ListUI ui = getUI();
 1609           return (ui != null) ? ui.indexToLocation(this, index) : null;
 1610       }
 1611   
 1612   
 1613       /**
 1614        * Returns the bounding rectangle, in the list's coordinate system,
 1615        * for the range of cells specified by the two indices.
 1616        * These indices can be supplied in any order.
 1617        * <p>
 1618        * If the smaller index is outside the list's range of cells, this method
 1619        * returns {@code null}. If the smaller index is valid, but the larger
 1620        * index is outside the list's range, the bounds of just the first index
 1621        * is returned. Otherwise, the bounds of the valid range is returned.
 1622        * <p>
 1623        * This is a cover method that delegates to the method of the same name
 1624        * in the list's {@code ListUI}. It returns {@code null} if the list has
 1625        * no {@code ListUI}.
 1626        *
 1627        * @param index0 the first index in the range
 1628        * @param index1 the second index in the range
 1629        * @return the bounding rectangle for the range of cells, or {@code null}
 1630        */
 1631       public Rectangle getCellBounds(int index0, int index1) {
 1632           ListUI ui = getUI();
 1633           return (ui != null) ? ui.getCellBounds(this, index0, index1) : null;
 1634       }
 1635   
 1636   
 1637       /**
 1638        * --- ListModel Support ---
 1639        */
 1640   
 1641   
 1642       /**
 1643        * Returns the data model that holds the list of items displayed
 1644        * by the <code>JList</code> component.
 1645        *
 1646        * @return the <code>ListModel</code> that provides the displayed
 1647        *                          list of items
 1648        * @see #setModel
 1649        */
 1650       public ListModel<E> getModel() {
 1651           return dataModel;
 1652       }
 1653   
 1654       /**
 1655        * Sets the model that represents the contents or "value" of the
 1656        * list, notifies property change listeners, and then clears the
 1657        * list's selection.
 1658        * <p>
 1659        * This is a JavaBeans bound property.
 1660        *
 1661        * @param model  the <code>ListModel</code> that provides the
 1662        *                                          list of items for display
 1663        * @exception IllegalArgumentException  if <code>model</code> is
 1664        *                                          <code>null</code>
 1665        * @see #getModel
 1666        * @see #clearSelection
 1667        * @beaninfo
 1668        *       bound: true
 1669        *   attribute: visualUpdate true
 1670        * description: The object that contains the data to be drawn by this JList.
 1671        */
 1672       public void setModel(ListModel<E> model) {
 1673           if (model == null) {
 1674               throw new IllegalArgumentException("model must be non null");
 1675           }
 1676           ListModel<E> oldValue = dataModel;
 1677           dataModel = model;
 1678           firePropertyChange("model", oldValue, dataModel);
 1679           clearSelection();
 1680       }
 1681   
 1682   
 1683       /**
 1684        * Constructs a read-only <code>ListModel</code> from an array of items,
 1685        * and calls {@code setModel} with this model.
 1686        * <p>
 1687        * Attempts to pass a {@code null} value to this method results in
 1688        * undefined behavior and, most likely, exceptions. The created model
 1689        * references the given array directly. Attempts to modify the array
 1690        * after invoking this method results in undefined behavior.
 1691        *
 1692        * @param listData an array of {@code E} containing the items to
 1693        *        display in the list
 1694        * @see #setModel
 1695        */
 1696       public void setListData(final E[] listData) {
 1697           setModel (
 1698               new AbstractListModel<E>() {
 1699                   public int getSize() { return listData.length; }
 1700                   public E getElementAt(int i) { return listData[i]; }
 1701               }
 1702           );
 1703       }
 1704   
 1705   
 1706       /**
 1707        * Constructs a read-only <code>ListModel</code> from a <code>Vector</code>
 1708        * and calls {@code setModel} with this model.
 1709        * <p>
 1710        * Attempts to pass a {@code null} value to this method results in
 1711        * undefined behavior and, most likely, exceptions. The created model
 1712        * references the given {@code Vector} directly. Attempts to modify the
 1713        * {@code Vector} after invoking this method results in undefined behavior.
 1714        *
 1715        * @param listData a <code>Vector</code> containing the items to
 1716        *                                          display in the list
 1717        * @see #setModel
 1718        */
 1719       public void setListData(final Vector<? extends E> listData) {
 1720           setModel (
 1721               new AbstractListModel<E>() {
 1722                   public int getSize() { return listData.size(); }
 1723                   public E getElementAt(int i) { return listData.elementAt(i); }
 1724               }
 1725           );
 1726       }
 1727   
 1728   
 1729       /**
 1730        * --- ListSelectionModel delegations and extensions ---
 1731        */
 1732   
 1733   
 1734       /**
 1735        * Returns an instance of {@code DefaultListSelectionModel}; called
 1736        * during construction to initialize the list's selection model
 1737        * property.
 1738        *
 1739        * @return a {@code DefaultListSelecitonModel}, used to initialize
 1740        *         the list's selection model property during construction
 1741        * @see #setSelectionModel
 1742        * @see DefaultListSelectionModel
 1743        */
 1744       protected ListSelectionModel createSelectionModel() {
 1745           return new DefaultListSelectionModel();
 1746       }
 1747   
 1748   
 1749       /**
 1750        * Returns the current selection model. The selection model maintains the
 1751        * selection state of the list. See the class level documentation for more
 1752        * details.
 1753        *
 1754        * @return the <code>ListSelectionModel</code> that maintains the
 1755        *         list's selections
 1756        *
 1757        * @see #setSelectionModel
 1758        * @see ListSelectionModel
 1759        */
 1760       public ListSelectionModel getSelectionModel() {
 1761           return selectionModel;
 1762       }
 1763   
 1764   
 1765       /**
 1766        * Notifies {@code ListSelectionListener}s added directly to the list
 1767        * of selection changes made to the selection model. {@code JList}
 1768        * listens for changes made to the selection in the selection model,
 1769        * and forwards notification to listeners added to the list directly,
 1770        * by calling this method.
 1771        * <p>
 1772        * This method constructs a {@code ListSelectionEvent} with this list
 1773        * as the source, and the specified arguments, and sends it to the
 1774        * registered {@code ListSelectionListeners}.
 1775        *
 1776        * @param firstIndex the first index in the range, {@code <= lastIndex}
 1777        * @param lastIndex the last index in the range, {@code >= firstIndex}
 1778        * @param isAdjusting whether or not this is one in a series of
 1779        *        multiple events, where changes are still being made
 1780        *
 1781        * @see #addListSelectionListener
 1782        * @see #removeListSelectionListener
 1783        * @see javax.swing.event.ListSelectionEvent
 1784        * @see EventListenerList
 1785        */
 1786       protected void fireSelectionValueChanged(int firstIndex, int lastIndex,
 1787                                                boolean isAdjusting)
 1788       {
 1789           Object[] listeners = listenerList.getListenerList();
 1790           ListSelectionEvent e = null;
 1791   
 1792           for (int i = listeners.length - 2; i >= 0; i -= 2) {
 1793               if (listeners[i] == ListSelectionListener.class) {
 1794                   if (e == null) {
 1795                       e = new ListSelectionEvent(this, firstIndex, lastIndex,
 1796                                                  isAdjusting);
 1797                   }
 1798                   ((ListSelectionListener)listeners[i+1]).valueChanged(e);
 1799               }
 1800           }
 1801       }
 1802   
 1803   
 1804       /* A ListSelectionListener that forwards ListSelectionEvents from
 1805        * the selectionModel to the JList ListSelectionListeners.  The
 1806        * forwarded events only differ from the originals in that their
 1807        * source is the JList instead of the selectionModel itself.
 1808        */
 1809       private class ListSelectionHandler implements ListSelectionListener, Serializable
 1810       {
 1811           public void valueChanged(ListSelectionEvent e) {
 1812               fireSelectionValueChanged(e.getFirstIndex(),
 1813                                         e.getLastIndex(),
 1814                                         e.getValueIsAdjusting());
 1815           }
 1816       }
 1817   
 1818   
 1819       /**
 1820        * Adds a listener to the list, to be notified each time a change to the
 1821        * selection occurs; the preferred way of listening for selection state
 1822        * changes. {@code JList} takes care of listening for selection state
 1823        * changes in the selection model, and notifies the given listener of
 1824        * each change. {@code ListSelectionEvent}s sent to the listener have a
 1825        * {@code source} property set to this list.
 1826        *
 1827        * @param listener the {@code ListSelectionListener} to add
 1828        * @see #getSelectionModel
 1829        * @see #getListSelectionListeners
 1830        */
 1831       public void addListSelectionListener(ListSelectionListener listener)
 1832       {
 1833           if (selectionListener == null) {
 1834               selectionListener = new ListSelectionHandler();
 1835               getSelectionModel().addListSelectionListener(selectionListener);
 1836           }
 1837   
 1838           listenerList.add(ListSelectionListener.class, listener);
 1839       }
 1840   
 1841   
 1842       /**
 1843        * Removes a selection listener from the list.
 1844        *
 1845        * @param listener the {@code ListSelectionListener} to remove
 1846        * @see #addListSelectionListener
 1847        * @see #getSelectionModel
 1848        */
 1849       public void removeListSelectionListener(ListSelectionListener listener) {
 1850           listenerList.remove(ListSelectionListener.class, listener);
 1851       }
 1852   
 1853   
 1854       /**
 1855        * Returns an array of all the {@code ListSelectionListener}s added
 1856        * to this {@code JList} by way of {@code addListSelectionListener}.
 1857        *
 1858        * @return all of the {@code ListSelectionListener}s on this list, or
 1859        *         an empty array if no listeners have been added
 1860        * @see #addListSelectionListener
 1861        * @since 1.4
 1862        */
 1863       public ListSelectionListener[] getListSelectionListeners() {
 1864           return listenerList.getListeners(ListSelectionListener.class);
 1865       }
 1866   
 1867   
 1868       /**
 1869        * Sets the <code>selectionModel</code> for the list to a
 1870        * non-<code>null</code> <code>ListSelectionModel</code>
 1871        * implementation. The selection model handles the task of making single
 1872        * selections, selections of contiguous ranges, and non-contiguous
 1873        * selections.
 1874        * <p>
 1875        * This is a JavaBeans bound property.
 1876        *
 1877        * @param selectionModel  the <code>ListSelectionModel</code> that
 1878        *                          implements the selections
 1879        * @exception IllegalArgumentException   if <code>selectionModel</code>
 1880        *                                          is <code>null</code>
 1881        * @see #getSelectionModel
 1882        * @beaninfo
 1883        *       bound: true
 1884        * description: The selection model, recording which cells are selected.
 1885        */
 1886       public void setSelectionModel(ListSelectionModel selectionModel) {
 1887           if (selectionModel == null) {
 1888               throw new IllegalArgumentException("selectionModel must be non null");
 1889           }
 1890   
 1891           /* Remove the forwarding ListSelectionListener from the old
 1892            * selectionModel, and add it to the new one, if necessary.
 1893            */
 1894           if (selectionListener != null) {
 1895               this.selectionModel.removeListSelectionListener(selectionListener);
 1896               selectionModel.addListSelectionListener(selectionListener);
 1897           }
 1898   
 1899           ListSelectionModel oldValue = this.selectionModel;
 1900           this.selectionModel = selectionModel;
 1901           firePropertyChange("selectionModel", oldValue, selectionModel);
 1902       }
 1903   
 1904   
 1905       /**
 1906        * Sets the selection mode for the list. This is a cover method that sets
 1907        * the selection mode directly on the selection model.
 1908        * <p>
 1909        * The following list describes the accepted selection modes:
 1910        * <ul>
 1911        * <li>{@code ListSelectionModel.SINGLE_SELECTION} -
 1912        *   Only one list index can be selected at a time. In this mode,
 1913        *   {@code setSelectionInterval} and {@code addSelectionInterval} are
 1914        *   equivalent, both replacing the current selection with the index
 1915        *   represented by the second argument (the "lead").
 1916        * <li>{@code ListSelectionModel.SINGLE_INTERVAL_SELECTION} -
 1917        *   Only one contiguous interval can be selected at a time.
 1918        *   In this mode, {@code addSelectionInterval} behaves like
 1919        *   {@code setSelectionInterval} (replacing the current selection},
 1920        *   unless the given interval is immediately adjacent to or overlaps
 1921        *   the existing selection, and can be used to grow the selection.
 1922        * <li>{@code ListSelectionModel.MULTIPLE_INTERVAL_SELECTION} -
 1923        *   In this mode, there's no restriction on what can be selected.
 1924        *   This mode is the default.
 1925        * </ul>
 1926        *
 1927        * @param selectionMode the selection mode
 1928        * @see #getSelectionMode
 1929        * @throws IllegalArgumentException if the selection mode isn't
 1930        *         one of those allowed
 1931        * @beaninfo
 1932        * description: The selection mode.
 1933        *        enum: SINGLE_SELECTION            ListSelectionModel.SINGLE_SELECTION
 1934        *              SINGLE_INTERVAL_SELECTION   ListSelectionModel.SINGLE_INTERVAL_SELECTION
 1935        *              MULTIPLE_INTERVAL_SELECTION ListSelectionModel.MULTIPLE_INTERVAL_SELECTION
 1936        */
 1937       public void setSelectionMode(int selectionMode) {
 1938           getSelectionModel().setSelectionMode(selectionMode);
 1939       }
 1940   
 1941       /**
 1942        * Returns the current selection mode for the list. This is a cover
 1943        * method that delegates to the method of the same name on the
 1944        * list's selection model.
 1945        *
 1946        * @return the current selection mode
 1947        * @see #setSelectionMode
 1948        */
 1949       public int getSelectionMode() {
 1950           return getSelectionModel().getSelectionMode();
 1951       }
 1952   
 1953   
 1954       /**
 1955        * Returns the anchor selection index. This is a cover method that
 1956        * delegates to the method of the same name on the list's selection model.
 1957        *
 1958        * @return the anchor selection index
 1959        * @see ListSelectionModel#getAnchorSelectionIndex
 1960        */
 1961       public int getAnchorSelectionIndex() {
 1962           return getSelectionModel().getAnchorSelectionIndex();
 1963       }
 1964   
 1965   
 1966       /**
 1967        * Returns the lead selection index. This is a cover method that
 1968        * delegates to the method of the same name on the list's selection model.
 1969        *
 1970        * @return the lead selection index
 1971        * @see ListSelectionModel#getLeadSelectionIndex
 1972        * @beaninfo
 1973        * description: The lead selection index.
 1974        */
 1975       public int getLeadSelectionIndex() {
 1976           return getSelectionModel().getLeadSelectionIndex();
 1977       }
 1978   
 1979   
 1980       /**
 1981        * Returns the smallest selected cell index, or {@code -1} if the selection
 1982        * is empty. This is a cover method that delegates to the method of the same
 1983        * name on the list's selection model.
 1984        *
 1985        * @return the smallest selected cell index, or {@code -1}
 1986        * @see ListSelectionModel#getMinSelectionIndex
 1987        */
 1988       public int getMinSelectionIndex() {
 1989           return getSelectionModel().getMinSelectionIndex();
 1990       }
 1991   
 1992   
 1993       /**
 1994        * Returns the largest selected cell index, or {@code -1} if the selection
 1995        * is empty. This is a cover method that delegates to the method of the same
 1996        * name on the list's selection model.
 1997        *
 1998        * @return the largest selected cell index
 1999        * @see ListSelectionModel#getMaxSelectionIndex
 2000        */
 2001       public int getMaxSelectionIndex() {
 2002           return getSelectionModel().getMaxSelectionIndex();
 2003       }
 2004   
 2005   
 2006       /**
 2007        * Returns {@code true} if the specified index is selected,
 2008        * else {@code false}. This is a cover method that delegates to the method
 2009        * of the same name on the list's selection model.
 2010        *
 2011        * @param index index to be queried for selection state
 2012        * @return {@code true} if the specified index is selected,
 2013        *         else {@code false}
 2014        * @see ListSelectionModel#isSelectedIndex
 2015        * @see #setSelectedIndex
 2016        */
 2017       public boolean isSelectedIndex(int index) {
 2018           return getSelectionModel().isSelectedIndex(index);
 2019       }
 2020   
 2021   
 2022       /**
 2023        * Returns {@code true} if nothing is selected, else {@code false}.
 2024        * This is a cover method that delegates to the method of the same
 2025        * name on the list's selection model.
 2026        *
 2027        * @return {@code true} if nothing is selected, else {@code false}
 2028        * @see ListSelectionModel#isSelectionEmpty
 2029        * @see #clearSelection
 2030        */
 2031       public boolean isSelectionEmpty() {
 2032           return getSelectionModel().isSelectionEmpty();
 2033       }
 2034   
 2035   
 2036       /**
 2037        * Clears the selection; after calling this method, {@code isSelectionEmpty}
 2038        * will return {@code true}. This is a cover method that delegates to the
 2039        * method of the same name on the list's selection model.
 2040        *
 2041        * @see ListSelectionModel#clearSelection
 2042        * @see #isSelectionEmpty
 2043        */
 2044       public void clearSelection() {
 2045           getSelectionModel().clearSelection();
 2046       }
 2047   
 2048   
 2049       /**
 2050        * Selects the specified interval. Both {@code anchor} and {@code lead}
 2051        * indices are included. {@code anchor} doesn't have to be less than or
 2052        * equal to {@code lead}. This is a cover method that delegates to the
 2053        * method of the same name on the list's selection model.
 2054        * <p>
 2055        * Refer to the documentation of the selection model class being used
 2056        * for details on how values less than {@code 0} are handled.
 2057        *
 2058        * @param anchor the first index to select
 2059        * @param lead the last index to select
 2060        * @see ListSelectionModel#setSelectionInterval
 2061        * @see DefaultListSelectionModel#setSelectionInterval
 2062        * @see #createSelectionModel
 2063        * @see #addSelectionInterval
 2064        * @see #removeSelectionInterval
 2065        */
 2066       public void setSelectionInterval(int anchor, int lead) {
 2067           getSelectionModel().setSelectionInterval(anchor, lead);
 2068       }
 2069   
 2070   
 2071       /**
 2072        * Sets the selection to be the union of the specified interval with current
 2073        * selection. Both the {@code anchor} and {@code lead} indices are
 2074        * included. {@code anchor} doesn't have to be less than or
 2075        * equal to {@code lead}. This is a cover method that delegates to the
 2076        * method of the same name on the list's selection model.
 2077        * <p>
 2078        * Refer to the documentation of the selection model class being used
 2079        * for details on how values less than {@code 0} are handled.
 2080        *
 2081        * @param anchor the first index to add to the selection
 2082        * @param lead the last index to add to the selection
 2083        * @see ListSelectionModel#addSelectionInterval
 2084        * @see DefaultListSelectionModel#addSelectionInterval
 2085        * @see #createSelectionModel
 2086        * @see #setSelectionInterval
 2087        * @see #removeSelectionInterval
 2088        */
 2089       public void addSelectionInterval(int anchor, int lead) {
 2090           getSelectionModel().addSelectionInterval(anchor, lead);
 2091       }
 2092   
 2093   
 2094       /**
 2095        * Sets the selection to be the set difference of the specified interval
 2096        * and the current selection. Both the {@code index0} and {@code index1}
 2097        * indices are removed. {@code index0} doesn't have to be less than or
 2098        * equal to {@code index1}. This is a cover method that delegates to the
 2099        * method of the same name on the list's selection model.
 2100        * <p>
 2101        * Refer to the documentation of the selection model class being used
 2102        * for details on how values less than {@code 0} are handled.
 2103        *
 2104        * @param index0 the first index to remove from the selection
 2105        * @param index1 the last index to remove from the selection
 2106        * @see ListSelectionModel#removeSelectionInterval
 2107        * @see DefaultListSelectionModel#removeSelectionInterval
 2108        * @see #createSelectionModel
 2109        * @see #setSelectionInterval
 2110        * @see #addSelectionInterval
 2111        */
 2112       public void removeSelectionInterval(int index0, int index1) {
 2113           getSelectionModel().removeSelectionInterval(index0, index1);
 2114       }
 2115   
 2116   
 2117       /**
 2118        * Sets the selection model's {@code valueIsAdjusting} property. When
 2119        * {@code true}, upcoming changes to selection should be considered part
 2120        * of a single change. This property is used internally and developers
 2121        * typically need not call this method. For example, when the model is being
 2122        * updated in response to a user drag, the value of the property is set
 2123        * to {@code true} when the drag is initiated and set to {@code false}
 2124        * when the drag is finished. This allows listeners to update only
 2125        * when a change has been finalized, rather than handling all of the
 2126        * intermediate values.
 2127        * <p>
 2128        * You may want to use this directly if making a series of changes
 2129        * that should be considered part of a single change.
 2130        * <p>
 2131        * This is a cover method that delegates to the method of the same name on
 2132        * the list's selection model. See the documentation for
 2133        * {@link javax.swing.ListSelectionModel#setValueIsAdjusting} for
 2134        * more details.
 2135        *
 2136        * @param b the new value for the property
 2137        * @see ListSelectionModel#setValueIsAdjusting
 2138        * @see javax.swing.event.ListSelectionEvent#getValueIsAdjusting
 2139        * @see #getValueIsAdjusting
 2140        */
 2141       public void setValueIsAdjusting(boolean b) {
 2142           getSelectionModel().setValueIsAdjusting(b);
 2143       }
 2144   
 2145   
 2146       /**
 2147        * Returns the value of the selection model's {@code isAdjusting} property.
 2148        * <p>
 2149        * This is a cover method that delegates to the method of the same name on
 2150        * the list's selection model.
 2151        *
 2152        * @return the value of the selection model's {@code isAdjusting} property.
 2153        *
 2154        * @see #setValueIsAdjusting
 2155        * @see ListSelectionModel#getValueIsAdjusting
 2156        */
 2157       public boolean getValueIsAdjusting() {
 2158           return getSelectionModel().getValueIsAdjusting();
 2159       }
 2160   
 2161   
 2162       /**
 2163        * Returns an array of all of the selected indices, in increasing
 2164        * order.
 2165        *
 2166        * @return all of the selected indices, in increasing order,
 2167        *         or an empty array if nothing is selected
 2168        * @see #removeSelectionInterval
 2169        * @see #addListSelectionListener
 2170        */
 2171       @Transient
 2172       public int[] getSelectedIndices() {
 2173           ListSelectionModel sm = getSelectionModel();
 2174           int iMin = sm.getMinSelectionIndex();
 2175           int iMax = sm.getMaxSelectionIndex();
 2176   
 2177           if ((iMin < 0) || (iMax < 0)) {
 2178               return new int[0];
 2179           }
 2180   
 2181           int[] rvTmp = new int[1+ (iMax - iMin)];
 2182           int n = 0;
 2183           for(int i = iMin; i <= iMax; i++) {
 2184               if (sm.isSelectedIndex(i)) {
 2185                   rvTmp[n++] = i;
 2186               }
 2187           }
 2188           int[] rv = new int[n];
 2189           System.arraycopy(rvTmp, 0, rv, 0, n);
 2190           return rv;
 2191       }
 2192   
 2193   
 2194       /**
 2195        * Selects a single cell. Does nothing if the given index is greater
 2196        * than or equal to the model size. This is a convenience method that uses
 2197        * {@code setSelectionInterval} on the selection model. Refer to the
 2198        * documentation for the selection model class being used for details on
 2199        * how values less than {@code 0} are handled.
 2200        *
 2201        * @param index the index of the cell to select
 2202        * @see ListSelectionModel#setSelectionInterval
 2203        * @see #isSelectedIndex
 2204        * @see #addListSelectionListener
 2205        * @beaninfo
 2206        * description: The index of the selected cell.
 2207        */
 2208       public void setSelectedIndex(int index) {
 2209           if (index >= getModel().getSize()) {
 2210               return;
 2211           }
 2212           getSelectionModel().setSelectionInterval(index, index);
 2213       }
 2214   
 2215   
 2216       /**
 2217        * Changes the selection to be the set of indices specified by the given
 2218        * array. Indices greater than or equal to the model size are ignored.
 2219        * This is a convenience method that clears the selection and then uses
 2220        * {@code addSelectionInterval} on the selection model to add the indices.
 2221        * Refer to the documentation of the selection model class being used for
 2222        * details on how values less than {@code 0} are handled.
 2223        *
 2224        * @param indices an array of the indices of the cells to select,
 2225        *                {@code non-null}
 2226        * @see ListSelectionModel#addSelectionInterval
 2227        * @see #isSelectedIndex
 2228        * @see #addListSelectionListener
 2229        * @throws NullPointerException if the given array is {@code null}
 2230        */
 2231       public void setSelectedIndices(int[] indices) {
 2232           ListSelectionModel sm = getSelectionModel();
 2233           sm.clearSelection();
 2234           int size = getModel().getSize();
 2235           for (int i : indices) {
 2236               if (i < size) {
 2237                   sm.addSelectionInterval(i, i);
 2238               }
 2239           }
 2240       }
 2241   
 2242   
 2243       /**
 2244        * Returns an array of all the selected values, in increasing order based
 2245        * on their indices in the list.
 2246        *
 2247        * @return the selected values, or an empty array if nothing is selected
 2248        * @see #isSelectedIndex
 2249        * @see #getModel
 2250        * @see #addListSelectionListener
 2251        *
 2252        * @deprecated As of JDK 1.7, replaced by {@link #getSelectedValuesList()}
 2253        */
 2254       @Deprecated
 2255       public Object[] getSelectedValues() {
 2256           ListSelectionModel sm = getSelectionModel();
 2257           ListModel<E> dm = getModel();
 2258   
 2259           int iMin = sm.getMinSelectionIndex();
 2260           int iMax = sm.getMaxSelectionIndex();
 2261   
 2262           if ((iMin < 0) || (iMax < 0)) {
 2263               return new Object[0];
 2264           }
 2265   
 2266           Object[] rvTmp = new Object[1+ (iMax - iMin)];
 2267           int n = 0;
 2268           for(int i = iMin; i <= iMax; i++) {
 2269               if (sm.isSelectedIndex(i)) {
 2270                   rvTmp[n++] = dm.getElementAt(i);
 2271               }
 2272           }
 2273           Object[] rv = new Object[n];
 2274           System.arraycopy(rvTmp, 0, rv, 0, n);
 2275           return rv;
 2276       }
 2277   
 2278       /**
 2279        * Returns a list of all the selected items, in increasing order based
 2280        * on their indices in the list.
 2281        *
 2282        * @return the selected items, or an empty list if nothing is selected
 2283        * @see #isSelectedIndex
 2284        * @see #getModel
 2285        * @see #addListSelectionListener
 2286        *
 2287        * @since 1.7
 2288        */
 2289       public List<E> getSelectedValuesList() {
 2290           ListSelectionModel sm = getSelectionModel();
 2291           ListModel<E> dm = getModel();
 2292   
 2293           int iMin = sm.getMinSelectionIndex();
 2294           int iMax = sm.getMaxSelectionIndex();
 2295   
 2296           if ((iMin < 0) || (iMax < 0)) {
 2297               return Collections.emptyList();
 2298           }
 2299   
 2300           List<E> selectedItems = new ArrayList<E>();
 2301           for(int i = iMin; i <= iMax; i++) {
 2302               if (sm.isSelectedIndex(i)) {
 2303                   selectedItems.add(dm.getElementAt(i));
 2304               }
 2305           }
 2306           return selectedItems;
 2307       }
 2308   
 2309   
 2310       /**
 2311        * Returns the smallest selected cell index; <i>the selection</i> when only
 2312        * a single item is selected in the list. When multiple items are selected,
 2313        * it is simply the smallest selected index. Returns {@code -1} if there is
 2314        * no selection.
 2315        * <p>
 2316        * This method is a cover that delegates to {@code getMinSelectionIndex}.
 2317        *
 2318        * @return the smallest selected cell index
 2319        * @see #getMinSelectionIndex
 2320        * @see #addListSelectionListener
 2321        */
 2322       public int getSelectedIndex() {
 2323           return getMinSelectionIndex();
 2324       }
 2325   
 2326   
 2327       /**
 2328        * Returns the value for the smallest selected cell index;
 2329        * <i>the selected value</i> when only a single item is selected in the
 2330        * list. When multiple items are selected, it is simply the value for the
 2331        * smallest selected index. Returns {@code null} if there is no selection.
 2332        * <p>
 2333        * This is a convenience method that simply returns the model value for
 2334        * {@code getMinSelectionIndex}.
 2335        *
 2336        * @return the first selected value
 2337        * @see #getMinSelectionIndex
 2338        * @see #getModel
 2339        * @see #addListSelectionListener
 2340        */
 2341       public E getSelectedValue() {
 2342           int i = getMinSelectionIndex();
 2343           return (i == -1) ? null : getModel().getElementAt(i);
 2344       }
 2345   
 2346   
 2347       /**
 2348        * Selects the specified object from the list.
 2349        *
 2350        * @param anObject      the object to select
 2351        * @param shouldScroll  {@code true} if the list should scroll to display
 2352        *                      the selected object, if one exists; otherwise {@code false}
 2353        */
 2354       public void setSelectedValue(Object anObject,boolean shouldScroll) {
 2355           if(anObject == null)
 2356               setSelectedIndex(-1);
 2357           else if(!anObject.equals(getSelectedValue())) {
 2358               int i,c;
 2359               ListModel<E> dm = getModel();
 2360               for(i=0,c=dm.getSize();i<c;i++)
 2361                   if(anObject.equals(dm.getElementAt(i))){
 2362                       setSelectedIndex(i);
 2363                       if(shouldScroll)
 2364                           ensureIndexIsVisible(i);
 2365                       repaint();  /** FIX-ME setSelectedIndex does not redraw all the time with the basic l&f**/
 2366                       return;
 2367                   }
 2368               setSelectedIndex(-1);
 2369           }
 2370           repaint(); /** FIX-ME setSelectedIndex does not redraw all the time with the basic l&f**/
 2371       }
 2372   
 2373   
 2374   
 2375       /**
 2376        * --- The Scrollable Implementation ---
 2377        */
 2378   
 2379       private void checkScrollableParameters(Rectangle visibleRect, int orientation) {
 2380           if (visibleRect == null) {
 2381               throw new IllegalArgumentException("visibleRect must be non-null");
 2382           }
 2383           switch (orientation) {
 2384           case SwingConstants.VERTICAL:
 2385           case SwingConstants.HORIZONTAL:
 2386               break;
 2387           default:
 2388               throw new IllegalArgumentException("orientation must be one of: VERTICAL, HORIZONTAL");
 2389           }
 2390       }
 2391   
 2392   
 2393       /**
 2394        * Computes the size of viewport needed to display {@code visibleRowCount}
 2395        * rows. The value returned by this method depends on the layout
 2396        * orientation:
 2397        * <p>
 2398        * <b>{@code VERTICAL}:</b>
 2399        * <br>
 2400        * This is trivial if both {@code fixedCellWidth} and {@code fixedCellHeight}
 2401        * have been set (either explicitly or by specifying a prototype cell value).
 2402        * The width is simply the {@code fixedCellWidth} plus the list's horizontal
 2403        * insets. The height is the {@code fixedCellHeight} multiplied by the
 2404        * {@code visibleRowCount}, plus the list's vertical insets.
 2405        * <p>
 2406        * If either {@code fixedCellWidth} or {@code fixedCellHeight} haven't been
 2407        * specified, heuristics are used. If the model is empty, the width is
 2408        * the {@code fixedCellWidth}, if greater than {@code 0}, or a hard-coded
 2409        * value of {@code 256}. The height is the {@code fixedCellHeight} multiplied
 2410        * by {@code visibleRowCount}, if {@code fixedCellHeight} is greater than
 2411        * {@code 0}, otherwise it is a hard-coded value of {@code 16} multiplied by
 2412        * {@code visibleRowCount}.
 2413        * <p>
 2414        * If the model isn't empty, the width is the preferred size's width,
 2415        * typically the width of the widest list element. The height is the
 2416        * {@code fixedCellHeight} multiplied by the {@code visibleRowCount},
 2417        * plus the list's vertical insets.
 2418        * <p>
 2419        * <b>{@code VERTICAL_WRAP} or {@code HORIZONTAL_WRAP}:</b>
 2420        * <br>
 2421        * This method simply returns the value from {@code getPreferredSize}.
 2422        * The list's {@code ListUI} is expected to override {@code getPreferredSize}
 2423        * to return an appropriate value.
 2424        *
 2425        * @return a dimension containing the size of the viewport needed
 2426        *          to display {@code visibleRowCount} rows
 2427        * @see #getPreferredScrollableViewportSize
 2428        * @see #setPrototypeCellValue
 2429        */
 2430       public Dimension getPreferredScrollableViewportSize()
 2431       {
 2432           if (getLayoutOrientation() != VERTICAL) {
 2433               return getPreferredSize();
 2434           }
 2435           Insets insets = getInsets();
 2436           int dx = insets.left + insets.right;
 2437           int dy = insets.top + insets.bottom;
 2438   
 2439           int visibleRowCount = getVisibleRowCount();
 2440           int fixedCellWidth = getFixedCellWidth();
 2441           int fixedCellHeight = getFixedCellHeight();
 2442   
 2443           if ((fixedCellWidth > 0) && (fixedCellHeight > 0)) {
 2444               int width = fixedCellWidth + dx;
 2445               int height = (visibleRowCount * fixedCellHeight) + dy;
 2446               return new Dimension(width, height);
 2447           }
 2448           else if (getModel().getSize() > 0) {
 2449               int width = getPreferredSize().width;
 2450               int height;
 2451               Rectangle r = getCellBounds(0, 0);
 2452               if (r != null) {
 2453                   height = (visibleRowCount * r.height) + dy;
 2454               }
 2455               else {
 2456                   // Will only happen if UI null, shouldn't matter what we return
 2457                   height = 1;
 2458               }
 2459               return new Dimension(width, height);
 2460           }
 2461           else {
 2462               fixedCellWidth = (fixedCellWidth > 0) ? fixedCellWidth : 256;
 2463               fixedCellHeight = (fixedCellHeight > 0) ? fixedCellHeight : 16;
 2464               return new Dimension(fixedCellWidth, fixedCellHeight * visibleRowCount);
 2465           }
 2466       }
 2467   
 2468   
 2469       /**
 2470        * Returns the distance to scroll to expose the next or previous
 2471        * row (for vertical scrolling) or column (for horizontal scrolling).
 2472        * <p>
 2473        * For horizontal scrolling, if the layout orientation is {@code VERTICAL},
 2474        * then the list's font size is returned (or {@code 1} if the font is
 2475        * {@code null}).
 2476        *
 2477        * @param visibleRect the view area visible within the viewport
 2478        * @param orientation {@code SwingConstants.HORIZONTAL} or
 2479        *                    {@code SwingConstants.VERTICAL}
 2480        * @param direction less or equal to zero to scroll up/back,
 2481        *                  greater than zero for down/forward
 2482        * @return the "unit" increment for scrolling in the specified direction;
 2483        *         always positive
 2484        * @see #getScrollableBlockIncrement
 2485        * @see Scrollable#getScrollableUnitIncrement
 2486        * @throws IllegalArgumentException if {@code visibleRect} is {@code null}, or
 2487        *         {@code orientation} isn't one of {@code SwingConstants.VERTICAL} or
 2488        *         {@code SwingConstants.HORIZONTAL}
 2489        */
 2490       public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction)
 2491       {
 2492           checkScrollableParameters(visibleRect, orientation);
 2493   
 2494           if (orientation == SwingConstants.VERTICAL) {
 2495               int row = locationToIndex(visibleRect.getLocation());
 2496   
 2497               if (row == -1) {
 2498                   return 0;
 2499               }
 2500               else {
 2501                   /* Scroll Down */
 2502                   if (direction > 0) {
 2503                       Rectangle r = getCellBounds(row, row);
 2504                       return (r == null) ? 0 : r.height - (visibleRect.y - r.y);
 2505                   }
 2506                   /* Scroll Up */
 2507                   else {
 2508                       Rectangle r = getCellBounds(row, row);
 2509   
 2510                       /* The first row is completely visible and it's row 0.
 2511                        * We're done.
 2512                        */
 2513                       if ((r.y == visibleRect.y) && (row == 0))  {
 2514                           return 0;
 2515                       }
 2516                       /* The first row is completely visible, return the
 2517                        * height of the previous row or 0 if the first row
 2518                        * is the top row of the list.
 2519                        */
 2520                       else if (r.y == visibleRect.y) {
 2521                           Point loc = r.getLocation();
 2522                           loc.y--;
 2523                           int prevIndex = locationToIndex(loc);
 2524                           Rectangle prevR = getCellBounds(prevIndex, prevIndex);
 2525   
 2526                           if (prevR == null || prevR.y >= r.y) {
 2527                               return 0;
 2528                           }
 2529                           return prevR.height;
 2530                       }
 2531                       /* The first row is partially visible, return the
 2532                        * height of hidden part.
 2533                        */
 2534                       else {
 2535                           return visibleRect.y - r.y;
 2536                       }
 2537                   }
 2538               }
 2539           } else if (orientation == SwingConstants.HORIZONTAL &&
 2540                              getLayoutOrientation() != JList.VERTICAL) {
 2541               boolean leftToRight = getComponentOrientation().isLeftToRight();
 2542               int index;
 2543               Point leadingPoint;
 2544   
 2545               if (leftToRight) {
 2546                   leadingPoint = visibleRect.getLocation();
 2547               }
 2548               else {
 2549                   leadingPoint = new Point(visibleRect.x + visibleRect.width -1,
 2550                                            visibleRect.y);
 2551               }
 2552               index = locationToIndex(leadingPoint);
 2553   
 2554               if (index != -1) {
 2555                   Rectangle cellBounds = getCellBounds(index, index);
 2556                   if (cellBounds != null && cellBounds.contains(leadingPoint)) {
 2557                       int leadingVisibleEdge;
 2558                       int leadingCellEdge;
 2559   
 2560                       if (leftToRight) {
 2561                           leadingVisibleEdge = visibleRect.x;
 2562                           leadingCellEdge = cellBounds.x;
 2563                       }
 2564                       else {
 2565                           leadingVisibleEdge = visibleRect.x + visibleRect.width;
 2566                           leadingCellEdge = cellBounds.x + cellBounds.width;
 2567                       }
 2568   
 2569                       if (leadingCellEdge != leadingVisibleEdge) {
 2570                           if (direction < 0) {
 2571                               // Show remainder of leading cell
 2572                               return Math.abs(leadingVisibleEdge - leadingCellEdge);
 2573   
 2574                           }
 2575                           else if (leftToRight) {
 2576                               // Hide rest of leading cell
 2577                               return leadingCellEdge + cellBounds.width - leadingVisibleEdge;
 2578                           }
 2579                           else {
 2580                               // Hide rest of leading cell
 2581                               return leadingVisibleEdge - cellBounds.x;
 2582                           }
 2583                       }
 2584                       // ASSUME: All cells are the same width
 2585                       return cellBounds.width;
 2586                   }
 2587               }
 2588           }
 2589           Font f = getFont();
 2590           return (f != null) ? f.getSize() : 1;
 2591       }
 2592   
 2593   
 2594       /**
 2595        * Returns the distance to scroll to expose the next or previous block.
 2596        * <p>
 2597        * For vertical scrolling, the following rules are used:
 2598        * <ul>
 2599        * <li>if scrolling down, returns the distance to scroll so that the last
 2600        * visible element becomes the first completely visible element
 2601        * <li>if scrolling up, returns the distance to scroll so that the first
 2602        * visible element becomes the last completely visible element
 2603        * <li>returns {@code visibleRect.height} if the list is empty
 2604        * </ul>
 2605        * <p>
 2606        * For horizontal scrolling, when the layout orientation is either
 2607        * {@code VERTICAL_WRAP} or {@code HORIZONTAL_WRAP}:
 2608        * <ul>
 2609        * <li>if scrolling right, returns the distance to scroll so that the
 2610        * last visible element becomes
 2611        * the first completely visible element
 2612        * <li>if scrolling left, returns the distance to scroll so that the first
 2613        * visible element becomes the last completely visible element
 2614        * <li>returns {@code visibleRect.width} if the list is empty
 2615        * </ul>
 2616        * <p>
 2617        * For horizontal scrolling and {@code VERTICAL} orientation,
 2618        * returns {@code visibleRect.width}.
 2619        * <p>
 2620        * Note that the value of {@code visibleRect} must be the equal to
 2621        * {@code this.getVisibleRect()}.
 2622        *
 2623        * @param visibleRect the view area visible within the viewport
 2624        * @param orientation {@code SwingConstants.HORIZONTAL} or
 2625        *                    {@code SwingConstants.VERTICAL}
 2626        * @param direction less or equal to zero to scroll up/back,
 2627        *                  greater than zero for down/forward
 2628        * @return the "block" increment for scrolling in the specified direction;
 2629        *         always positive
 2630        * @see #getScrollableUnitIncrement
 2631        * @see Scrollable#getScrollableBlockIncrement
 2632        * @throws IllegalArgumentException if {@code visibleRect} is {@code null}, or
 2633        *         {@code orientation} isn't one of {@code SwingConstants.VERTICAL} or
 2634        *         {@code SwingConstants.HORIZONTAL}
 2635        */
 2636       public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
 2637           checkScrollableParameters(visibleRect, orientation);
 2638           if (orientation == SwingConstants.VERTICAL) {
 2639               int inc = visibleRect.height;
 2640               /* Scroll Down */
 2641               if (direction > 0) {
 2642                   // last cell is the lowest left cell
 2643                   int last = locationToIndex(new Point(visibleRect.x, visibleRect.y+visibleRect.height-1));
 2644                   if (last != -1) {
 2645                       Rectangle lastRect = getCellBounds(last,last);
 2646                       if (lastRect != null) {
 2647                           inc = lastRect.y - visibleRect.y;
 2648                           if ( (inc == 0) && (last < getModel().getSize()-1) ) {
 2649                               inc = lastRect.height;
 2650                           }
 2651                       }
 2652                   }
 2653               }
 2654               /* Scroll Up */
 2655               else {
 2656                   int newFirst = locationToIndex(new Point(visibleRect.x, visibleRect.y-visibleRect.height));
 2657                   int first = getFirstVisibleIndex();
 2658                   if (newFirst != -1) {
 2659                       if (first == -1) {
 2660                           first = locationToIndex(visibleRect.getLocation());
 2661                       }
 2662                       Rectangle newFirstRect = getCellBounds(newFirst,newFirst);
 2663                       Rectangle firstRect = getCellBounds(first,first);
 2664                       if ((newFirstRect != null) && (firstRect!=null)) {
 2665                           while ( (newFirstRect.y + visibleRect.height <
 2666                                    firstRect.y + firstRect.height) &&
 2667                                   (newFirstRect.y < firstRect.y) ) {
 2668                               newFirst++;
 2669                               newFirstRect = getCellBounds(newFirst,newFirst);
 2670                           }
 2671                           inc = visibleRect.y - newFirstRect.y;
 2672                           if ( (inc <= 0) && (newFirstRect.y > 0)) {
 2673                               newFirst--;
 2674                               newFirstRect = getCellBounds(newFirst,newFirst);
 2675                               if (newFirstRect != null) {
 2676                                   inc = visibleRect.y - newFirstRect.y;
 2677                               }
 2678                           }
 2679                       }
 2680                   }
 2681               }
 2682               return inc;
 2683           }
 2684           else if (orientation == SwingConstants.HORIZONTAL &&
 2685                    getLayoutOrientation() != JList.VERTICAL) {
 2686               boolean leftToRight = getComponentOrientation().isLeftToRight();
 2687               int inc = visibleRect.width;
 2688               /* Scroll Right (in ltr mode) or Scroll Left (in rtl mode) */
 2689               if (direction > 0) {
 2690                   // position is upper right if ltr, or upper left otherwise
 2691                   int x = visibleRect.x + (leftToRight ? (visibleRect.width - 1) : 0);
 2692                   int last = locationToIndex(new Point(x, visibleRect.y));
 2693   
 2694                   if (last != -1) {
 2695                       Rectangle lastRect = getCellBounds(last,last);
 2696                       if (lastRect != null) {
 2697                           if (leftToRight) {
 2698                               inc = lastRect.x - visibleRect.x;
 2699                           } else {
 2700                               inc = visibleRect.x + visibleRect.width
 2701                                         - (lastRect.x + lastRect.width);
 2702                           }
 2703                           if (inc < 0) {
 2704                               inc += lastRect.width;
 2705                           } else if ( (inc == 0) && (last < getModel().getSize()-1) ) {
 2706                               inc = lastRect.width;
 2707                           }
 2708                       }
 2709                   }
 2710               }
 2711               /* Scroll Left (in ltr mode) or Scroll Right (in rtl mode) */
 2712               else {
 2713                   // position is upper left corner of the visibleRect shifted
 2714                   // left by the visibleRect.width if ltr, or upper right shifted
 2715                   // right by the visibleRect.width otherwise
 2716                   int x = visibleRect.x + (leftToRight
 2717                                            ? -visibleRect.width
 2718                                            : visibleRect.width - 1 + visibleRect.width);
 2719                   int first = locationToIndex(new Point(x, visibleRect.y));
 2720   
 2721                   if (first != -1) {
 2722                       Rectangle firstRect = getCellBounds(first,first);
 2723                       if (firstRect != null) {
 2724                           // the right of the first cell
 2725                           int firstRight = firstRect.x + firstRect.width;
 2726   
 2727                           if (leftToRight) {
 2728                               if ((firstRect.x < visibleRect.x - visibleRect.width)
 2729                                       && (firstRight < visibleRect.x)) {
 2730                                   inc = visibleRect.x - firstRight;
 2731                               } else {
 2732                                   inc = visibleRect.x - firstRect.x;
 2733                               }
 2734                           } else {
 2735                               int visibleRight = visibleRect.x + visibleRect.width;
 2736   
 2737                               if ((firstRight > visibleRight + visibleRect.width)
 2738                                       && (firstRect.x > visibleRight)) {
 2739                                   inc = firstRect.x - visibleRight;
 2740                               } else {
 2741                                   inc = firstRight - visibleRight;
 2742                               }
 2743                           }
 2744                       }
 2745                   }
 2746               }
 2747               return inc;
 2748           }
 2749           return visibleRect.width;
 2750       }
 2751   
 2752   
 2753       /**
 2754        * Returns {@code true} if this {@code JList} is displayed in a
 2755        * {@code JViewport} and the viewport is wider than the list's
 2756        * preferred width, or if the layout orientation is {@code HORIZONTAL_WRAP}
 2757        * and {@code visibleRowCount <= 0}; otherwise returns {@code false}.
 2758        * <p>
 2759        * If {@code false}, then don't track the viewport's width. This allows
 2760        * horizontal scrolling if the {@code JViewport} is itself embedded in a
 2761        * {@code JScrollPane}.
 2762        *
 2763        * @return whether or not an enclosing viewport should force the list's
 2764        *         width to match its own
 2765        * @see Scrollable#getScrollableTracksViewportWidth
 2766        */
 2767       public boolean getScrollableTracksViewportWidth() {
 2768           if (getLayoutOrientation() == HORIZONTAL_WRAP &&
 2769                                         getVisibleRowCount() <= 0) {
 2770               return true;
 2771           }
 2772           Container parent = SwingUtilities.getUnwrappedParent(this);
 2773           if (parent instanceof JViewport) {
 2774               return parent.getWidth() > getPreferredSize().width;
 2775           }
 2776           return false;
 2777       }
 2778   
 2779       /**
 2780        * Returns {@code true} if this {@code JList} is displayed in a
 2781        * {@code JViewport} and the viewport is taller than the list's
 2782        * preferred height, or if the layout orientation is {@code VERTICAL_WRAP}
 2783        * and {@code visibleRowCount <= 0}; otherwise returns {@code false}.
 2784        * <p>
 2785        * If {@code false}, then don't track the viewport's height. This allows
 2786        * vertical scrolling if the {@code JViewport} is itself embedded in a
 2787        * {@code JScrollPane}.
 2788        *
 2789        * @return whether or not an enclosing viewport should force the list's
 2790        *         height to match its own
 2791        * @see Scrollable#getScrollableTracksViewportHeight
 2792        */
 2793       public boolean getScrollableTracksViewportHeight() {
 2794           if (getLayoutOrientation() == VERTICAL_WRAP &&
 2795                        getVisibleRowCount() <= 0) {
 2796               return true;
 2797           }
 2798           Container parent = SwingUtilities.getUnwrappedParent(this);
 2799           if (parent instanceof JViewport) {
 2800               return parent.getHeight() > getPreferredSize().height;
 2801           }
 2802           return false;
 2803       }
 2804   
 2805   
 2806       /*
 2807        * See {@code readObject} and {@code writeObject} in {@code JComponent}
 2808        * for more information about serialization in Swing.
 2809        */
 2810       private void writeObject(ObjectOutputStream s) throws IOException {
 2811           s.defaultWriteObject();
 2812           if (getUIClassID().equals(uiClassID)) {
 2813               byte count = JComponent.getWriteObjCounter(this);
 2814               JComponent.setWriteObjCounter(this, --count);
 2815               if (count == 0 && ui != null) {
 2816                   ui.installUI(this);
 2817               }
 2818           }
 2819       }
 2820   
 2821   
 2822       /**
 2823        * Returns a {@code String} representation of this {@code JList}.
 2824        * This method is intended to be used only for debugging purposes,
 2825        * and the content and format of the returned {@code String} may vary
 2826        * between implementations. The returned {@code String} may be empty,
 2827        * but may not be {@code null}.
 2828        *
 2829        * @return  a {@code String} representation of this {@code JList}.
 2830        */
 2831       protected String paramString() {
 2832           String selectionForegroundString = (selectionForeground != null ?
 2833                                               selectionForeground.toString() :
 2834                                               "");
 2835           String selectionBackgroundString = (selectionBackground != null ?
 2836                                               selectionBackground.toString() :
 2837                                               "");
 2838   
 2839           return super.paramString() +
 2840           ",fixedCellHeight=" + fixedCellHeight +
 2841           ",fixedCellWidth=" + fixedCellWidth +
 2842           ",horizontalScrollIncrement=" + horizontalScrollIncrement +
 2843           ",selectionBackground=" + selectionBackgroundString +
 2844           ",selectionForeground=" + selectionForegroundString +
 2845           ",visibleRowCount=" + visibleRowCount +
 2846           ",layoutOrientation=" + layoutOrientation;
 2847       }
 2848   
 2849   
 2850       /**
 2851        * --- Accessibility Support ---
 2852        */
 2853   
 2854       /**
 2855        * Gets the {@code AccessibleContext} associated with this {@code JList}.
 2856        * For {@code JList}, the {@code AccessibleContext} takes the form of an
 2857        * {@code AccessibleJList}.
 2858        * <p>
 2859        * A new {@code AccessibleJList} instance is created if necessary.
 2860        *
 2861        * @return an {@code AccessibleJList} that serves as the
 2862        *         {@code AccessibleContext} of this {@code JList}
 2863        */
 2864       public AccessibleContext getAccessibleContext() {
 2865           if (accessibleContext == null) {
 2866               accessibleContext = new AccessibleJList();
 2867           }
 2868           return accessibleContext;
 2869       }
 2870   
 2871       /**
 2872        * This class implements accessibility support for the
 2873        * {@code JList} class. It provides an implementation of the
 2874        * Java Accessibility API appropriate to list user-interface
 2875        * elements.
 2876        * <p>
 2877        * <strong>Warning:</strong>
 2878        * Serialized objects of this class will not be compatible with
 2879        * future Swing releases. The current serialization support is
 2880        * appropriate for short term storage or RMI between applications running
 2881        * the same version of Swing.  As of 1.4, support for long term storage
 2882        * of all JavaBeans<sup><font size="-2">TM</font></sup>
 2883        * has been added to the <code>java.beans</code> package.
 2884        * Please see {@link java.beans.XMLEncoder}.
 2885        */
 2886       protected class AccessibleJList extends AccessibleJComponent
 2887           implements AccessibleSelection, PropertyChangeListener,
 2888           ListSelectionListener, ListDataListener {
 2889   
 2890           int leadSelectionIndex;
 2891   
 2892           public AccessibleJList() {
 2893               super();
 2894               JList.this.addPropertyChangeListener(this);
 2895               JList.this.getSelectionModel().addListSelectionListener(this);
 2896               JList.this.getModel().addListDataListener(this);
 2897               leadSelectionIndex = JList.this.getLeadSelectionIndex();
 2898           }
 2899   
 2900           /**
 2901            * Property Change Listener change method. Used to track changes
 2902            * to the DataModel and ListSelectionModel, in order to re-set
 2903            * listeners to those for reporting changes there via the Accessibility
 2904            * PropertyChange mechanism.
 2905            *
 2906            * @param e PropertyChangeEvent
 2907            */
 2908           public void propertyChange(PropertyChangeEvent e) {
 2909               String name = e.getPropertyName();
 2910               Object oldValue = e.getOldValue();
 2911               Object newValue = e.getNewValue();
 2912   
 2913                   // re-set listData listeners
 2914               if (name.compareTo("model") == 0) {
 2915   
 2916                   if (oldValue != null && oldValue instanceof ListModel) {
 2917                       ((ListModel) oldValue).removeListDataListener(this);
 2918                   }
 2919                   if (newValue != null && newValue instanceof ListModel) {
 2920                       ((ListModel) newValue).addListDataListener(this);
 2921                   }
 2922   
 2923                   // re-set listSelectionModel listeners
 2924               } else if (name.compareTo("selectionModel") == 0) {
 2925   
 2926                   if (oldValue != null && oldValue instanceof ListSelectionModel) {
 2927                       ((ListSelectionModel) oldValue).removeListSelectionListener(this);
 2928                   }
 2929                   if (newValue != null && newValue instanceof ListSelectionModel) {
 2930                       ((ListSelectionModel) newValue).addListSelectionListener(this);
 2931                   }
 2932   
 2933                   firePropertyChange(
 2934                       AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY,
 2935                       Boolean.valueOf(false), Boolean.valueOf(true));
 2936               }
 2937           }
 2938   
 2939           /**
 2940            * List Selection Listener value change method. Used to fire
 2941            * the property change
 2942            *
 2943            * @param e ListSelectionEvent
 2944            *
 2945            */
 2946           public void valueChanged(ListSelectionEvent e) {
 2947               int oldLeadSelectionIndex = leadSelectionIndex;
 2948               leadSelectionIndex = JList.this.getLeadSelectionIndex();
 2949               if (oldLeadSelectionIndex != leadSelectionIndex) {
 2950                   Accessible oldLS, newLS;
 2951                   oldLS = (oldLeadSelectionIndex >= 0)
 2952                           ? getAccessibleChild(oldLeadSelectionIndex)
 2953                           : null;
 2954                   newLS = (leadSelectionIndex >= 0)
 2955                           ? getAccessibleChild(leadSelectionIndex)
 2956                           : null;
 2957                   firePropertyChange(AccessibleContext.ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY,
 2958                                      oldLS, newLS);
 2959               }
 2960   
 2961               firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
 2962                                  Boolean.valueOf(false), Boolean.valueOf(true));
 2963               firePropertyChange(AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY,
 2964                                  Boolean.valueOf(false), Boolean.valueOf(true));
 2965   
 2966               // Process the State changes for Multiselectable
 2967               AccessibleStateSet s = getAccessibleStateSet();
 2968               ListSelectionModel lsm = JList.this.getSelectionModel();
 2969               if (lsm.getSelectionMode() != ListSelectionModel.SINGLE_SELECTION) {
 2970                   if (!s.contains(AccessibleState.MULTISELECTABLE)) {
 2971                       s.add(AccessibleState.MULTISELECTABLE);
 2972                       firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
 2973                                          null, AccessibleState.MULTISELECTABLE);
 2974                   }
 2975               } else {
 2976                   if (s.contains(AccessibleState.MULTISELECTABLE)) {
 2977                       s.remove(AccessibleState.MULTISELECTABLE);
 2978                       firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
 2979                                          AccessibleState.MULTISELECTABLE, null);
 2980                   }
 2981               }
 2982           }
 2983   
 2984           /**
 2985            * List Data Listener interval added method. Used to fire the visible data property change
 2986            *
 2987            * @param e ListDataEvent
 2988            *
 2989            */
 2990           public void intervalAdded(ListDataEvent e) {
 2991               firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
 2992                                  Boolean.valueOf(false), Boolean.valueOf(true));
 2993           }
 2994   
 2995           /**
 2996            * List Data Listener interval removed method. Used to fire the visible data property change
 2997            *
 2998            * @param e ListDataEvent
 2999            *
 3000            */
 3001           public void intervalRemoved(ListDataEvent e) {
 3002               firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
 3003                                  Boolean.valueOf(false), Boolean.valueOf(true));
 3004           }
 3005   
 3006           /**
 3007            * List Data Listener contents changed method. Used to fire the visible data property change
 3008            *
 3009            * @param e ListDataEvent
 3010            *
 3011            */
 3012            public void contentsChanged(ListDataEvent e) {
 3013                firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
 3014                                   Boolean.valueOf(false), Boolean.valueOf(true));
 3015            }
 3016   
 3017       // AccessibleContext methods
 3018   
 3019           /**
 3020            * Get the state set of this object.
 3021            *
 3022            * @return an instance of AccessibleState containing the current state
 3023            * of the object
 3024            * @see AccessibleState
 3025            */
 3026           public AccessibleStateSet getAccessibleStateSet() {
 3027               AccessibleStateSet states = super.getAccessibleStateSet();
 3028               if (selectionModel.getSelectionMode() !=
 3029                   ListSelectionModel.SINGLE_SELECTION) {
 3030                   states.add(AccessibleState.MULTISELECTABLE);
 3031               }
 3032               return states;
 3033           }
 3034   
 3035           /**
 3036            * Get the role of this object.
 3037            *
 3038            * @return an instance of AccessibleRole describing the role of the
 3039            * object
 3040            * @see AccessibleRole
 3041            */
 3042           public AccessibleRole getAccessibleRole() {
 3043               return AccessibleRole.LIST;
 3044           }
 3045   
 3046           /**
 3047            * Returns the <code>Accessible</code> child contained at
 3048            * the local coordinate <code>Point</code>, if one exists.
 3049            * Otherwise returns <code>null</code>.
 3050            *
 3051            * @return the <code>Accessible</code> at the specified
 3052            *    location, if it exists
 3053            */
 3054           public Accessible getAccessibleAt(Point p) {
 3055               int i = locationToIndex(p);
 3056               if (i >= 0) {
 3057                   return new AccessibleJListChild(JList.this, i);
 3058               } else {
 3059                   return null;
 3060               }
 3061           }
 3062   
 3063           /**
 3064            * Returns the number of accessible children in the object.  If all
 3065            * of the children of this object implement Accessible, than this
 3066            * method should return the number of children of this object.
 3067            *
 3068            * @return the number of accessible children in the object.
 3069            */
 3070           public int getAccessibleChildrenCount() {
 3071               return getModel().getSize();
 3072           }
 3073   
 3074           /**
 3075            * Return the nth Accessible child of the object.
 3076            *
 3077            * @param i zero-based index of child
 3078            * @return the nth Accessible child of the object
 3079            */
 3080           public Accessible getAccessibleChild(int i) {
 3081               if (i >= getModel().getSize()) {
 3082                   return null;
 3083               } else {
 3084                   return new AccessibleJListChild(JList.this, i);
 3085               }
 3086           }
 3087   
 3088           /**
 3089            * Get the AccessibleSelection associated with this object.  In the
 3090            * implementation of the Java Accessibility API for this class,
 3091            * return this object, which is responsible for implementing the
 3092            * AccessibleSelection interface on behalf of itself.
 3093            *
 3094            * @return this object
 3095            */
 3096           public AccessibleSelection getAccessibleSelection() {
 3097               return this;
 3098           }
 3099   
 3100   
 3101       // AccessibleSelection methods
 3102   
 3103           /**
 3104            * Returns the number of items currently selected.
 3105            * If no items are selected, the return value will be 0.
 3106            *
 3107            * @return the number of items currently selected.
 3108            */
 3109            public int getAccessibleSelectionCount() {
 3110                return JList.this.getSelectedIndices().length;
 3111            }
 3112   
 3113           /**
 3114            * Returns an Accessible representing the specified selected item
 3115            * in the object.  If there isn't a selection, or there are
 3116            * fewer items selected than the integer passed in, the return
 3117            * value will be <code>null</code>.
 3118            *
 3119            * @param i the zero-based index of selected items
 3120            * @return an Accessible containing the selected item
 3121            */
 3122            public Accessible getAccessibleSelection(int i) {
 3123                int len = getAccessibleSelectionCount();
 3124                if (i < 0 || i >= len) {
 3125                    return null;
 3126                } else {
 3127                    return getAccessibleChild(JList.this.getSelectedIndices()[i]);
 3128                }
 3129            }
 3130   
 3131           /**
 3132            * Returns true if the current child of this object is selected.
 3133            *
 3134            * @param i the zero-based index of the child in this Accessible
 3135            * object.
 3136            * @see AccessibleContext#getAccessibleChild
 3137            */
 3138           public boolean isAccessibleChildSelected(int i) {
 3139               return isSelectedIndex(i);
 3140           }
 3141   
 3142           /**
 3143            * Adds the specified selected item in the object to the object's
 3144            * selection.  If the object supports multiple selections,
 3145            * the specified item is added to any existing selection, otherwise
 3146            * it replaces any existing selection in the object.  If the
 3147            * specified item is already selected, this method has no effect.
 3148            *
 3149            * @param i the zero-based index of selectable items
 3150            */
 3151            public void addAccessibleSelection(int i) {
 3152                JList.this.addSelectionInterval(i, i);
 3153            }
 3154   
 3155           /**
 3156            * Removes the specified selected item in the object from the object's
 3157            * selection.  If the specified item isn't currently selected, this
 3158            * method has no effect.
 3159            *
 3160            * @param i the zero-based index of selectable items
 3161            */
 3162            public void removeAccessibleSelection(int i) {
 3163                JList.this.removeSelectionInterval(i, i);
 3164            }
 3165   
 3166           /**
 3167            * Clears the selection in the object, so that nothing in the
 3168            * object is selected.
 3169            */
 3170            public void clearAccessibleSelection() {
 3171                JList.this.clearSelection();
 3172            }
 3173   
 3174           /**
 3175            * Causes every selected item in the object to be selected
 3176            * if the object supports multiple selections.
 3177            */
 3178            public void selectAllAccessibleSelection() {
 3179                JList.this.addSelectionInterval(0, getAccessibleChildrenCount() -1);
 3180            }
 3181   
 3182             /**
 3183              * This class implements accessibility support appropriate
 3184              * for list children.
 3185              */
 3186           protected class AccessibleJListChild extends AccessibleContext
 3187                   implements Accessible, AccessibleComponent {
 3188               private JList<E>     parent = null;
 3189               private int       indexInParent;
 3190               private Component component = null;
 3191               private AccessibleContext accessibleContext = null;
 3192               private ListModel<E> listModel;
 3193               private ListCellRenderer<? super E> cellRenderer = null;
 3194   
 3195               public AccessibleJListChild(JList<E> parent, int indexInParent) {
 3196                   this.parent = parent;
 3197                   this.setAccessibleParent(parent);
 3198                   this.indexInParent = indexInParent;
 3199                   if (parent != null) {
 3200                       listModel = parent.getModel();
 3201                       cellRenderer = parent.getCellRenderer();
 3202                   }
 3203               }
 3204   
 3205               private Component getCurrentComponent() {
 3206                   return getComponentAtIndex(indexInParent);
 3207               }
 3208   
 3209               private AccessibleContext getCurrentAccessibleContext() {
 3210                   Component c = getComponentAtIndex(indexInParent);
 3211                   if (c instanceof Accessible) {
 3212                       return c.getAccessibleContext();
 3213                   } else {
 3214                       return null;
 3215                   }
 3216               }
 3217   
 3218               private Component getComponentAtIndex(int index) {
 3219                   if (index < 0 || index >= listModel.getSize()) {
 3220                       return null;
 3221                   }
 3222                   if ((parent != null)
 3223                           && (listModel != null)
 3224                           && cellRenderer != null) {
 3225                       E value = listModel.getElementAt(index);
 3226                       boolean isSelected = parent.isSelectedIndex(index);
 3227                       boolean isFocussed = parent.isFocusOwner()
 3228                               && (index == parent.getLeadSelectionIndex());
 3229                       return cellRenderer.getListCellRendererComponent(
 3230                               parent,
 3231                               value,
 3232                               index,
 3233                               isSelected,
 3234                               isFocussed);
 3235                   } else {
 3236                       return null;
 3237                   }
 3238               }
 3239   
 3240   
 3241               // Accessible Methods
 3242              /**
 3243               * Get the AccessibleContext for this object. In the
 3244               * implementation of the Java Accessibility API for this class,
 3245               * returns this object, which is its own AccessibleContext.
 3246               *
 3247               * @return this object
 3248               */
 3249               public AccessibleContext getAccessibleContext() {
 3250                   return this;
 3251               }
 3252   
 3253   
 3254               // AccessibleContext methods
 3255   
 3256               public String getAccessibleName() {
 3257                   AccessibleContext ac = getCurrentAccessibleContext();
 3258                   if (ac != null) {
 3259                       return ac.getAccessibleName();
 3260                   } else {
 3261                       return null;
 3262                   }
 3263               }
 3264   
 3265               public void setAccessibleName(String s) {
 3266                   AccessibleContext ac = getCurrentAccessibleContext();
 3267                   if (ac != null) {
 3268                       ac.setAccessibleName(s);
 3269                   }
 3270               }
 3271   
 3272               public String getAccessibleDescription() {
 3273                   AccessibleContext ac = getCurrentAccessibleContext();
 3274                   if (ac != null) {
 3275                       return ac.getAccessibleDescription();
 3276                   } else {
 3277                       return null;
 3278                   }
 3279               }
 3280   
 3281               public void setAccessibleDescription(String s) {
 3282                   AccessibleContext ac = getCurrentAccessibleContext();
 3283                   if (ac != null) {
 3284                       ac.setAccessibleDescription(s);
 3285                   }
 3286               }
 3287   
 3288               public AccessibleRole getAccessibleRole() {
 3289                   AccessibleContext ac = getCurrentAccessibleContext();
 3290                   if (ac != null) {
 3291                       return ac.getAccessibleRole();
 3292                   } else {
 3293                       return null;
 3294                   }
 3295               }
 3296   
 3297               public AccessibleStateSet getAccessibleStateSet() {
 3298                   AccessibleContext ac = getCurrentAccessibleContext();
 3299                   AccessibleStateSet s;
 3300                   if (ac != null) {
 3301                       s = ac.getAccessibleStateSet();
 3302                   } else {
 3303                       s = new AccessibleStateSet();
 3304                   }
 3305   
 3306                   s.add(AccessibleState.SELECTABLE);
 3307                   if (parent.isFocusOwner()
 3308                       && (indexInParent == parent.getLeadSelectionIndex())) {
 3309                       s.add(AccessibleState.ACTIVE);
 3310                   }
 3311                   if (parent.isSelectedIndex(indexInParent)) {
 3312                       s.add(AccessibleState.SELECTED);
 3313                   }
 3314                   if (this.isShowing()) {
 3315                       s.add(AccessibleState.SHOWING);
 3316                   } else if (s.contains(AccessibleState.SHOWING)) {
 3317                       s.remove(AccessibleState.SHOWING);
 3318                   }
 3319                   if (this.isVisible()) {
 3320                       s.add(AccessibleState.VISIBLE);
 3321                   } else if (s.contains(AccessibleState.VISIBLE)) {
 3322                       s.remove(AccessibleState.VISIBLE);
 3323                   }
 3324                   s.add(AccessibleState.TRANSIENT); // cell-rendered
 3325                   return s;
 3326               }
 3327   
 3328               public int getAccessibleIndexInParent() {
 3329                   return indexInParent;
 3330               }
 3331   
 3332               public int getAccessibleChildrenCount() {
 3333                   AccessibleContext ac = getCurrentAccessibleContext();
 3334                   if (ac != null) {
 3335                       return ac.getAccessibleChildrenCount();
 3336                   } else {
 3337                       return 0;
 3338                   }
 3339               }
 3340   
 3341               public Accessible getAccessibleChild(int i) {
 3342                   AccessibleContext ac = getCurrentAccessibleContext();
 3343                   if (ac != null) {
 3344                       Accessible accessibleChild = ac.getAccessibleChild(i);
 3345                       ac.setAccessibleParent(this);
 3346                       return accessibleChild;
 3347                   } else {
 3348                       return null;
 3349                   }
 3350               }
 3351   
 3352               public Locale getLocale() {
 3353                   AccessibleContext ac = getCurrentAccessibleContext();
 3354                   if (ac != null) {
 3355                       return ac.getLocale();
 3356                   } else {
 3357                       return null;
 3358                   }
 3359               }
 3360   
 3361               public void addPropertyChangeListener(PropertyChangeListener l) {
 3362                   AccessibleContext ac = getCurrentAccessibleContext();
 3363                   if (ac != null) {
 3364                       ac.addPropertyChangeListener(l);
 3365                   }
 3366               }
 3367   
 3368               public void removePropertyChangeListener(PropertyChangeListener l) {
 3369                   AccessibleContext ac = getCurrentAccessibleContext();
 3370                   if (ac != null) {
 3371                       ac.removePropertyChangeListener(l);
 3372                   }
 3373               }
 3374   
 3375               public AccessibleAction getAccessibleAction() {
 3376                   return getCurrentAccessibleContext().getAccessibleAction();
 3377               }
 3378   
 3379              /**
 3380               * Get the AccessibleComponent associated with this object.  In the
 3381               * implementation of the Java Accessibility API for this class,
 3382               * return this object, which is responsible for implementing the
 3383               * AccessibleComponent interface on behalf of itself.
 3384               *
 3385               * @return this object
 3386               */
 3387               public AccessibleComponent getAccessibleComponent() {
 3388                   return this; // to override getBounds()
 3389               }
 3390   
 3391               public AccessibleSelection getAccessibleSelection() {
 3392                   return getCurrentAccessibleContext().getAccessibleSelection();
 3393               }
 3394   
 3395               public AccessibleText getAccessibleText() {
 3396                   return getCurrentAccessibleContext().getAccessibleText();
 3397               }
 3398   
 3399               public AccessibleValue getAccessibleValue() {
 3400                   return getCurrentAccessibleContext().getAccessibleValue();
 3401               }
 3402   
 3403   
 3404               // AccessibleComponent methods
 3405   
 3406               public Color getBackground() {
 3407                   AccessibleContext ac = getCurrentAccessibleContext();
 3408                   if (ac instanceof AccessibleComponent) {
 3409                       return ((AccessibleComponent) ac).getBackground();
 3410                   } else {
 3411                       Component c = getCurrentComponent();
 3412                       if (c != null) {
 3413                           return c.getBackground();
 3414                       } else {
 3415                           return null;
 3416                       }
 3417                   }
 3418               }
 3419   
 3420               public void setBackground(Color c) {
 3421                   AccessibleContext ac = getCurrentAccessibleContext();
 3422                   if (ac instanceof AccessibleComponent) {
 3423                       ((AccessibleComponent) ac).setBackground(c);
 3424                   } else {
 3425                       Component cp = getCurrentComponent();
 3426                       if (cp != null) {
 3427                           cp.setBackground(c);
 3428                       }
 3429                   }
 3430               }
 3431   
 3432               public Color getForeground() {
 3433                   AccessibleContext ac = getCurrentAccessibleContext();
 3434                   if (ac instanceof AccessibleComponent) {
 3435                       return ((AccessibleComponent) ac).getForeground();
 3436                   } else {
 3437                       Component c = getCurrentComponent();
 3438                       if (c != null) {
 3439                           return c.getForeground();
 3440                       } else {
 3441                           return null;
 3442                       }
 3443                   }
 3444               }
 3445   
 3446               public void setForeground(Color c) {
 3447                   AccessibleContext ac = getCurrentAccessibleContext();
 3448                   if (ac instanceof AccessibleComponent) {
 3449                       ((AccessibleComponent) ac).setForeground(c);
 3450                   } else {
 3451                       Component cp = getCurrentComponent();
 3452                       if (cp != null) {
 3453                           cp.setForeground(c);
 3454                       }
 3455                   }
 3456               }
 3457   
 3458               public Cursor getCursor() {
 3459                   AccessibleContext ac = getCurrentAccessibleContext();
 3460                   if (ac instanceof AccessibleComponent) {
 3461                       return ((AccessibleComponent) ac).getCursor();
 3462                   } else {
 3463                       Component c = getCurrentComponent();
 3464                       if (c != null) {
 3465                           return c.getCursor();
 3466                       } else {
 3467                           Accessible ap = getAccessibleParent();
 3468                           if (ap instanceof AccessibleComponent) {
 3469                               return ((AccessibleComponent) ap).getCursor();
 3470                           } else {
 3471                               return null;
 3472                           }
 3473                       }
 3474                   }
 3475               }
 3476   
 3477               public void setCursor(Cursor c) {
 3478                   AccessibleContext ac = getCurrentAccessibleContext();
 3479                   if (ac instanceof AccessibleComponent) {
 3480                       ((AccessibleComponent) ac).setCursor(c);
 3481                   } else {
 3482                       Component cp = getCurrentComponent();
 3483                       if (cp != null) {
 3484                           cp.setCursor(c);
 3485                       }
 3486                   }
 3487               }
 3488   
 3489               public Font getFont() {
 3490                   AccessibleContext ac = getCurrentAccessibleContext();
 3491                   if (ac instanceof AccessibleComponent) {
 3492                       return ((AccessibleComponent) ac).getFont();
 3493                   } else {
 3494                       Component c = getCurrentComponent();
 3495                       if (c != null) {
 3496                           return c.getFont();
 3497                       } else {
 3498                           return null;
 3499                       }
 3500                   }
 3501               }
 3502   
 3503               public void setFont(Font f) {
 3504                   AccessibleContext ac = getCurrentAccessibleContext();
 3505                   if (ac instanceof AccessibleComponent) {
 3506                       ((AccessibleComponent) ac).setFont(f);
 3507                   } else {
 3508                       Component c = getCurrentComponent();
 3509                       if (c != null) {
 3510                           c.setFont(f);
 3511                       }
 3512                   }
 3513               }
 3514   
 3515               public FontMetrics getFontMetrics(Font f) {
 3516                   AccessibleContext ac = getCurrentAccessibleContext();
 3517                   if (ac instanceof AccessibleComponent) {
 3518                       return ((AccessibleComponent) ac).getFontMetrics(f);
 3519                   } else {
 3520                       Component c = getCurrentComponent();
 3521                       if (c != null) {
 3522                           return c.getFontMetrics(f);
 3523                       } else {
 3524                           return null;
 3525                       }
 3526                   }
 3527               }
 3528   
 3529               public boolean isEnabled() {
 3530                   AccessibleContext ac = getCurrentAccessibleContext();
 3531                   if (ac instanceof AccessibleComponent) {
 3532                       return ((AccessibleComponent) ac).isEnabled();
 3533                   } else {
 3534                       Component c = getCurrentComponent();
 3535                       if (c != null) {
 3536                           return c.isEnabled();
 3537                       } else {
 3538                           return false;
 3539                       }
 3540                   }
 3541               }
 3542   
 3543               public void setEnabled(boolean b) {
 3544                   AccessibleContext ac = getCurrentAccessibleContext();
 3545                   if (ac instanceof AccessibleComponent) {
 3546                       ((AccessibleComponent) ac).setEnabled(b);
 3547                   } else {
 3548                       Component c = getCurrentComponent();
 3549                       if (c != null) {
 3550                           c.setEnabled(b);
 3551                       }
 3552                   }
 3553               }
 3554   
 3555               public boolean isVisible() {
 3556                   int fi = parent.getFirstVisibleIndex();
 3557                   int li = parent.getLastVisibleIndex();
 3558                   // The UI incorrectly returns a -1 for the last
 3559                   // visible index if the list is smaller than the
 3560                   // viewport size.
 3561                   if (li == -1) {
 3562                       li = parent.getModel().getSize() - 1;
 3563                   }
 3564                   return ((indexInParent >= fi)
 3565                           && (indexInParent <= li));
 3566               }
 3567   
 3568               public void setVisible(boolean b) {
 3569               }
 3570   
 3571               public boolean isShowing() {
 3572                   return (parent.isShowing() && isVisible());
 3573               }
 3574   
 3575               public boolean contains(Point p) {
 3576                   AccessibleContext ac = getCurrentAccessibleContext();
 3577                   if (ac instanceof AccessibleComponent) {
 3578                       Rectangle r = ((AccessibleComponent) ac).getBounds();
 3579                       return r.contains(p);
 3580                   } else {
 3581                       Component c = getCurrentComponent();
 3582                       if (c != null) {
 3583                           Rectangle r = c.getBounds();
 3584                           return r.contains(p);
 3585                       } else {
 3586                           return getBounds().contains(p);
 3587                       }
 3588                   }
 3589               }
 3590   
 3591               public Point getLocationOnScreen() {
 3592                   if (parent != null) {
 3593                       Point listLocation = parent.getLocationOnScreen();
 3594                       Point componentLocation = parent.indexToLocation(indexInParent);
 3595                       if (componentLocation != null) {
 3596                           componentLocation.translate(listLocation.x, listLocation.y);
 3597                           return componentLocation;
 3598                       } else {
 3599                           return null;
 3600                       }
 3601                   } else {
 3602                       return null;
 3603                   }
 3604               }
 3605   
 3606               public Point getLocation() {
 3607                   if (parent != null) {
 3608                       return parent.indexToLocation(indexInParent);
 3609                   } else {
 3610                       return null;
 3611                   }
 3612               }
 3613   
 3614               public void setLocation(Point p) {
 3615                   if ((parent != null)  && (parent.contains(p))) {
 3616                       ensureIndexIsVisible(indexInParent);
 3617                   }
 3618               }
 3619   
 3620               public Rectangle getBounds() {
 3621                   if (parent != null) {
 3622                       return parent.getCellBounds(indexInParent,indexInParent);
 3623                   } else {
 3624                       return null;
 3625                   }
 3626               }
 3627   
 3628               public void setBounds(Rectangle r) {
 3629                   AccessibleContext ac = getCurrentAccessibleContext();
 3630                   if (ac instanceof AccessibleComponent) {
 3631                       ((AccessibleComponent) ac).setBounds(r);
 3632                   }
 3633               }
 3634   
 3635               public Dimension getSize() {
 3636                   Rectangle cellBounds = this.getBounds();
 3637                   if (cellBounds != null) {
 3638                       return cellBounds.getSize();
 3639                   } else {
 3640                       return null;
 3641                   }
 3642               }
 3643   
 3644               public void setSize (Dimension d) {
 3645                   AccessibleContext ac = getCurrentAccessibleContext();
 3646                   if (ac instanceof AccessibleComponent) {
 3647                       ((AccessibleComponent) ac).setSize(d);
 3648                   } else {
 3649                       Component c = getCurrentComponent();
 3650                       if (c != null) {
 3651                           c.setSize(d);
 3652                       }
 3653                   }
 3654               }
 3655   
 3656               public Accessible getAccessibleAt(Point p) {
 3657                   AccessibleContext ac = getCurrentAccessibleContext();
 3658                   if (ac instanceof AccessibleComponent) {
 3659                       return ((AccessibleComponent) ac).getAccessibleAt(p);
 3660                   } else {
 3661                       return null;
 3662                   }
 3663               }
 3664   
 3665               public boolean isFocusTraversable() {
 3666                   AccessibleContext ac = getCurrentAccessibleContext();
 3667                   if (ac instanceof AccessibleComponent) {
 3668                       return ((AccessibleComponent) ac).isFocusTraversable();
 3669                   } else {
 3670                       Component c = getCurrentComponent();
 3671                       if (c != null) {
 3672                           return c.isFocusTraversable();
 3673                       } else {
 3674                           return false;
 3675                       }
 3676                   }
 3677               }
 3678   
 3679               public void requestFocus() {
 3680                   AccessibleContext ac = getCurrentAccessibleContext();
 3681                   if (ac instanceof AccessibleComponent) {
 3682                       ((AccessibleComponent) ac).requestFocus();
 3683                   } else {
 3684                       Component c = getCurrentComponent();
 3685                       if (c != null) {
 3686                           c.requestFocus();
 3687                       }
 3688                   }
 3689               }
 3690   
 3691               public void addFocusListener(FocusListener l) {
 3692                   AccessibleContext ac = getCurrentAccessibleContext();
 3693                   if (ac instanceof AccessibleComponent) {
 3694                       ((AccessibleComponent) ac).addFocusListener(l);
 3695                   } else {
 3696                       Component c = getCurrentComponent();
 3697                       if (c != null) {
 3698                           c.addFocusListener(l);
 3699                       }
 3700                   }
 3701               }
 3702   
 3703               public void removeFocusListener(FocusListener l) {
 3704                   AccessibleContext ac = getCurrentAccessibleContext();
 3705                   if (ac instanceof AccessibleComponent) {
 3706                       ((AccessibleComponent) ac).removeFocusListener(l);
 3707                   } else {
 3708                       Component c = getCurrentComponent();
 3709                       if (c != null) {
 3710                           c.removeFocusListener(l);
 3711                       }
 3712                   }
 3713               }
 3714   
 3715               // TIGER - 4733624
 3716               /**
 3717                * Returns the icon for the element renderer, as the only item
 3718                * of an array of <code>AccessibleIcon</code>s or a <code>null</code> array
 3719                * if the renderer component contains no icons.
 3720                *
 3721                * @return an array containing the accessible icon
 3722                *         or a <code>null</code> array if none
 3723                * @since 1.3
 3724                */
 3725               public AccessibleIcon [] getAccessibleIcon() {
 3726                   AccessibleContext ac = getCurrentAccessibleContext();
 3727                   if (ac != null) {
 3728                       return ac.getAccessibleIcon();
 3729                   } else {
 3730                       return null;
 3731                   }
 3732               }
 3733           } // inner class AccessibleJListChild
 3734       } // inner class AccessibleJList
 3735   }

Home » openjdk-7 » javax » swing » [javadoc | source]