Save This Page
Home » openjdk-7 » javax » swing » [javadoc | source]
    1   /*
    2    * Copyright 1997-2008 Sun Microsystems, Inc.  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.  Sun designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   22    * CA 95054 USA or visit www.sun.com if you need additional information or
   23    * have any questions.
   24    */
   25   
   26   package javax.swing;
   27   
   28   import java.awt.event;
   29   import java.awt;
   30   
   31   import java.util.Vector;
   32   import java.util.Locale;
   33   
   34   import java.beans.PropertyChangeEvent;
   35   import java.beans.PropertyChangeListener;
   36   import java.beans.Transient;
   37   
   38   import javax.swing.event;
   39   import javax.accessibility;
   40   import javax.swing.plaf;
   41   import javax.swing.text.Position;
   42   
   43   import java.io.ObjectOutputStream;
   44   import java.io.ObjectInputStream;
   45   import java.io.IOException;
   46   import java.io.Serializable;
   47   
   48   import sun.swing.SwingUtilities2;
   49   import sun.swing.SwingUtilities2.Section;
   50   import static sun.swing.SwingUtilities2.Section.*;
   51   
   52   
   53   /**
   54    * A component that displays a list of objects and allows the user to select
   55    * one or more items. A separate model, {@code ListModel}, maintains the
   56    * contents of the list.
   57    * <p>
   58    * It's easy to display an array or Vector of objects, using the {@code JList}
   59    * constructor that automatically builds a read-only {@code ListModel} instance
   60    * for you:
   61    * <pre>
   62    * // Create a JList that displays strings from an array
   63    *
   64    * String[] data = {"one", "two", "three", "four"};
   65    * JList myList = new JList(data);
   66    *
   67    * // Create a JList that displays the superclasses of JList.class, by
   68    * // creating it with a Vector populated with this data
   69    *
   70    * Vector superClasses = new Vector();
   71    * Class rootClass = javax.swing.JList.class;
   72    * for(Class cls = rootClass; cls != null; cls = cls.getSuperclass()) {
   73    *     superClasses.addElement(cls);
   74    * }
   75    * JList myList = new JList(superClasses);
   76    *
   77    * // The automatically created model is stored in JList's "model"
   78    * // property, which you can retrieve
   79    *
   80    * ListModel model = myList.getModel();
   81    * for(int i = 0; i < model.getSize(); i++) {
   82    *     System.out.println(model.getElementAt(i));
   83    * }
   84    * </pre>
   85    * <p>
   86    * A {@code ListModel} can be supplied directly to a {@code JList} by way of a
   87    * constructor or the {@code setModel} method. The contents need not be static -
   88    * the number of items, and the values of items can change over time. A correct
   89    * {@code ListModel} implementation notifies the set of
   90    * {@code javax.swing.event.ListDataListener}s that have been added to it, each
   91    * time a change occurs. These changes are characterized by a
   92    * {@code javax.swing.event.ListDataEvent}, which identifies the range of list
   93    * indices that have been modified, added, or removed. {@code JList}'s
   94    * {@code ListUI} is responsible for keeping the visual representation up to
   95    * date with changes, by listening to the model.
   96    * <p>
   97    * Simple, dynamic-content, {@code JList} applications can use the
   98    * {@code DefaultListModel} class to maintain list elements. This class
   99    * implements the {@code ListModel} interface and also provides a
  100    * <code>java.util.Vector</code>-like API. Applications that need a more
  101    * custom <code>ListModel</code> implementation may instead wish to subclass
  102    * {@code AbstractListModel}, which provides basic support for managing and
  103    * notifying listeners. For example, a read-only implementation of
  104    * {@code AbstractListModel}:
  105    * <pre>
  106    * // This list model has about 2^16 elements.  Enjoy scrolling.
  107    *
  108    * ListModel bigData = new AbstractListModel() {
  109    *     public int getSize() { return Short.MAX_VALUE; }
  110    *     public Object getElementAt(int index) { return "Index " + index; }
  111    * };
  112    * </pre>
  113    * <p>
  114    * The selection state of a {@code JList} is managed by another separate
  115    * model, an instance of {@code ListSelectionModel}. {@code JList} is
  116    * initialized with a selection model on construction, and also contains
  117    * methods to query or set this selection model. Additionally, {@code JList}
  118    * provides convenient methods for easily managing the selection. These methods,
  119    * such as {@code setSelectedIndex} and {@code getSelectedValue}, are cover
  120    * methods that take care of the details of interacting with the selection
  121    * model. By default, {@code JList}'s selection model is configured to allow any
  122    * combination of items to be selected at a time; selection mode
  123    * {@code MULTIPLE_INTERVAL_SELECTION}. The selection mode can be changed
  124    * on the selection model directly, or via {@code JList}'s cover method.
  125    * Responsibility for updating the selection model in response to user gestures
  126    * lies with the list's {@code ListUI}.
  127    * <p>
  128    * A correct {@code ListSelectionModel} implementation notifies the set of
  129    * {@code javax.swing.event.ListSelectionListener}s that have been added to it
  130    * each time a change to the selection occurs. These changes are characterized
  131    * by a {@code javax.swing.event.ListSelectionEvent}, which identifies the range
  132    * of the selection change.
  133    * <p>
  134    * The preferred way to listen for changes in list selection is to add
  135    * {@code ListSelectionListener}s directly to the {@code JList}. {@code JList}
  136    * then takes care of listening to the the selection model and notifying your
  137    * listeners of change.
  138    * <p>
  139    * Responsibility for listening to selection changes in order to keep the list's
  140    * visual representation up to date lies with the list's {@code ListUI}.
  141    * <p>
  142    * <a name="renderer">
  143    * Painting of cells in a {@code JList} is handled by a delegate called a
  144    * cell renderer, installed on the list as the {@code cellRenderer} property.
  145    * The renderer provides a {@code java.awt.Component} that is used
  146    * like a "rubber stamp" to paint the cells. Each time a cell needs to be
  147    * painted, the list's {@code ListUI} asks the cell renderer for the component,
  148    * moves it into place, and has it paint the contents of the cell by way of its
  149    * {@code paint} method. A default cell renderer, which uses a {@code JLabel}
  150    * component to render, is installed by the lists's {@code ListUI}. You can
  151    * substitute your own renderer using code like this:
  152    * <pre>
  153    *  // Display an icon and a string for each object in the list.
  154    *
  155    * class MyCellRenderer extends JLabel implements ListCellRenderer {
  156    *     final static ImageIcon longIcon = new ImageIcon("long.gif");
  157    *     final static ImageIcon shortIcon = new ImageIcon("short.gif");
  158    *
  159    *     // This is the only method defined by ListCellRenderer.
  160    *     // We just reconfigure the JLabel each time we're called.
  161    *
  162    *     public Component getListCellRendererComponent(
  163    *       JList list,              // the list
  164    *       Object value,            // value to display
  165    *       int index,               // cell index
  166    *       boolean isSelected,      // is the cell selected
  167    *       boolean cellHasFocus)    // does the cell have focus
  168    *     {
  169    *         String s = value.toString();
  170    *         setText(s);
  171    *         setIcon((s.length() > 10) ? longIcon : shortIcon);
  172    *         if (isSelected) {
  173    *             setBackground(list.getSelectionBackground());
  174    *             setForeground(list.getSelectionForeground());
  175    *         } else {
  176    *             setBackground(list.getBackground());
  177    *             setForeground(list.getForeground());
  178    *         }
  179    *         setEnabled(list.isEnabled());
  180    *         setFont(list.getFont());
  181    *         setOpaque(true);
  182    *         return this;
  183    *     }
  184    * }
  185    *
  186    * myList.setCellRenderer(new MyCellRenderer());
  187    * </pre>
  188    * <p>
  189    * Another job for the cell renderer is in helping to determine sizing
  190    * information for the list. By default, the list's {@code ListUI} determines
  191    * the size of cells by asking the cell renderer for its preferred
  192    * size for each list item. This can be expensive for large lists of items.
  193    * To avoid these calculations, you can set a {@code fixedCellWidth} and
  194    * {@code fixedCellHeight} on the list, or have these values calculated
  195    * automatically based on a single prototype value:
  196    * <a name="prototype_example">
  197    * <pre>
  198    * JList bigDataList = new JList(bigData);
  199    *
  200    * // We don't want the JList implementation to compute the width
  201    * // or height of all of the list cells, so we give it a string
  202    * // that's as big as we'll need for any cell.  It uses this to
  203    * // compute values for the fixedCellWidth and fixedCellHeight
  204    * // properties.
  205    *
  206    * bigDataList.setPrototypeCellValue("Index 1234567890");
  207    * </pre>
  208    * <p>
  209    * {@code JList} doesn't implement scrolling directly. To create a list that
  210    * scrolls, make it the viewport view of a {@code JScrollPane}. For example:
  211    * <pre>
  212    * JScrollPane scrollPane = new JScrollPane(myList);
  213    *
  214    * // Or in two steps:
  215    * JScrollPane scrollPane = new JScrollPane();
  216    * scrollPane.getViewport().setView(myList);
  217    * </pre>
  218    * <p>
  219    * {@code JList} doesn't provide any special handling of double or triple
  220    * (or N) mouse clicks, but it's easy to add a {@code MouseListener} if you
  221    * wish to take action on these events. Use the {@code locationToIndex}
  222    * method to determine what cell was clicked. For example:
  223    * <pre>
  224    * MouseListener mouseListener = new MouseAdapter() {
  225    *     public void mouseClicked(MouseEvent e) {
  226    *         if (e.getClickCount() == 2) {
  227    *             int index = list.locationToIndex(e.getPoint());
  228    *             System.out.println("Double clicked on Item " + index);
  229    *          }
  230    *     }
  231    * };
  232    * list.addMouseListener(mouseListener);
  233    * </pre>
  234    * <p>
  235    * <strong>Warning:</strong> Swing is not thread safe. For more
  236    * information see <a
  237    * href="package-summary.html#threading">Swing's Threading
  238    * Policy</a>.
  239    * <p>
  240    * <strong>Warning:</strong>
  241    * Serialized objects of this class will not be compatible with
  242    * future Swing releases. The current serialization support is
  243    * appropriate for short term storage or RMI between applications running
  244    * the same version of Swing.  As of 1.4, support for long term storage
  245    * of all JavaBeans<sup><font size="-2">TM</font></sup>
  246    * has been added to the <code>java.beans</code> package.
  247    * Please see {@link java.beans.XMLEncoder}.
  248    * <p>
  249    * See <a href="http://java.sun.com/docs/books/tutorial/uiswing/components/list.html">How to Use Lists</a>
  250    * in <a href="http://java.sun.com/Series/Tutorial/index.html"><em>The Java Tutorial</em></a>
  251    * for further documentation.
  252    * Also see the article <a href="http://java.sun.com/products/jfc/tsc/tech_topics/jlist_1/jlist.html">Advanced JList Programming</a>
  253    * in <a href="http://java.sun.com/products/jfc/tsc"><em>The Swing Connection</em></a>.
  254    * <p>
  255    * @see ListModel
  256    * @see AbstractListModel
  257    * @see DefaultListModel
  258    * @see ListSelectionModel
  259    * @see DefaultListSelectionModel
  260    * @see ListCellRenderer
  261    * @see DefaultListCellRenderer
  262    *
  263    * @beaninfo
  264    *   attribute: isContainer false
  265    * description: A component which allows for the selection of one or more objects from a list.
  266    *
  267    * @author Hans Muller
  268    */
  269   public class JList extends JComponent implements Scrollable, Accessible
  270   {
  271       /**
  272        * @see #getUIClassID
  273        * @see #readObject
  274        */
  275       private static final String uiClassID = "ListUI";
  276   
  277       /**
  278        * Indicates a vertical layout of cells, in a single column;
  279        * the default layout.
  280        * @see #setLayoutOrientation
  281        * @since 1.4
  282        */
  283       public static final int VERTICAL = 0;
  284   
  285       /**
  286        * Indicates a "newspaper style" layout with cells flowing vertically
  287        * then horizontally.
  288        * @see #setLayoutOrientation
  289        * @since 1.4
  290        */
  291       public static final int VERTICAL_WRAP = 1;
  292   
  293       /**
  294        * Indicates a "newspaper style" layout with cells flowing horizontally
  295        * then vertically.
  296        * @see #setLayoutOrientation
  297        * @since 1.4
  298        */
  299       public static final int HORIZONTAL_WRAP = 2;
  300   
  301       private int fixedCellWidth = -1;
  302       private int fixedCellHeight = -1;
  303       private int horizontalScrollIncrement = -1;
  304       private Object prototypeCellValue;
  305       private int visibleRowCount = 8;
  306       private Color selectionForeground;
  307       private Color selectionBackground;
  308       private boolean dragEnabled;
  309   
  310       private ListSelectionModel selectionModel;
  311       private ListModel dataModel;
  312       private ListCellRenderer cellRenderer;
  313       private ListSelectionListener selectionListener;
  314   
  315       /**
  316        * How to lay out the cells; defaults to <code>VERTICAL</code>.
  317        */
  318       private int layoutOrientation;
  319   
  320       /**
  321        * The drop mode for this component.
  322        */
  323       private DropMode dropMode = DropMode.USE_SELECTION;
  324   
  325       /**
  326        * The drop location.
  327        */
  328       private transient DropLocation dropLocation;
  329   
  330       /**
  331        * A subclass of <code>TransferHandler.DropLocation</code> representing
  332        * a drop location for a <code>JList</code>.
  333        *
  334        * @see #getDropLocation
  335        * @since 1.6
  336        */
  337       public static final class DropLocation extends TransferHandler.DropLocation {
  338           private final int index;
  339           private final boolean isInsert;
  340   
  341           private DropLocation(Point p, int index, boolean isInsert) {
  342               super(p);
  343               this.index = index;
  344               this.isInsert = isInsert;
  345           }
  346   
  347           /**
  348            * Returns the index where dropped data should be placed in the
  349            * list. Interpretation of the value depends on the drop mode set on
  350            * the associated component. If the drop mode is either
  351            * <code>DropMode.USE_SELECTION</code> or <code>DropMode.ON</code>,
  352            * the return value is an index of a row in the list. If the drop mode is
  353            * <code>DropMode.INSERT</code>, the return value refers to the index
  354            * where the data should be inserted. If the drop mode is
  355            * <code>DropMode.ON_OR_INSERT</code>, the value of
  356            * <code>isInsert()</code> indicates whether the index is an index
  357            * of a row, or an insert index.
  358            * <p>
  359            * <code>-1</code> indicates that the drop occurred over empty space,
  360            * and no index could be calculated.
  361            *
  362            * @return the drop index
  363            */
  364           public int getIndex() {
  365               return index;
  366           }
  367   
  368           /**
  369            * Returns whether or not this location represents an insert
  370            * location.
  371            *
  372            * @return whether or not this is an insert location
  373            */
  374           public boolean isInsert() {
  375               return isInsert;
  376           }
  377   
  378           /**
  379            * Returns a string representation of this drop location.
  380            * This method is intended to be used for debugging purposes,
  381            * and the content and format of the returned string may vary
  382            * between implementations.
  383            *
  384            * @return a string representation of this drop location
  385            */
  386           public String toString() {
  387               return getClass().getName()
  388                      + "[dropPoint=" + getDropPoint() + ","
  389                      + "index=" + index + ","
  390                      + "insert=" + isInsert + "]";
  391           }
  392       }
  393   
  394       /**
  395        * Constructs a {@code JList} that displays elements from the specified,
  396        * {@code non-null}, model. All {@code JList} constructors delegate to
  397        * this one.
  398        * <p>
  399        * This constructor registers the list with the {@code ToolTipManager},
  400        * allowing for tooltips to be provided by the cell renderers.
  401        *
  402        * @param dataModel the model for the list
  403        * @exception IllegalArgumentException if the model is {@code null}
  404        */
  405       public JList(ListModel dataModel)
  406       {
  407           if (dataModel == null) {
  408               throw new IllegalArgumentException("dataModel must be non null");
  409           }
  410   
  411           // Register with the ToolTipManager so that tooltips from the
  412           // renderer show through.
  413           ToolTipManager toolTipManager = ToolTipManager.sharedInstance();
  414           toolTipManager.registerComponent(this);
  415   
  416           layoutOrientation = VERTICAL;
  417   
  418           this.dataModel = dataModel;
  419           selectionModel = createSelectionModel();
  420           setAutoscrolls(true);
  421           setOpaque(true);
  422           updateUI();
  423       }
  424   
  425   
  426       /**
  427        * Constructs a <code>JList</code> that displays the elements in
  428        * the specified array. This constructor creates a read-only model
  429        * for the given array, and then delegates to the constructor that
  430        * takes a {@code ListModel}.
  431        * <p>
  432        * Attempts to pass a {@code null} value to this method results in
  433        * undefined behavior and, most likely, exceptions. The created model
  434        * references the given array directly. Attempts to modify the array
  435        * after constructing the list results in undefined behavior.
  436        *
  437        * @param  listData  the array of Objects to be loaded into the data model,
  438        *                   {@code non-null}
  439        */
  440       public JList(final Object[] listData)
  441       {
  442           this (
  443               new AbstractListModel() {
  444                   public int getSize() { return listData.length; }
  445                   public Object getElementAt(int i) { return listData[i]; }
  446               }
  447           );
  448       }
  449   
  450   
  451       /**
  452        * Constructs a <code>JList</code> that displays the elements in
  453        * the specified <code>Vector</code>. This constructor creates a read-only
  454        * model for the given {@code Vector}, and then delegates to the constructor
  455        * that takes a {@code ListModel}.
  456        * <p>
  457        * Attempts to pass a {@code null} value to this method results in
  458        * undefined behavior and, most likely, exceptions. The created model
  459        * references the given {@code Vector} directly. Attempts to modify the
  460        * {@code Vector} after constructing the list results in undefined behavior.
  461        *
  462        * @param  listData  the <code>Vector</code> to be loaded into the
  463        *                   data model, {@code non-null}
  464        */
  465       public JList(final Vector<?> listData) {
  466           this (
  467               new AbstractListModel() {
  468                   public int getSize() { return listData.size(); }
  469                   public Object getElementAt(int i) { return listData.elementAt(i); }
  470               }
  471           );
  472       }
  473   
  474   
  475       /**
  476        * Constructs a <code>JList</code> with an empty, read-only, model.
  477        */
  478       public JList() {
  479           this (
  480               new AbstractListModel() {
  481                 public int getSize() { return 0; }
  482                 public Object getElementAt(int i) { return "No Data Model"; }
  483               }
  484           );
  485       }
  486   
  487   
  488       /**
  489        * Returns the {@code ListUI}, the look and feel object that
  490        * renders this component.
  491        *
  492        * @return the <code>ListUI</code> object that renders this component
  493        */
  494       public ListUI getUI() {
  495           return (ListUI)ui;
  496       }
  497   
  498   
  499       /**
  500        * Sets the {@code ListUI}, the look and feel object that
  501        * renders this component.
  502        *
  503        * @param ui  the <code>ListUI</code> object
  504        * @see UIDefaults#getUI
  505        * @beaninfo
  506        *        bound: true
  507        *       hidden: true
  508        *    attribute: visualUpdate true
  509        *  description: The UI object that implements the Component's LookAndFeel.
  510        */
  511       public void setUI(ListUI ui) {
  512           super.setUI(ui);
  513       }
  514   
  515   
  516       /**
  517        * Resets the {@code ListUI} property by setting it to the value provided
  518        * by the current look and feel. If the current cell renderer was installed
  519        * by the developer (rather than the look and feel itself), this also causes
  520        * the cell renderer and its children to be updated, by calling
  521        * {@code SwingUtilities.updateComponentTreeUI} on it.
  522        *
  523        * @see UIManager#getUI
  524        * @see SwingUtilities#updateComponentTreeUI
  525        */
  526       public void updateUI() {
  527           setUI((ListUI)UIManager.getUI(this));
  528   
  529           ListCellRenderer renderer = getCellRenderer();
  530           if (renderer instanceof Component) {
  531               SwingUtilities.updateComponentTreeUI((Component)renderer);
  532           }
  533       }
  534   
  535   
  536       /**
  537        * Returns {@code "ListUI"}, the <code>UIDefaults</code> key used to look
  538        * up the name of the {@code javax.swing.plaf.ListUI} class that defines
  539        * the look and feel for this component.
  540        *
  541        * @return the string "ListUI"
  542        * @see JComponent#getUIClassID
  543        * @see UIDefaults#getUI
  544        */
  545       public String getUIClassID() {
  546           return uiClassID;
  547       }
  548   
  549   
  550       /* -----private-----
  551        * This method is called by setPrototypeCellValue and setCellRenderer
  552        * to update the fixedCellWidth and fixedCellHeight properties from the
  553        * current value of prototypeCellValue (if it's non null).
  554        * <p>
  555        * This method sets fixedCellWidth and fixedCellHeight but does <b>not</b>
  556        * generate PropertyChangeEvents for them.
  557        *
  558        * @see #setPrototypeCellValue
  559        * @see #setCellRenderer
  560        */
  561       private void updateFixedCellSize()
  562       {
  563           ListCellRenderer cr = getCellRenderer();
  564           Object value = getPrototypeCellValue();
  565   
  566           if ((cr != null) && (value != null)) {
  567               Component c = cr.getListCellRendererComponent(this, value, 0, false, false);
  568   
  569               /* The ListUI implementation will add Component c to its private
  570                * CellRendererPane however we can't assume that's already
  571                * been done here.  So we temporarily set the one "inherited"
  572                * property that may affect the renderer components preferred size:
  573                * its font.
  574                */
  575               Font f = c.getFont();
  576               c.setFont(getFont());
  577   
  578               Dimension d = c.getPreferredSize();
  579               fixedCellWidth = d.width;
  580               fixedCellHeight = d.height;
  581   
  582               c.setFont(f);
  583           }
  584       }
  585   
  586   
  587       /**
  588        * Returns the "prototypical" cell value -- a value used to calculate a
  589        * fixed width and height for cells. This can be {@code null} if there
  590        * is no such value.
  591        *
  592        * @return the value of the {@code prototypeCellValue} property
  593        * @see #setPrototypeCellValue
  594        */
  595       public Object getPrototypeCellValue() {
  596           return prototypeCellValue;
  597       }
  598   
  599       /**
  600        * Sets the {@code prototypeCellValue} property, and then (if the new value
  601        * is {@code non-null}), computes the {@code fixedCellWidth} and
  602        * {@code fixedCellHeight} properties by requesting the cell renderer
  603        * component for the given value (and index 0) from the cell renderer, and
  604        * using that component's preferred size.
  605        * <p>
  606        * This method is useful when the list is too long to allow the
  607        * {@code ListUI} to compute the width/height of each cell, and there is a
  608        * single cell value that is known to occupy as much space as any of the
  609        * others, a so-called prototype.
  610        * <p>
  611        * While all three of the {@code prototypeCellValue},
  612        * {@code fixedCellHeight}, and {@code fixedCellWidth} properties may be
  613        * modified by this method, {@code PropertyChangeEvent} notifications are
  614        * only sent when the {@code prototypeCellValue} property changes.
  615        * <p>
  616        * To see an example which sets this property, see the
  617        * <a href="#prototype_example">class description</a> above.
  618        * <p>
  619        * The default value of this property is <code>null</code>.
  620        * <p>
  621        * This is a JavaBeans bound property.
  622        *
  623        * @param prototypeCellValue  the value on which to base
  624        *                          <code>fixedCellWidth</code> and
  625        *                          <code>fixedCellHeight</code>
  626        * @see #getPrototypeCellValue
  627        * @see #setFixedCellWidth
  628        * @see #setFixedCellHeight
  629        * @see JComponent#addPropertyChangeListener
  630        * @beaninfo
  631        *       bound: true
  632        *   attribute: visualUpdate true
  633        * description: The cell prototype value, used to compute cell width and height.
  634        */
  635       public void setPrototypeCellValue(Object prototypeCellValue) {
  636           Object oldValue = this.prototypeCellValue;
  637           this.prototypeCellValue = prototypeCellValue;
  638   
  639           /* If the prototypeCellValue has changed and is non-null,
  640            * then recompute fixedCellWidth and fixedCellHeight.
  641            */
  642   
  643           if ((prototypeCellValue != null) && !prototypeCellValue.equals(oldValue)) {
  644               updateFixedCellSize();
  645           }
  646   
  647           firePropertyChange("prototypeCellValue", oldValue, prototypeCellValue);
  648       }
  649   
  650   
  651       /**
  652        * Returns the value of the {@code fixedCellWidth} property.
  653        *
  654        * @return the fixed cell width
  655        * @see #setFixedCellWidth
  656        */
  657       public int getFixedCellWidth() {
  658           return fixedCellWidth;
  659       }
  660   
  661       /**
  662        * Sets a fixed value to be used for the width of every cell in the list.
  663        * If {@code width} is -1, cell widths are computed in the {@code ListUI}
  664        * by applying <code>getPreferredSize</code> to the cell renderer component
  665        * for each list element.
  666        * <p>
  667        * The default value of this property is {@code -1}.
  668        * <p>
  669        * This is a JavaBeans bound property.
  670        *
  671        * @param width the width to be used for all cells in the list
  672        * @see #setPrototypeCellValue
  673        * @see #setFixedCellWidth
  674        * @see JComponent#addPropertyChangeListener
  675        * @beaninfo
  676        *       bound: true
  677        *   attribute: visualUpdate true
  678        * description: Defines a fixed cell width when greater than zero.
  679        */
  680       public void setFixedCellWidth(int width) {
  681           int oldValue = fixedCellWidth;
  682           fixedCellWidth = width;
  683           firePropertyChange("fixedCellWidth", oldValue, fixedCellWidth);
  684       }
  685   
  686   
  687       /**
  688        * Returns the value of the {@code fixedCellHeight} property.
  689        *
  690        * @return the fixed cell height
  691        * @see #setFixedCellHeight
  692        */
  693       public int getFixedCellHeight() {
  694           return fixedCellHeight;
  695       }
  696   
  697       /**
  698        * Sets a fixed value to be used for the height of every cell in the list.
  699        * If {@code height} is -1, cell heights are computed in the {@code ListUI}
  700        * by applying <code>getPreferredSize</code> to the cell renderer component
  701        * for each list element.
  702        * <p>
  703        * The default value of this property is {@code -1}.
  704        * <p>
  705        * This is a JavaBeans bound property.
  706        *
  707        * @param height the height to be used for for all cells in the list
  708        * @see #setPrototypeCellValue
  709        * @see #setFixedCellWidth
  710        * @see JComponent#addPropertyChangeListener
  711        * @beaninfo
  712        *       bound: true
  713        *   attribute: visualUpdate true
  714        * description: Defines a fixed cell height when greater than zero.
  715        */
  716       public void setFixedCellHeight(int height) {
  717           int oldValue = fixedCellHeight;
  718           fixedCellHeight = height;
  719           firePropertyChange("fixedCellHeight", oldValue, fixedCellHeight);
  720       }
  721   
  722   
  723       /**
  724        * Returns the object responsible for painting list items.
  725        *
  726        * @return the value of the {@code cellRenderer} property
  727        * @see #setCellRenderer
  728        */
  729       @Transient
  730       public ListCellRenderer getCellRenderer() {
  731           return cellRenderer;
  732       }
  733   
  734       /**
  735        * Sets the delegate that is used to paint each cell in the list.
  736        * The job of a cell renderer is discussed in detail in the
  737        * <a href="#renderer">class level documentation</a>.
  738        * <p>
  739        * If the {@code prototypeCellValue} property is {@code non-null},
  740        * setting the cell renderer also causes the {@code fixedCellWidth} and
  741        * {@code fixedCellHeight} properties to be re-calculated. Only one
  742        * <code>PropertyChangeEvent</code> is generated however -
  743        * for the <code>cellRenderer</code> property.
  744        * <p>
  745        * The default value of this property is provided by the {@code ListUI}
  746        * delegate, i.e. by the look and feel implementation.
  747        * <p>
  748        * This is a JavaBeans bound property.
  749        *
  750        * @param cellRenderer the <code>ListCellRenderer</code>
  751        *                          that paints list cells
  752        * @see #getCellRenderer
  753        * @beaninfo
  754        *       bound: true
  755        *   attribute: visualUpdate true
  756        * description: The component used to draw the cells.
  757        */
  758       public void setCellRenderer(ListCellRenderer cellRenderer) {
  759           ListCellRenderer oldValue = this.cellRenderer;
  760           this.cellRenderer = cellRenderer;
  761   
  762           /* If the cellRenderer has changed and prototypeCellValue
  763            * was set, then recompute fixedCellWidth and fixedCellHeight.
  764            */
  765           if ((cellRenderer != null) && !cellRenderer.equals(oldValue)) {
  766               updateFixedCellSize();
  767           }
  768   
  769           firePropertyChange("cellRenderer", oldValue, cellRenderer);
  770       }
  771   
  772   
  773       /**
  774        * Returns the color used to draw the foreground of selected items.
  775        * {@code DefaultListCellRenderer} uses this color to draw the foreground
  776        * of items in the selected state, as do the renderers installed by most
  777        * {@code ListUI} implementations.
  778        *
  779        * @return the color to draw the foreground of selected items
  780        * @see #setSelectionForeground
  781        * @see DefaultListCellRenderer
  782        */
  783       public Color getSelectionForeground() {
  784           return selectionForeground;
  785       }
  786   
  787   
  788       /**
  789        * Sets the color used to draw the foreground of selected items, which
  790        * cell renderers can use to render text and graphics.
  791        * {@code DefaultListCellRenderer} uses this color to draw the foreground
  792        * of items in the selected state, as do the renderers installed by most
  793        * {@code ListUI} implementations.
  794        * <p>
  795        * The default value of this property is defined by the look and feel
  796        * implementation.
  797        * <p>
  798        * This is a JavaBeans bound property.
  799        *
  800        * @param selectionForeground  the {@code Color} to use in the foreground
  801        *                             for selected list items
  802        * @see #getSelectionForeground
  803        * @see #setSelectionBackground
  804        * @see #setForeground
  805        * @see #setBackground
  806        * @see #setFont
  807        * @see DefaultListCellRenderer
  808        * @beaninfo
  809        *       bound: true
  810        *   attribute: visualUpdate true
  811        * description: The foreground color of selected cells.
  812        */
  813       public void setSelectionForeground(Color selectionForeground) {
  814           Color oldValue = this.selectionForeground;
  815           this.selectionForeground = selectionForeground;
  816           firePropertyChange("selectionForeground", oldValue, selectionForeground);
  817       }
  818   
  819   
  820       /**
  821        * Returns the color used to draw the background of selected items.
  822        * {@code DefaultListCellRenderer} uses this color to draw the background
  823        * of items in the selected state, as do the renderers installed by most
  824        * {@code ListUI} implementations.
  825        *
  826        * @return the color to draw the background of selected items
  827        * @see #setSelectionBackground
  828        * @see DefaultListCellRenderer
  829        */
  830       public Color getSelectionBackground() {
  831           return selectionBackground;
  832       }
  833   
  834   
  835       /**
  836        * Sets the color used to draw the background of selected items, which
  837        * cell renderers can use fill selected cells.
  838        * {@code DefaultListCellRenderer} uses this color to fill the background
  839        * of items in the selected state, as do the renderers installed by most
  840        * {@code ListUI} implementations.
  841        * <p>
  842        * The default value of this property is defined by the look
  843        * and feel implementation.
  844        * <p>
  845        * This is a JavaBeans bound property.
  846        *
  847        * @param selectionBackground  the {@code Color} to use for the
  848        *                             background of selected cells
  849        * @see #getSelectionBackground
  850        * @see #setSelectionForeground
  851        * @see #setForeground
  852        * @see #setBackground
  853        * @see #setFont
  854        * @see DefaultListCellRenderer
  855        * @beaninfo
  856        *       bound: true
  857        *   attribute: visualUpdate true
  858        * description: The background color of selected cells.
  859        */
  860       public void setSelectionBackground(Color selectionBackground) {
  861           Color oldValue = this.selectionBackground;
  862           this.selectionBackground = selectionBackground;
  863           firePropertyChange("selectionBackground", oldValue, selectionBackground);
  864       }
  865   
  866   
  867       /**
  868        * Returns the value of the {@code visibleRowCount} property. See the
  869        * documentation for {@link #setVisibleRowCount} for details on how to
  870        * interpret this value.
  871        *
  872        * @return the value of the {@code visibleRowCount} property.
  873        * @see #setVisibleRowCount
  874        */
  875       public int getVisibleRowCount() {
  876           return visibleRowCount;
  877       }
  878   
  879       /**
  880        * Sets the {@code visibleRowCount} property, which has different meanings
  881        * depending on the layout orientation: For a {@code VERTICAL} layout
  882        * orientation, this sets the preferred number of rows to display without
  883        * requiring scrolling; for other orientations, it affects the wrapping of
  884        * cells.
  885        * <p>
  886        * In {@code VERTICAL} orientation:<br>
  887        * Setting this property affects the return value of the
  888        * {@link #getPreferredScrollableViewportSize} method, which is used to
  889        * calculate the preferred size of an enclosing viewport. See that method's
  890        * documentation for more details.
  891        * <p>
  892        * In {@code HORIZONTAL_WRAP} and {@code VERTICAL_WRAP} orientations:<br>
  893        * This affects how cells are wrapped. See the documentation of
  894        * {@link #setLayoutOrientation} for more details.
  895        * <p>
  896        * The default value of this property is {@code 8}.
  897        * <p>
  898        * Calling this method with a negative value results in the property
  899        * being set to {@code 0}.
  900        * <p>
  901        * This is a JavaBeans bound property.
  902        *
  903        * @param visibleRowCount  an integer specifying the preferred number of
  904        *                         rows to display without requiring scrolling
  905        * @see #getVisibleRowCount
  906        * @see #getPreferredScrollableViewportSize
  907        * @see #setLayoutOrientation
  908        * @see JComponent#getVisibleRect
  909        * @see JViewport
  910        * @beaninfo
  911        *       bound: true
  912        *   attribute: visualUpdate true
  913        * description: The preferred number of rows to display without
  914        *              requiring scrolling
  915        */
  916       public void setVisibleRowCount(int visibleRowCount) {
  917           int oldValue = this.visibleRowCount;
  918           this.visibleRowCount = Math.max(0, visibleRowCount);
  919           firePropertyChange("visibleRowCount", oldValue, visibleRowCount);
  920       }
  921   
  922   
  923       /**
  924        * Returns the layout orientation property for the list: {@code VERTICAL}
  925        * if the layout is a single column of cells, {@code VERTICAL_WRAP} if the
  926        * layout is "newspaper style" with the content flowing vertically then
  927        * horizontally, or {@code HORIZONTAL_WRAP} if the layout is "newspaper
  928        * style" with the content flowing horizontally then vertically.
  929        *
  930        * @return the value of the {@code layoutOrientation} property
  931        * @see #setLayoutOrientation
  932        * @since 1.4
  933        */
  934       public int getLayoutOrientation() {
  935           return layoutOrientation;
  936       }
  937   
  938   
  939       /**
  940        * Defines the way list cells are layed out. Consider a {@code JList}
  941        * with five cells. Cells can be layed out in one of the following ways:
  942        * <p>
  943        * <pre>
  944        * VERTICAL:          0
  945        *                    1
  946        *                    2
  947        *                    3
  948        *                    4
  949        *
  950        * HORIZONTAL_WRAP:   0  1  2
  951        *                    3  4
  952        *
  953        * VERTICAL_WRAP:     0  3
  954        *                    1  4
  955        *                    2
  956        * </pre>
  957        * <p>
  958        * A description of these layouts follows:
  959        *
  960        * <table border="1"
  961        *  summary="Describes layouts VERTICAL, HORIZONTAL_WRAP, and VERTICAL_WRAP">
  962        *   <tr><th><p align="left">Value</p></th><th><p align="left">Description</p></th></tr>
  963        *   <tr><td><code>VERTICAL</code>
  964        *       <td>Cells are layed out vertically in a single column.
  965        *   <tr><td><code>HORIZONTAL_WRAP</code>
  966        *       <td>Cells are layed out horizontally, wrapping to a new row as
  967        *           necessary. If the {@code visibleRowCount} property is less than
  968        *           or equal to zero, wrapping is determined by the width of the
  969        *           list; otherwise wrapping is done in such a way as to ensure
  970        *           {@code visibleRowCount} rows in the list.
  971        *   <tr><td><code>VERTICAL_WRAP</code>
  972        *       <td>Cells are layed out vertically, wrapping to a new column as
  973        *           necessary. If the {@code visibleRowCount} property is less than
  974        *           or equal to zero, wrapping is determined by the height of the
  975        *           list; otherwise wrapping is done at {@code visibleRowCount} rows.
  976        *  </table>
  977        * <p>
  978        * The default value of this property is <code>VERTICAL</code>.
  979        *
  980        * @param layoutOrientation the new layout orientation, one of:
  981        *        {@code VERTICAL}, {@code HORIZONTAL_WRAP} or {@code VERTICAL_WRAP}
  982        * @see #getLayoutOrientation
  983        * @see #setVisibleRowCount
  984        * @see #getScrollableTracksViewportHeight
  985        * @see #getScrollableTracksViewportWidth
  986        * @throws IllegalArgumentException if {@code layoutOrientation} isn't one of the
  987        *         allowable values
  988        * @since 1.4
  989        * @beaninfo
  990        *       bound: true
  991        *   attribute: visualUpdate true
  992        * description: Defines the way list cells are layed out.
  993        *        enum: VERTICAL JList.VERTICAL
  994        *              HORIZONTAL_WRAP JList.HORIZONTAL_WRAP
  995        *              VERTICAL_WRAP JList.VERTICAL_WRAP
  996        */
  997       public void setLayoutOrientation(int layoutOrientation) {
  998           int oldValue = this.layoutOrientation;
  999           switch (layoutOrientation) {
 1000           case VERTICAL:
 1001           case VERTICAL_WRAP:
 1002           case HORIZONTAL_WRAP:
 1003               this.layoutOrientation = layoutOrientation;
 1004               firePropertyChange("layoutOrientation", oldValue, layoutOrientation);
 1005               break;
 1006           default:
 1007               throw new IllegalArgumentException("layoutOrientation must be one of: VERTICAL, HORIZONTAL_WRAP or VERTICAL_WRAP");
 1008           }
 1009       }
 1010   
 1011   
 1012       /**
 1013        * Returns the smallest list index that is currently visible.
 1014        * In a left-to-right {@code componentOrientation}, the first visible
 1015        * cell is found closest to the list's upper-left corner. In right-to-left
 1016        * orientation, it is found closest to the upper-right corner.
 1017        * If nothing is visible or the list is empty, {@code -1} is returned.
 1018        * Note that the returned cell may only be partially visible.
 1019        *
 1020        * @return the index of the first visible cell
 1021        * @see #getLastVisibleIndex
 1022        * @see JComponent#getVisibleRect
 1023        */
 1024       public int getFirstVisibleIndex() {
 1025           Rectangle r = getVisibleRect();
 1026           int first;
 1027           if (this.getComponentOrientation().isLeftToRight()) {
 1028               first = locationToIndex(r.getLocation());
 1029           } else {
 1030               first = locationToIndex(new Point((r.x + r.width) - 1, r.y));
 1031           }
 1032           if (first != -1) {
 1033               Rectangle bounds = getCellBounds(first, first);
 1034               if (bounds != null) {
 1035                   SwingUtilities.computeIntersection(r.x, r.y, r.width, r.height, bounds);
 1036                   if (bounds.width == 0 || bounds.height == 0) {
 1037                       first = -1;
 1038                   }
 1039               }
 1040           }
 1041           return first;
 1042       }
 1043   
 1044   
 1045       /**
 1046        * Returns the largest list index that is currently visible.
 1047        * If nothing is visible or the list is empty, {@code -1} is returned.
 1048        * Note that the returned cell may only be partially visible.
 1049        *
 1050        * @return the index of the last visible cell
 1051        * @see #getFirstVisibleIndex
 1052        * @see JComponent#getVisibleRect
 1053        */
 1054       public int getLastVisibleIndex() {
 1055           boolean leftToRight = this.getComponentOrientation().isLeftToRight();
 1056           Rectangle r = getVisibleRect();
 1057           Point lastPoint;
 1058           if (leftToRight) {
 1059               lastPoint = new Point((r.x + r.width) - 1, (r.y + r.height) - 1);
 1060           } else {
 1061               lastPoint = new Point(r.x, (r.y + r.height) - 1);
 1062           }
 1063           int location = locationToIndex(lastPoint);
 1064   
 1065           if (location != -1) {
 1066               Rectangle bounds = getCellBounds(location, location);
 1067   
 1068               if (bounds != null) {
 1069                   SwingUtilities.computeIntersection(r.x, r.y, r.width, r.height, bounds);
 1070                   if (bounds.width == 0 || bounds.height == 0) {
 1071                       // Try the top left(LTR) or top right(RTL) corner, and
 1072                       // then go across checking each cell for HORIZONTAL_WRAP.
 1073                       // Try the lower left corner, and then go across checking
 1074                       // each cell for other list layout orientation.
 1075                       boolean isHorizontalWrap =
 1076                           (getLayoutOrientation() == HORIZONTAL_WRAP);
 1077                       Point visibleLocation = isHorizontalWrap ?
 1078                           new Point(lastPoint.x, r.y) :
 1079                           new Point(r.x, lastPoint.y);
 1080                       int last;
 1081                       int visIndex = -1;
 1082                       int lIndex = location;
 1083                       location = -1;
 1084   
 1085                       do {
 1086                           last = visIndex;
 1087                           visIndex = locationToIndex(visibleLocation);
 1088   
 1089                           if (visIndex != -1) {
 1090                               bounds = getCellBounds(visIndex, visIndex);
 1091                               if (visIndex != lIndex && bounds != null &&
 1092                                   bounds.contains(visibleLocation)) {
 1093                                   location = visIndex;
 1094                                   if (isHorizontalWrap) {
 1095                                       visibleLocation.y = bounds.y + bounds.height;
 1096                                       if (visibleLocation.y >= lastPoint.y) {
 1097                                           // Past visible region, bail.
 1098                                           last = visIndex;
 1099                                       }
 1100                                   }
 1101                                   else {
 1102                                       visibleLocation.x = bounds.x + bounds.width;
 1103                                       if (visibleLocation.x >= lastPoint.x) {
 1104                                           // Past visible region, bail.
 1105                                           last = visIndex;
 1106                                       }
 1107                                   }
 1108   
 1109                               }
 1110                               else {
 1111                                   last = visIndex;
 1112                               }
 1113                           }
 1114                       } while (visIndex != -1 && last != visIndex);
 1115                   }
 1116               }
 1117           }
 1118           return location;
 1119       }
 1120   
 1121   
 1122       /**
 1123        * Scrolls the list within an enclosing viewport to make the specified
 1124        * cell completely visible. This calls {@code scrollRectToVisible} with
 1125        * the bounds of the specified cell. For this method to work, the
 1126        * {@code JList} must be within a <code>JViewport</code>.
 1127        * <p>
 1128        * If the given index is outside the list's range of cells, this method
 1129        * results in nothing.
 1130        *
 1131        * @param index  the index of the cell to make visible
 1132        * @see JComponent#scrollRectToVisible
 1133        * @see #getVisibleRect
 1134        */
 1135       public void ensureIndexIsVisible(int index) {
 1136           Rectangle cellBounds = getCellBounds(index, index);
 1137           if (cellBounds != null) {
 1138               scrollRectToVisible(cellBounds);
 1139           }
 1140       }
 1141   
 1142       /**
 1143        * Turns on or off automatic drag handling. In order to enable automatic
 1144        * drag handling, this property should be set to {@code true}, and the
 1145        * list's {@code TransferHandler} needs to be {@code non-null}.
 1146        * The default value of the {@code dragEnabled} property is {@code false}.
 1147        * <p>
 1148        * The job of honoring this property, and recognizing a user drag gesture,
 1149        * lies with the look and feel implementation, and in particular, the list's
 1150        * {@code ListUI}. When automatic drag handling is enabled, most look and
 1151        * feels (including those that subclass {@code BasicLookAndFeel}) begin a
 1152        * drag and drop operation whenever the user presses the mouse button over
 1153        * an item and then moves the mouse a few pixels. Setting this property to
 1154        * {@code true} can therefore have a subtle effect on how selections behave.
 1155        * <p>
 1156        * If a look and feel is used that ignores this property, you can still
 1157        * begin a drag and drop operation by calling {@code exportAsDrag} on the
 1158        * list's {@code TransferHandler}.
 1159        *
 1160        * @param b whether or not to enable automatic drag handling
 1161        * @exception HeadlessException if
 1162        *            <code>b</code> is <code>true</code> and
 1163        *            <code>GraphicsEnvironment.isHeadless()</code>
 1164        *            returns <code>true</code>
 1165        * @see java.awt.GraphicsEnvironment#isHeadless
 1166        * @see #getDragEnabled
 1167        * @see #setTransferHandler
 1168        * @see TransferHandler
 1169        * @since 1.4
 1170        *
 1171        * @beaninfo
 1172        *  description: determines whether automatic drag handling is enabled
 1173        *        bound: false
 1174        */
 1175       public void setDragEnabled(boolean b) {
 1176           if (b && GraphicsEnvironment.isHeadless()) {
 1177               throw new HeadlessException();
 1178           }
 1179           dragEnabled = b;
 1180       }
 1181   
 1182       /**
 1183        * Returns whether or not automatic drag handling is enabled.
 1184        *
 1185        * @return the value of the {@code dragEnabled} property
 1186        * @see #setDragEnabled
 1187        * @since 1.4
 1188        */
 1189       public boolean getDragEnabled() {
 1190           return dragEnabled;
 1191       }
 1192   
 1193       /**
 1194        * Sets the drop mode for this component. For backward compatibility,
 1195        * the default for this property is <code>DropMode.USE_SELECTION</code>.
 1196        * Usage of one of the other modes is recommended, however, for an
 1197        * improved user experience. <code>DropMode.ON</code>, for instance,
 1198        * offers similar behavior of showing items as selected, but does so without
 1199        * affecting the actual selection in the list.
 1200        * <p>
 1201        * <code>JList</code> supports the following drop modes:
 1202        * <ul>
 1203        *    <li><code>DropMode.USE_SELECTION</code></li>
 1204        *    <li><code>DropMode.ON</code></li>
 1205        *    <li><code>DropMode.INSERT</code></li>
 1206        *    <li><code>DropMode.ON_OR_INSERT</code></li>
 1207        * </ul>
 1208        * The drop mode is only meaningful if this component has a
 1209        * <code>TransferHandler</code> that accepts drops.
 1210        *
 1211        * @param dropMode the drop mode to use
 1212        * @throws IllegalArgumentException if the drop mode is unsupported
 1213        *         or <code>null</code>
 1214        * @see #getDropMode
 1215        * @see #getDropLocation
 1216        * @see #setTransferHandler
 1217        * @see TransferHandler
 1218        * @since 1.6
 1219        */
 1220       public final void setDropMode(DropMode dropMode) {
 1221           if (dropMode != null) {
 1222               switch (dropMode) {
 1223                   case USE_SELECTION:
 1224                   case ON:
 1225                   case INSERT:
 1226                   case ON_OR_INSERT:
 1227                       this.dropMode = dropMode;
 1228                       return;
 1229               }
 1230           }
 1231   
 1232           throw new IllegalArgumentException(dropMode + ": Unsupported drop mode for list");
 1233       }
 1234   
 1235       /**
 1236        * Returns the drop mode for this component.
 1237        *
 1238        * @return the drop mode for this component
 1239        * @see #setDropMode
 1240        * @since 1.6
 1241        */
 1242       public final DropMode getDropMode() {
 1243           return dropMode;
 1244       }
 1245   
 1246       /**
 1247        * Calculates a drop location in this component, representing where a
 1248        * drop at the given point should insert data.
 1249        *
 1250        * @param p the point to calculate a drop location for
 1251        * @return the drop location, or <code>null</code>
 1252        */
 1253       DropLocation dropLocationForPoint(Point p) {
 1254           DropLocation location = null;
 1255           Rectangle rect = null;
 1256   
 1257           int index = locationToIndex(p);
 1258           if (index != -1) {
 1259               rect = getCellBounds(index, index);
 1260           }
 1261   
 1262           switch(dropMode) {
 1263               case USE_SELECTION:
 1264               case ON:
 1265                   location = new DropLocation(p,
 1266                       (rect != null && rect.contains(p)) ? index : -1,
 1267                       false);
 1268   
 1269                   break;
 1270               case INSERT:
 1271                   if (index == -1) {
 1272                       location = new DropLocation(p, getModel().getSize(), true);
 1273                       break;
 1274                   }
 1275   
 1276                   if (layoutOrientation == HORIZONTAL_WRAP) {
 1277                       boolean ltr = getComponentOrientation().isLeftToRight();
 1278   
 1279                       if (SwingUtilities2.liesInHorizontal(rect, p, ltr, false) == TRAILING) {
 1280                           index++;
 1281                       // special case for below all cells
 1282                       } else if (index == getModel().getSize() - 1 && p.y >= rect.y + rect.height) {
 1283                           index++;
 1284                       }
 1285                   } else {
 1286                       if (SwingUtilities2.liesInVertical(rect, p, false) == TRAILING) {
 1287                           index++;
 1288                       }
 1289                   }
 1290   
 1291                   location = new DropLocation(p, index, true);
 1292   
 1293                   break;
 1294               case ON_OR_INSERT:
 1295                   if (index == -1) {
 1296                       location = new DropLocation(p, getModel().getSize(), true);
 1297                       break;
 1298                   }
 1299   
 1300                   boolean between = false;
 1301   
 1302                   if (layoutOrientation == HORIZONTAL_WRAP) {
 1303                       boolean ltr = getComponentOrientation().isLeftToRight();
 1304   
 1305                       Section section = SwingUtilities2.liesInHorizontal(rect, p, ltr, true);
 1306                       if (section == TRAILING) {
 1307                           index++;
 1308                           between = true;
 1309                       // special case for below all cells
 1310                       } else if (index == getModel().getSize() - 1 && p.y >= rect.y + rect.height) {
 1311                           index++;
 1312                           between = true;
 1313                       } else if (section == LEADING) {
 1314                           between = true;
 1315                       }
 1316                   } else {
 1317                       Section section = SwingUtilities2.liesInVertical(rect, p, true);
 1318                       if (section == LEADING) {
 1319                           between = true;
 1320                       } else if (section == TRAILING) {
 1321                           index++;
 1322                           between = true;
 1323                       }
 1324                   }
 1325   
 1326                   location = new DropLocation(p, index, between);
 1327   
 1328                   break;
 1329               default:
 1330                   assert false : "Unexpected drop mode";
 1331           }
 1332   
 1333           return location;
 1334       }
 1335   
 1336       /**
 1337        * Called to set or clear the drop location during a DnD operation.
 1338        * In some cases, the component may need to use it's internal selection
 1339        * temporarily to indicate the drop location. To help facilitate this,
 1340        * this method returns and accepts as a parameter a state object.
 1341        * This state object can be used to store, and later restore, the selection
 1342        * state. Whatever this method returns will be passed back to it in
 1343        * future calls, as the state parameter. If it wants the DnD system to
 1344        * continue storing the same state, it must pass it back every time.
 1345        * Here's how this is used:
 1346        * <p>
 1347        * Let's say that on the first call to this method the component decides
 1348        * to save some state (because it is about to use the selection to show
 1349        * a drop index). It can return a state object to the caller encapsulating
 1350        * any saved selection state. On a second call, let's say the drop location
 1351        * is being changed to something else. The component doesn't need to
 1352        * restore anything yet, so it simply passes back the same state object
 1353        * to have the DnD system continue storing it. Finally, let's say this
 1354        * method is messaged with <code>null</code>. This means DnD
 1355        * is finished with this component for now, meaning it should restore
 1356        * state. At this point, it can use the state parameter to restore
 1357        * said state, and of course return <code>null</code> since there's
 1358        * no longer anything to store.
 1359        *
 1360        * @param location the drop location (as calculated by
 1361        *        <code>dropLocationForPoint</code>) or <code>null</code>
 1362        *        if there's no longer a valid drop location
 1363        * @param state the state object saved earlier for this component,
 1364        *        or <code>null</code>
 1365        * @param forDrop whether or not the method is being called because an
 1366        *        actual drop occurred
 1367        * @return any saved state for this component, or <code>null</code> if none
 1368        */
 1369       Object setDropLocation(TransferHandler.DropLocation location,
 1370                              Object state,
 1371                              boolean forDrop) {
 1372   
 1373           Object retVal = null;
 1374           DropLocation listLocation = (DropLocation)location;
 1375   
 1376           if (dropMode == DropMode.USE_SELECTION) {
 1377               if (listLocation == null) {
 1378                   if (!forDrop && state != null) {
 1379                       setSelectedIndices(((int[][])state)[0]);
 1380   
 1381                       int anchor = ((int[][])state)[1][0];
 1382                       int lead = ((int[][])state)[1][1];
 1383   
 1384                       SwingUtilities2.setLeadAnchorWithoutSelection(
 1385                               getSelectionModel(), lead, anchor);
 1386                   }
 1387               } else {
 1388                   if (dropLocation == null) {
 1389                       int[] inds = getSelectedIndices();
 1390                       retVal = new int[][] {inds, {getAnchorSelectionIndex(),
 1391                                                    getLeadSelectionIndex()}};
 1392                   } else {
 1393                       retVal = state;
 1394                   }
 1395   
 1396                   int index = listLocation.getIndex();
 1397                   if (index == -1) {
 1398                       clearSelection();
 1399                       getSelectionModel().setAnchorSelectionIndex(-1);
 1400                       getSelectionModel().setLeadSelectionIndex(-1);
 1401                   } else {
 1402                       setSelectionInterval(index, index);
 1403                   }
 1404               }
 1405           }
 1406   
 1407           DropLocation old = dropLocation;
 1408           dropLocation = listLocation;
 1409           firePropertyChange("dropLocation", old, dropLocation);
 1410   
 1411           return retVal;
 1412       }
 1413   
 1414       /**
 1415        * Returns the location that this component should visually indicate
 1416        * as the drop location during a DnD operation over the component,
 1417        * or {@code null} if no location is to currently be shown.
 1418        * <p>
 1419        * This method is not meant for querying the drop location
 1420        * from a {@code TransferHandler}, as the drop location is only
 1421        * set after the {@code TransferHandler}'s <code>canImport</code>
 1422        * has returned and has allowed for the location to be shown.
 1423        * <p>
 1424        * When this property changes, a property change event with
 1425        * name "dropLocation" is fired by the component.
 1426        * <p>
 1427        * By default, responsibility for listening for changes to this property
 1428        * and indicating the drop location visually lies with the list's
 1429        * {@code ListUI}, which may paint it directly and/or install a cell
 1430        * renderer to do so. Developers wishing to implement custom drop location
 1431        * painting and/or replace the default cell renderer, may need to honor
 1432        * this property.
 1433        *
 1434        * @return the drop location
 1435        * @see #setDropMode
 1436        * @see TransferHandler#canImport(TransferHandler.TransferSupport)
 1437        * @since 1.6
 1438        */
 1439       public final DropLocation getDropLocation() {
 1440           return dropLocation;
 1441       }
 1442   
 1443       /**
 1444        * Returns the next list element whose {@code toString} value
 1445        * starts with the given prefix.
 1446        *
 1447        * @param prefix the string to test for a match
 1448        * @param startIndex the index for starting the search
 1449        * @param bias the search direction, either
 1450        * Position.Bias.Forward or Position.Bias.Backward.
 1451        * @return the index of the next list element that
 1452        * starts with the prefix; otherwise {@code -1}
 1453        * @exception IllegalArgumentException if prefix is {@code null}
 1454        * or startIndex is out of bounds
 1455        * @since 1.4
 1456        */
 1457       public int getNextMatch(String prefix, int startIndex, Position.Bias bias) {
 1458           ListModel model = getModel();
 1459           int max = model.getSize();
 1460           if (prefix == null) {
 1461               throw new IllegalArgumentException();
 1462           }
 1463           if (startIndex < 0 || startIndex >= max) {
 1464               throw new IllegalArgumentException();
 1465           }
 1466           prefix = prefix.toUpperCase();
 1467   
 1468           // start search from the next element after the selected element
 1469           int increment = (bias == Position.Bias.Forward) ? 1 : -1;
 1470           int index = startIndex;
 1471           do {
 1472               Object o = model.getElementAt(index);
 1473   
 1474               if (o != null) {
 1475                   String string;
 1476   
 1477                   if (o instanceof String) {
 1478                       string = ((String)o).toUpperCase();
 1479                   }
 1480                   else {
 1481                       string = o.toString();
 1482                       if (string != null) {
 1483                           string = string.toUpperCase();
 1484                       }
 1485                   }
 1486   
 1487                   if (string != null && string.startsWith(prefix)) {
 1488                       return index;
 1489                   }
 1490               }
 1491               index = (index + increment + max) % max;
 1492           } while (index != startIndex);
 1493           return -1;
 1494       }
 1495   
 1496       /**
 1497        * Returns the tooltip text to be used for the given event. This overrides
 1498        * {@code JComponent}'s {@code getToolTipText} to first check the cell
 1499        * renderer component for the cell over which the event occurred, returning
 1500        * its tooltip text, if any. This implementation allows you to specify
 1501        * tooltip text on the cell level, by using {@code setToolTipText} on your
 1502        * cell renderer component.
 1503        * <p>
 1504        * <bold>Note:</bold> For <code>JList</code> to properly display the
 1505        * tooltips of its renderers in this manner, <code>JList</code> must be a
 1506        * registered component with the <code>ToolTipManager</code>. This registration
 1507        * is done automatically in the constructor. However, if at a later point
 1508        * <code>JList</code> is unregistered, by way of a call to
 1509        * {@code setToolTipText(null)}, tips from the renderers will no longer display.
 1510        *
 1511        * @param event the {@code MouseEvent} to fetch the tooltip text for
 1512        * @see JComponent#setToolTipText
 1513        * @see JComponent#getToolTipText
 1514        */
 1515       public String getToolTipText(MouseEvent event) {
 1516           if(event != null) {
 1517               Point p = event.getPoint();
 1518               int index = locationToIndex(p);
 1519               ListCellRenderer r = getCellRenderer();
 1520               Rectangle cellBounds;
 1521   
 1522               if (index != -1 && r != null && (cellBounds =
 1523                                  getCellBounds(index, index)) != null &&
 1524                                  cellBounds.contains(p.x, p.y)) {
 1525                   ListSelectionModel lsm = getSelectionModel();
 1526                   Component rComponent = r.getListCellRendererComponent(
 1527                              this, getModel().getElementAt(index), index,
 1528                              lsm.isSelectedIndex(index),
 1529                              (hasFocus() && (lsm.getLeadSelectionIndex() ==
 1530                                              index)));
 1531   
 1532                   if(rComponent instanceof JComponent) {
 1533                       MouseEvent      newEvent;
 1534   
 1535                       p.translate(-cellBounds.x, -cellBounds.y);
 1536                       newEvent = new MouseEvent(rComponent, event.getID(),
 1537                                                 event.getWhen(),
 1538                                                 event.getModifiers(),
 1539                                                 p.x, p.y,
 1540                                                 event.getXOnScreen(),
 1541                                                 event.getYOnScreen(),
 1542                                                 event.getClickCount(),
 1543                                                 event.isPopupTrigger(),
 1544                                                 MouseEvent.NOBUTTON);
 1545   
 1546                       String tip = ((JComponent)rComponent).getToolTipText(
 1547                                                 newEvent);
 1548   
 1549                       if (tip != null) {
 1550                           return tip;
 1551                       }
 1552                   }
 1553               }
 1554           }
 1555           return super.getToolTipText();
 1556       }
 1557   
 1558       /**
 1559        * --- ListUI Delegations ---
 1560        */
 1561   
 1562   
 1563       /**
 1564        * Returns the cell index closest to the given location in the list's
 1565        * coordinate system. To determine if the cell actually contains the
 1566        * specified location, compare the point against the cell's bounds,
 1567        * as provided by {@code getCellBounds}. This method returns {@code -1}
 1568        * if the model is empty
 1569        * <p>
 1570        * This is a cover method that delegates to the method of the same name
 1571        * in the list's {@code ListUI}. It returns {@code -1} if the list has
 1572        * no {@code ListUI}.
 1573        *
 1574        * @param location the coordinates of the point
 1575        * @return the cell index closest to the given location, or {@code -1}
 1576        */
 1577       public int locationToIndex(Point location) {
 1578           ListUI ui = getUI();
 1579           return (ui != null) ? ui.locationToIndex(this, location) : -1;
 1580       }
 1581   
 1582   
 1583       /**
 1584        * Returns the origin of the specified item in the list's coordinate
 1585        * system. This method returns {@code null} if the index isn't valid.
 1586        * <p>
 1587        * This is a cover method that delegates to the method of the same name
 1588        * in the list's {@code ListUI}. It returns {@code null} if the list has
 1589        * no {@code ListUI}.
 1590        *
 1591        * @param index the cell index
 1592        * @return the origin of the cell, or {@code null}
 1593        */
 1594       public Point indexToLocation(int index) {
 1595           ListUI ui = getUI();
 1596           return (ui != null) ? ui.indexToLocation(this, index) : null;
 1597       }
 1598   
 1599   
 1600       /**
 1601        * Returns the bounding rectangle, in the list's coordinate system,
 1602        * for the range of cells specified by the two indices.
 1603        * These indices can be supplied in any order.
 1604        * <p>
 1605        * If the smaller index is outside the list's range of cells, this method
 1606        * returns {@code null}. If the smaller index is valid, but the larger
 1607        * index is outside the list's range, the bounds of just the first index
 1608        * is returned. Otherwise, the bounds of the valid range is returned.
 1609        * <p>
 1610        * This is a cover method that delegates to the method of the same name
 1611        * in the list's {@code ListUI}. It returns {@code null} if the list has
 1612        * no {@code ListUI}.
 1613        *
 1614        * @param index0 the first index in the range
 1615        * @param index1 the second index in the range
 1616        * @return the bounding rectangle for the range of cells, or {@code null}
 1617        */
 1618       public Rectangle getCellBounds(int index0, int index1) {
 1619           ListUI ui = getUI();
 1620           return (ui != null) ? ui.getCellBounds(this, index0, index1) : null;
 1621       }
 1622   
 1623   
 1624       /**
 1625        * --- ListModel Support ---
 1626        */
 1627   
 1628   
 1629       /**
 1630        * Returns the data model that holds the list of items displayed
 1631        * by the <code>JList</code> component.
 1632        *
 1633        * @return the <code>ListModel</code> that provides the displayed
 1634        *                          list of items
 1635        * @see #setModel
 1636        */
 1637       public ListModel getModel() {
 1638           return dataModel;
 1639       }
 1640   
 1641       /**
 1642        * Sets the model that represents the contents or "value" of the
 1643        * list, notifies property change listeners, and then clears the
 1644        * list's selection.
 1645        * <p>
 1646        * This is a JavaBeans bound property.
 1647        *
 1648        * @param model  the <code>ListModel</code> that provides the
 1649        *                                          list of items for display
 1650        * @exception IllegalArgumentException  if <code>model</code> is
 1651        *                                          <code>null</code>
 1652        * @see #getModel
 1653        * @see #clearSelection
 1654        * @beaninfo
 1655        *       bound: true
 1656        *   attribute: visualUpdate true
 1657        * description: The object that contains the data to be drawn by this JList.
 1658        */
 1659       public void setModel(ListModel model) {
 1660           if (model == null) {
 1661               throw new IllegalArgumentException("model must be non null");
 1662           }
 1663           ListModel oldValue = dataModel;
 1664           dataModel = model;
 1665           firePropertyChange("model", oldValue, dataModel);
 1666           clearSelection();
 1667       }
 1668   
 1669   
 1670       /**
 1671        * Constructs a read-only <code>ListModel</code> from an array of objects,
 1672        * and calls {@code setModel} with this model.
 1673        * <p>
 1674        * Attempts to pass a {@code null} value to this method results in
 1675        * undefined behavior and, most likely, exceptions. The created model
 1676        * references the given array directly. Attempts to modify the array
 1677        * after invoking this method results in undefined behavior.
 1678        *
 1679        * @param listData an array of {@code Objects} containing the items to
 1680        *        display in the list
 1681        * @see #setModel
 1682        */
 1683       public void setListData(final Object[] listData) {
 1684           setModel (
 1685               new AbstractListModel() {
 1686                   public int getSize() { return listData.length; }
 1687                   public Object getElementAt(int i) { return listData[i]; }
 1688               }
 1689           );
 1690       }
 1691   
 1692   
 1693       /**
 1694        * Constructs a read-only <code>ListModel</code> from a <code>Vector</code>
 1695        * and calls {@code setModel} with this model.
 1696        * <p>
 1697        * Attempts to pass a {@code null} value to this method results in
 1698        * undefined behavior and, most likely, exceptions. The created model
 1699        * references the given {@code Vector} directly. Attempts to modify the
 1700        * {@code Vector} after invoking this method results in undefined behavior.
 1701        *
 1702        * @param listData a <code>Vector</code> containing the items to
 1703        *                                          display in the list
 1704        * @see #setModel
 1705        */
 1706       public void setListData(final Vector<?> listData) {
 1707           setModel (
 1708               new AbstractListModel() {
 1709                   public int getSize() { return listData.size(); }
 1710                   public Object getElementAt(int i) { return listData.elementAt(i); }
 1711               }
 1712           );
 1713       }
 1714   
 1715   
 1716       /**
 1717        * --- ListSelectionModel delegations and extensions ---
 1718        */
 1719   
 1720   
 1721       /**
 1722        * Returns an instance of {@code DefaultListSelectionModel}; called
 1723        * during construction to initialize the list's selection model
 1724        * property.
 1725        *
 1726        * @return a {@code DefaultListSelecitonModel}, used to initialize
 1727        *         the list's selection model property during construction
 1728        * @see #setSelectionModel
 1729        * @see DefaultListSelectionModel
 1730        */
 1731       protected ListSelectionModel createSelectionModel() {
 1732           return new DefaultListSelectionModel();
 1733       }
 1734   
 1735   
 1736       /**
 1737        * Returns the current selection model. The selection model maintains the
 1738        * selection state of the list. See the class level documentation for more
 1739        * details.
 1740        *
 1741        * @return the <code>ListSelectionModel</code> that maintains the
 1742        *         list's selections
 1743        *
 1744        * @see #setSelectionModel
 1745        * @see ListSelectionModel
 1746        */
 1747       public ListSelectionModel getSelectionModel() {
 1748           return selectionModel;
 1749       }
 1750   
 1751   
 1752       /**
 1753        * Notifies {@code ListSelectionListener}s added directly to the list
 1754        * of selection changes made to the selection model. {@code JList}
 1755        * listens for changes made to the selection in the selection model,
 1756        * and forwards notification to listeners added to the list directly,
 1757        * by calling this method.
 1758        * <p>
 1759        * This method constructs a {@code ListSelectionEvent} with this list
 1760        * as the source, and the specified arguments, and sends it to the
 1761        * registered {@code ListSelectionListeners}.
 1762        *
 1763        * @param firstIndex the first index in the range, {@code <= lastIndex}
 1764        * @param lastIndex the last index in the range, {@code >= firstIndex}
 1765        * @param isAdjusting whether or not this is one in a series of
 1766        *        multiple events, where changes are still being made
 1767        *
 1768        * @see #addListSelectionListener
 1769        * @see #removeListSelectionListener
 1770        * @see javax.swing.event.ListSelectionEvent
 1771        * @see EventListenerList
 1772        */
 1773       protected void fireSelectionValueChanged(int firstIndex, int lastIndex,
 1774                                                boolean isAdjusting)
 1775       {
 1776           Object[] listeners = listenerList.getListenerList();
 1777           ListSelectionEvent e = null;
 1778   
 1779           for (int i = listeners.length - 2; i >= 0; i -= 2) {
 1780               if (listeners[i] == ListSelectionListener.class) {
 1781                   if (e == null) {
 1782                       e = new ListSelectionEvent(this, firstIndex, lastIndex,
 1783                                                  isAdjusting);
 1784                   }
 1785                   ((ListSelectionListener)listeners[i+1]).valueChanged(e);
 1786               }
 1787           }
 1788       }
 1789   
 1790   
 1791       /* A ListSelectionListener that forwards ListSelectionEvents from
 1792        * the selectionModel to the JList ListSelectionListeners.  The
 1793        * forwarded events only differ from the originals in that their
 1794        * source is the JList instead of the selectionModel itself.
 1795        */
 1796       private class ListSelectionHandler implements ListSelectionListener, Serializable
 1797       {
 1798           public void valueChanged(ListSelectionEvent e) {
 1799               fireSelectionValueChanged(e.getFirstIndex(),
 1800                                         e.getLastIndex(),
 1801                                         e.getValueIsAdjusting());
 1802           }
 1803       }
 1804   
 1805   
 1806       /**
 1807        * Adds a listener to the list, to be notified each time a change to the
 1808        * selection occurs; the preferred way of listening for selection state
 1809        * changes. {@code JList} takes care of listening for selection state
 1810        * changes in the selection model, and notifies the given listener of
 1811        * each change. {@code ListSelectionEvent}s sent to the listener have a
 1812        * {@code source} property set to this list.
 1813        *
 1814        * @param listener the {@code ListSelectionListener} to add
 1815        * @see #getSelectionModel
 1816        * @see #getListSelectionListeners
 1817        */
 1818       public void addListSelectionListener(ListSelectionListener listener)
 1819       {
 1820           if (selectionListener == null) {
 1821               selectionListener = new ListSelectionHandler();
 1822               getSelectionModel().addListSelectionListener(selectionListener);
 1823           }
 1824   
 1825           listenerList.add(ListSelectionListener.class, listener);
 1826       }
 1827   
 1828   
 1829       /**
 1830        * Removes a selection listener from the list.
 1831        *
 1832        * @param listener the {@code ListSelectionListener} to remove
 1833        * @see #addListSelectionListener
 1834        * @see #getSelectionModel
 1835        */
 1836       public void removeListSelectionListener(ListSelectionListener listener) {
 1837           listenerList.remove(ListSelectionListener.class, listener);
 1838       }
 1839   
 1840   
 1841       /**
 1842        * Returns an array of all the {@code ListSelectionListener}s added
 1843        * to this {@code JList} by way of {@code addListSelectionListener}.
 1844        *
 1845        * @return all of the {@code ListSelectionListener}s on this list, or
 1846        *         an empty array if no listeners have been added
 1847        * @see #addListSelectionListener
 1848        * @since 1.4
 1849        */
 1850       public ListSelectionListener[] getListSelectionListeners() {
 1851           return (ListSelectionListener[])listenerList.getListeners(
 1852                   ListSelectionListener.class);
 1853       }
 1854   
 1855   
 1856       /**
 1857        * Sets the <code>selectionModel</code> for the list to a
 1858        * non-<code>null</code> <code>ListSelectionModel</code>
 1859        * implementation. The selection model handles the task of making single
 1860        * selections, selections of contiguous ranges, and non-contiguous
 1861        * selections.
 1862        * <p>
 1863        * This is a JavaBeans bound property.
 1864        *
 1865        * @param selectionModel  the <code>ListSelectionModel</code> that
 1866        *                          implements the selections
 1867        * @exception IllegalArgumentException   if <code>selectionModel</code>
 1868        *                                          is <code>null</code>
 1869        * @see #getSelectionModel
 1870        * @beaninfo
 1871        *       bound: true
 1872        * description: The selection model, recording which cells are selected.
 1873        */
 1874       public void setSelectionModel(ListSelectionModel selectionModel) {
 1875           if (selectionModel == null) {
 1876               throw new IllegalArgumentException("selectionModel must be non null");
 1877           }
 1878   
 1879           /* Remove the forwarding ListSelectionListener from the old
 1880            * selectionModel, and add it to the new one, if necessary.
 1881            */
 1882           if (selectionListener != null) {
 1883               this.selectionModel.removeListSelectionListener(selectionListener);
 1884               selectionModel.addListSelectionListener(selectionListener);
 1885           }
 1886   
 1887           ListSelectionModel oldValue = this.selectionModel;
 1888           this.selectionModel = selectionModel;
 1889           firePropertyChange("selectionModel", oldValue, selectionModel);
 1890       }
 1891   
 1892   
 1893       /**
 1894        * Sets the selection mode for the list. This is a cover method that sets
 1895        * the selection mode directly on the selection model.
 1896        * <p>
 1897        * The following list describes the accepted selection modes:
 1898        * <ul>
 1899        * <li>{@code ListSelectionModel.SINGLE_SELECTION} -
 1900        *   Only one list index can be selected at a time. In this mode,
 1901        *   {@code setSelectionInterval} and {@code addSelectionInterval} are
 1902        *   equivalent, both replacing the current selection with the index
 1903        *   represented by the second argument (the "lead").
 1904        * <li>{@code ListSelectionModel.SINGLE_INTERVAL_SELECTION} -
 1905        *   Only one contiguous interval can be selected at a time.
 1906        *   In this mode, {@code addSelectionInterval} behaves like
 1907        *   {@code setSelectionInterval} (replacing the current selection},
 1908        *   unless the given interval is immediately adjacent to or overlaps
 1909        *   the existing selection, and can be used to grow the selection.
 1910        * <li>{@code ListSelectionModel.MULTIPLE_INTERVAL_SELECTION} -
 1911        *   In this mode, there's no restriction on what can be selected.
 1912        *   This mode is the default.
 1913        * </ul>
 1914        *
 1915        * @param selectionMode the selection mode
 1916        * @see #getSelectionMode
 1917        * @throws IllegalArgumentException if the selection mode isn't
 1918        *         one of those allowed
 1919        * @beaninfo
 1920        * description: The selection mode.
 1921        *        enum: SINGLE_SELECTION            ListSelectionModel.SINGLE_SELECTION
 1922        *              SINGLE_INTERVAL_SELECTION   ListSelectionModel.SINGLE_INTERVAL_SELECTION
 1923        *              MULTIPLE_INTERVAL_SELECTION ListSelectionModel.MULTIPLE_INTERVAL_SELECTION
 1924        */
 1925       public void setSelectionMode(int selectionMode) {
 1926           getSelectionModel().setSelectionMode(selectionMode);
 1927       }
 1928   
 1929       /**
 1930        * Returns the current selection mode for the list. This is a cover
 1931        * method that delegates to the method of the same name on the
 1932        * list's selection model.
 1933        *
 1934        * @return the current selection mode
 1935        * @see #setSelectionMode
 1936        */
 1937       public int getSelectionMode() {
 1938           return getSelectionModel().getSelectionMode();
 1939       }
 1940   
 1941   
 1942       /**
 1943        * Returns the anchor selection index. This is a cover method that
 1944        * delegates to the method of the same name on the list's selection model.
 1945        *
 1946        * @return the anchor selection index
 1947        * @see ListSelectionModel#getAnchorSelectionIndex
 1948        */
 1949       public int getAnchorSelectionIndex() {
 1950           return getSelectionModel().getAnchorSelectionIndex();
 1951       }
 1952   
 1953   
 1954       /**
 1955        * Returns the lead 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 lead selection index
 1959        * @see ListSelectionModel#getLeadSelectionIndex
 1960        * @beaninfo
 1961        * description: The lead selection index.
 1962        */
 1963       public int getLeadSelectionIndex() {
 1964           return getSelectionModel().getLeadSelectionIndex();
 1965       }
 1966   
 1967   
 1968       /**
 1969        * Returns the smallest selected cell index, or {@code -1} if the selection
 1970        * is empty. This is a cover method that delegates to the method of the same
 1971        * name on the list's selection model.
 1972        *
 1973        * @return the smallest selected cell index, or {@code -1}
 1974        * @see ListSelectionModel#getMinSelectionIndex
 1975        */
 1976       public int getMinSelectionIndex() {
 1977           return getSelectionModel().getMinSelectionIndex();
 1978       }
 1979   
 1980   
 1981       /**
 1982        * Returns the largest selected cell index, or {@code -1} if the selection
 1983        * is empty. This is a cover method that delegates to the method of the same
 1984        * name on the list's selection model.
 1985        *
 1986        * @return the largest selected cell index
 1987        * @see ListSelectionModel#getMaxSelectionIndex
 1988        */
 1989       public int getMaxSelectionIndex() {
 1990           return getSelectionModel().getMaxSelectionIndex();
 1991       }
 1992   
 1993   
 1994       /**
 1995        * Returns {@code true} if the specified index is selected,
 1996        * else {@code false}. This is a cover method that delegates to the method
 1997        * of the same name on the list's selection model.
 1998        *
 1999        * @param index index to be queried for selection state
 2000        * @return {@code true} if the specified index is selected,
 2001        *         else {@code false}
 2002        * @see ListSelectionModel#isSelectedIndex
 2003        * @see #setSelectedIndex
 2004        */
 2005       public boolean isSelectedIndex(int index) {
 2006           return getSelectionModel().isSelectedIndex(index);
 2007       }
 2008   
 2009   
 2010       /**
 2011        * Returns {@code true} if nothing is selected, else {@code false}.
 2012        * This is a cover method that delegates to the method of the same
 2013        * name on the list's selection model.
 2014        *
 2015        * @return {@code true} if nothing is selected, else {@code false}
 2016        * @see ListSelectionModel#isSelectionEmpty
 2017        * @see #clearSelection
 2018        */
 2019       public boolean isSelectionEmpty() {
 2020           return getSelectionModel().isSelectionEmpty();
 2021       }
 2022   
 2023   
 2024       /**
 2025        * Clears the selection; after calling this method, {@code isSelectionEmpty}
 2026        * will return {@code true}. This is a cover method that delegates to the
 2027        * method of the same name on the list's selection model.
 2028        *
 2029        * @see ListSelectionModel#clearSelection
 2030        * @see #isSelectionEmpty
 2031        */
 2032       public void clearSelection() {
 2033           getSelectionModel().clearSelection();
 2034       }
 2035   
 2036   
 2037       /**
 2038        * Selects the specified interval. Both {@code anchor} and {@code lead}
 2039        * indices are included. {@code anchor} doesn't have to be less than or
 2040        * equal to {@code lead}. This is a cover method that delegates to the
 2041        * method of the same name on the list's selection model.
 2042        * <p>
 2043        * Refer to the documentation of the selection model class being used
 2044        * for details on how values less than {@code 0} are handled.
 2045        *
 2046        * @param anchor the first index to select
 2047        * @param lead the last index to select
 2048        * @see ListSelectionModel#setSelectionInterval
 2049        * @see DefaultListSelectionModel#setSelectionInterval
 2050        * @see #createSelectionModel
 2051        * @see #addSelectionInterval
 2052        * @see #removeSelectionInterval
 2053        */
 2054       public void setSelectionInterval(int anchor, int lead) {
 2055           getSelectionModel().setSelectionInterval(anchor, lead);
 2056       }
 2057   
 2058   
 2059       /**
 2060        * Sets the selection to be the union of the specified interval with current
 2061        * selection. Both the {@code anchor} and {@code lead} indices are
 2062        * included. {@code anchor} doesn't have to be less than or
 2063        * equal to {@code lead}. This is a cover method that delegates to the
 2064        * method of the same name on the list's selection model.
 2065        * <p>
 2066        * Refer to the documentation of the selection model class being used
 2067        * for details on how values less than {@code 0} are handled.
 2068        *
 2069        * @param anchor the first index to add to the selection
 2070        * @param lead the last index to add to the selection
 2071        * @see ListSelectionModel#addSelectionInterval
 2072        * @see DefaultListSelectionModel#addSelectionInterval
 2073        * @see #createSelectionModel
 2074        * @see #setSelectionInterval
 2075        * @see #removeSelectionInterval
 2076        */
 2077       public void addSelectionInterval(int anchor, int lead) {
 2078           getSelectionModel().addSelectionInterval(anchor, lead);
 2079       }
 2080   
 2081   
 2082       /**
 2083        * Sets the selection to be the set difference of the specified interval
 2084        * and the current selection. Both the {@code index0} and {@code index1}
 2085        * indices are removed. {@code index0} doesn't have to be less than or
 2086        * equal to {@code index1}. This is a cover method that delegates to the
 2087        * method of the same name on the list's selection model.
 2088        * <p>
 2089        * Refer to the documentation of the selection model class being used
 2090        * for details on how values less than {@code 0} are handled.
 2091        *
 2092        * @param index0 the first index to remove from the selection
 2093        * @param index1 the last index to remove from the selection
 2094        * @see ListSelectionModel#removeSelectionInterval
 2095        * @see DefaultListSelectionModel#removeSelectionInterval
 2096        * @see #createSelectionModel
 2097        * @see #setSelectionInterval
 2098        * @see #addSelectionInterval
 2099        */
 2100       public void removeSelectionInterval(int index0, int index1) {
 2101           getSelectionModel().removeSelectionInterval(index0, index1);
 2102       }
 2103   
 2104   
 2105       /**
 2106        * Sets the selection model's {@code valueIsAdjusting} property. When
 2107        * {@code true}, upcoming changes to selection should be considered part
 2108        * of a single change. This property is used internally and developers
 2109        * typically need not call this method. For example, when the model is being
 2110        * updated in response to a user drag, the value of the property is set
 2111        * to {@code true} when the drag is initiated and set to {@code false}
 2112        * when the drag is finished. This allows listeners to update only
 2113        * when a change has been finalized, rather than handling all of the
 2114        * intermediate values.
 2115        * <p>
 2116        * You may want to use this directly if making a series of changes
 2117        * that should be considered part of a single change.
 2118        * <p>
 2119        * This is a cover method that delegates to the method of the same name on
 2120        * the list's selection model. See the documentation for
 2121        * {@link javax.swing.ListSelectionModel#setValueIsAdjusting} for
 2122        * more details.
 2123        *
 2124        * @param b the new value for the property
 2125        * @see ListSelectionModel#setValueIsAdjusting
 2126        * @see javax.swing.event.ListSelectionEvent#getValueIsAdjusting
 2127        * @see #getValueIsAdjusting
 2128        */
 2129       public void setValueIsAdjusting(boolean b) {
 2130           getSelectionModel().setValueIsAdjusting(b);
 2131       }
 2132   
 2133   
 2134       /**
 2135        * Returns the value of the selection model's {@code isAdjusting} property.
 2136        * <p>
 2137        * This is a cover method that delegates to the method of the same name on
 2138        * the list's selection model.
 2139        *
 2140        * @return the value of the selection model's {@code isAdjusting} property.
 2141        *
 2142        * @see #setValueIsAdjusting
 2143        * @see ListSelectionModel#getValueIsAdjusting
 2144        */
 2145       public boolean getValueIsAdjusting() {
 2146           return getSelectionModel().getValueIsAdjusting();
 2147       }
 2148   
 2149   
 2150       /**
 2151        * Returns an array of all of the selected indices, in increasing
 2152        * order.
 2153        *
 2154        * @return all of the selected indices, in increasing order,
 2155        *         or an empty array if nothing is selected
 2156        * @see #removeSelectionInterval
 2157        * @see #addListSelectionListener
 2158        */
 2159       @Transient
 2160       public int[] getSelectedIndices() {
 2161           ListSelectionModel sm = getSelectionModel();
 2162           int iMin = sm.getMinSelectionIndex();
 2163           int iMax = sm.getMaxSelectionIndex();
 2164   
 2165           if ((iMin < 0) || (iMax < 0)) {
 2166               return new int[0];
 2167           }
 2168   
 2169           int[] rvTmp = new int[1+ (iMax - iMin)];
 2170           int n = 0;
 2171           for(int i = iMin; i <= iMax; i++) {
 2172               if (sm.isSelectedIndex(i)) {
 2173                   rvTmp[n++] = i;
 2174               }
 2175           }
 2176           int[] rv = new int[n];
 2177           System.arraycopy(rvTmp, 0, rv, 0, n);
 2178           return rv;
 2179       }
 2180   
 2181   
 2182       /**
 2183        * Selects a single cell. Does nothing if the given index is greater
 2184        * than or equal to the model size. This is a convenience method that uses
 2185        * {@code setSelectionInterval} on the selection model. Refer to the
 2186        * documentation for the selection model class being used for details on
 2187        * how values less than {@code 0} are handled.
 2188        *
 2189        * @param index the index of the cell to select
 2190        * @see ListSelectionModel#setSelectionInterval
 2191        * @see #isSelectedIndex
 2192        * @see #addListSelectionListener
 2193        * @beaninfo
 2194        * description: The index of the selected cell.
 2195        */
 2196       public void setSelectedIndex(int index) {
 2197           if (index >= getModel().getSize()) {
 2198               return;
 2199           }
 2200           getSelectionModel().setSelectionInterval(index, index);
 2201       }
 2202   
 2203   
 2204       /**
 2205        * Changes the selection to be the set of indices specified by the given
 2206        * array. Indices greater than or equal to the model size are ignored.
 2207        * This is a convenience method that clears the selection and then uses
 2208        * {@code addSelectionInterval} on the selection model to add the indices.
 2209        * Refer to the documentation of the selection model class being used for
 2210        * details on how values less than {@code 0} are handled.
 2211        *
 2212        * @param indices an array of the indices of the cells to select,
 2213        *                {@code non-null}
 2214        * @see ListSelectionModel#addSelectionInterval
 2215        * @see #isSelectedIndex
 2216        * @see #addListSelectionListener
 2217        * @throws NullPointerException if the given array is {@code null}
 2218        */
 2219       public void setSelectedIndices(int[] indices) {
 2220           ListSelectionModel sm = getSelectionModel();
 2221           sm.clearSelection();
 2222           int size = getModel().getSize();
 2223           for(int i = 0; i < indices.length; i++) {
 2224               if (indices[i] < size) {
 2225                   sm.addSelectionInterval(indices[i], indices[i]);
 2226               }
 2227           }
 2228       }
 2229   
 2230   
 2231       /**
 2232        * Returns an array of all the selected values, in increasing order based
 2233        * on their indices in the list.
 2234        *
 2235        * @return the selected values, or an empty array if nothing is selected
 2236        * @see #isSelectedIndex
 2237        * @see #getModel
 2238        * @see #addListSelectionListener
 2239        */
 2240       public Object[] getSelectedValues() {
 2241           ListSelectionModel sm = getSelectionModel();
 2242           ListModel dm = getModel();
 2243   
 2244           int iMin = sm.getMinSelectionIndex();
 2245           int iMax = sm.getMaxSelectionIndex();
 2246   
 2247           if ((iMin < 0) || (iMax < 0)) {
 2248               return new Object[0];
 2249           }
 2250   
 2251           Object[] rvTmp = new Object[1+ (iMax - iMin)];
 2252           int n = 0;
 2253           for(int i = iMin; i <= iMax; i++) {
 2254               if (sm.isSelectedIndex(i)) {
 2255                   rvTmp[n++] = dm.getElementAt(i);
 2256               }
 2257           }
 2258           Object[] rv = new Object[n];
 2259           System.arraycopy(rvTmp, 0, rv, 0, n);
 2260           return rv;
 2261       }
 2262   
 2263   
 2264       /**
 2265        * Returns the smallest selected cell index; <i>the selection</i> when only
 2266        * a single item is selected in the list. When multiple items are selected,
 2267        * it is simply the smallest selected index. Returns {@code -1} if there is
 2268        * no selection.
 2269        * <p>
 2270        * This method is a cover that delegates to {@code getMinSelectionIndex}.
 2271        *
 2272        * @return the smallest selected cell index
 2273        * @see #getMinSelectionIndex
 2274        * @see #addListSelectionListener
 2275        */
 2276       public int getSelectedIndex() {
 2277           return getMinSelectionIndex();
 2278       }
 2279   
 2280   
 2281       /**
 2282        * Returns the value for the smallest selected cell index;
 2283        * <i>the selected value</i> when only a single item is selected in the
 2284        * list. When multiple items are selected, it is simply the value for the
 2285        * smallest selected index. Returns {@code null} if there is no selection.
 2286        * <p>
 2287        * This is a convenience method that simply returns the model value for
 2288        * {@code getMinSelectionIndex}.
 2289        *
 2290        * @return the first selected value
 2291        * @see #getMinSelectionIndex
 2292        * @see #getModel
 2293        * @see #addListSelectionListener
 2294        */
 2295       public Object getSelectedValue() {
 2296           int i = getMinSelectionIndex();
 2297           return (i == -1) ? null : getModel().getElementAt(i);
 2298       }
 2299   
 2300   
 2301       /**
 2302        * Selects the specified object from the list.
 2303        *
 2304        * @param anObject      the object to select
 2305        * @param shouldScroll  {@code true} if the list should scroll to display
 2306        *                      the selected object, if one exists; otherwise {@code false}
 2307        */
 2308       public void setSelectedValue(Object anObject,boolean shouldScroll) {
 2309           if(anObject == null)
 2310               setSelectedIndex(-1);
 2311           else if(!anObject.equals(getSelectedValue())) {
 2312               int i,c;
 2313               ListModel dm = getModel();
 2314               for(i=0,c=dm.getSize();i<c;i++)
 2315                   if(anObject.equals(dm.getElementAt(i))){
 2316                       setSelectedIndex(i);
 2317                       if(shouldScroll)
 2318                           ensureIndexIsVisible(i);
 2319                       repaint();  /** FIX-ME setSelectedIndex does not redraw all the time with the basic l&f**/
 2320                       return;
 2321                   }
 2322               setSelectedIndex(-1);
 2323           }
 2324           repaint(); /** FIX-ME setSelectedIndex does not redraw all the time with the basic l&f**/
 2325       }
 2326   
 2327   
 2328   
 2329       /**
 2330        * --- The Scrollable Implementation ---
 2331        */
 2332   
 2333       private void checkScrollableParameters(Rectangle visibleRect, int orientation) {
 2334           if (visibleRect == null) {
 2335               throw new IllegalArgumentException("visibleRect must be non-null");
 2336           }
 2337           switch (orientation) {
 2338           case SwingConstants.VERTICAL:
 2339           case SwingConstants.HORIZONTAL:
 2340               break;
 2341           default:
 2342               throw new IllegalArgumentException("orientation must be one of: VERTICAL, HORIZONTAL");
 2343           }
 2344       }
 2345   
 2346   
 2347       /**
 2348        * Computes the size of viewport needed to display {@code visibleRowCount}
 2349        * rows. The value returned by this method depends on the layo