    rev 48858 : Work in progress for JDK-6303622
    Use generic in Swing components like JComboBox
    1. Added generic return type and parameter type for JComboBox.
    2. Modified JList related classes as well.
    3. Reverted the changes made to "getSelectedValues" as suggested by Joe.
    4. Modified files that were failing on Linux and Mac as well.

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

    2268     }
    2269
    2270     /**
    2271      * Returns a list of all the selected items, in increasing order based
    2272      * on their indices in the list.
    2273      *
    2274      * @return the selected items, or an empty list if nothing is selected
    2275      * @see #isSelectedIndex
    2276      * @see #getModel
    2277      * @see #addListSelectionListener
    2278      *
    2279      * @since 1.7
    2280      */
    2281     @BeanProperty(bound = false)
    2282     public List<E> getSelectedValuesList() {
    2283         ListSelectionModel sm = getSelectionModel();
    2284         ListModel<E> dm = getModel();
    2285
    2286         int iMin = sm.getMinSelectionIndex();
    2287         int iMax = sm.getMaxSelectionIndex();
    2288
    2289         if ((iMin < 0) || (iMax < 0)) {
    2290             return Collections.emptyList();
    2291         }
    2292
    2293         List<E> selectedItems = new ArrayList<E>();
    2294         for(int i = iMin; i <= iMax; i++) {
    2295             if (sm.isSelectedIndex(i)) {
    2296                 selectedItems.add(dm.getElementAt(i));
    2297             }
    2298         }
    2299         return selectedItems;
    2300     }
    2301
    2302
    2303     /**
    2304      * Returns the smallest selected cell index; <i>the selection</i> when only
    2305      * a single item is selected in the list. When multiple items are selected,
    2306      * it is simply the smallest selected index. Returns {@code -1} if there is
    2307      * no selection.
    2308      * <p>
    2309      * This method is a cover that delegates to {@code getMinSelectionIndex}.
    2310      *
    2311      * @return the smallest selected cell index
    2312      * @see #getMinSelectionIndex
    2313      * @see #addListSelectionListener
    2314      */
    2315     public int getSelectedIndex() {
    2316         return getMinSelectionIndex();
    2317     }
    2318
    2319
    2320     /**
    2321      * Returns the value for the smallest selected cell index;
    2322      * <i>the selected value</i> when only a single item is selected in the
    2323      * list. When multiple items are selected, it is simply the value for the
    2324      * smallest selected index. Returns {@code null} if there is no selection.
    2325      * <p>
    2326      * This is a convenience method that simply returns the model value for
    2327      * {@code getMinSelectionIndex}.
    2328      *
    2329      * @return the first selected value
    2330      * @see #getMinSelectionIndex
    2331      * @see #getModel
    2332      * @see #addListSelectionListener
    2333      */
    2334     @BeanProperty(bound = false)
    2335     public E getSelectedValue() {
    2336         int i = getMinSelectionIndex();
    2337         return (i == -1) ? null : getModel().getElementAt(i);
    2338     }
    2339
    2340
    2341     /**
    2342      * Selects the specified object from the list.
    2343      *
    2344      * @param <E> the type of the elements of this JList.
    2345      * @param anObject      the object to select
    2346      * @param shouldScroll  {@code true} if the list should scroll to display
    2347      *                      the selected object, if one exists; otherwise {@code false}
    2348      */
    2349     public void setSelectedValue(E anObject,boolean shouldScroll) {
    2350         if(anObject == null)
    2351             setSelectedIndex(-1);
    2352         else if(!anObject.equals(getSelectedValue())) {
    2353             int i,c;
    2354             ListModel<E> dm = getModel();
    2355             for(i=0,c=dm.getSize();i<c;i++)
    2356                 if(anObject.equals(dm.getElementAt(i))){
    2357                     setSelectedIndex(i);
    2358                     if(shouldScroll)
    2359                         ensureIndexIsVisible(i);
    2360                     repaint();  /** FIX-ME setSelectedIndex does not redraw all the time with the basic l&f**/
    2361                     return;
    2362                 }
    2363             setSelectedIndex(-1);
    2364         }
    2365         repaint(); /** FIX-ME setSelectedIndex does not redraw all the time with the basic l&f**/
    2366     }
    2367
    2368
    2369
    2370     /**
    2371      * --- The Scrollable Implementation ---
    2372      */
    2373
    2374     private void checkScrollableParameters(Rectangle visibleRect, int orientation) {
    2375         if (visibleRect == null) {
    2376             throw new IllegalArgumentException("visibleRect must be non-null");
    2377         }
    2378         switch (orientation) {
    2379         case SwingConstants.VERTICAL:
    2380         case SwingConstants.HORIZONTAL:
    2381             break;
    2382         default:
    2383             throw new IllegalArgumentException("orientation must be one of: VERTICAL, HORIZONTAL");
    2384         }
    2385     }
    2386
    2387
    2388     /**
    2389      * Computes the size of viewport needed to display {@code visibleRowCount}
    2390      * rows. The value returned by this method depends on the layout
    2391      * orientation:
    2392      * <p>
    2393      * <b>{@code VERTICAL}:</b>
    2394      * <br>
    2395      * This is trivial if both {@code fixedCellWidth} and {@code fixedCellHeight}
    2396      * have been set (either explicitly or by specifying a prototype cell value).
    2397      * The width is simply the {@code fixedCellWidth} plus the list's horizontal
    2398      * insets. The height is the {@code fixedCellHeight} multiplied by the
    2399      * {@code visibleRowCount}, plus the list's vertical insets.
    2400      * <p>
    2401      * If either {@code fixedCellWidth} or {@code fixedCellHeight} haven't been
    2402      * specified, heuristics are used. If the model is empty, the width is
    2403      * the {@code fixedCellWidth}, if greater than {@code 0}, or a hard-coded
    2404      * value of {@code 256}. The height is the {@code fixedCellHeight} multiplied
    2405      * by {@code visibleRowCount}, if {@code fixedCellHeight} is greater than
    2406      * {@code 0}, otherwise it is a hard-coded value of {@code 16} multiplied by
    2407      * {@code visibleRowCount}.
    2408      * <p>
    2409      * If the model isn't empty, the width is the preferred size's width,
    2410      * typically the width of the widest list element. The height is the
    2411      * {@code fixedCellHeight} multiplied by the {@code visibleRowCount},
    2412      * plus the list's vertical insets.
    2413      * <p>
    2414      * <b>{@code VERTICAL_WRAP} or {@code HORIZONTAL_WRAP}:</b>
    2415      * <br>
    2416      * This method simply returns the value from {@code getPreferredSize}.
    2417      * The list's {@code ListUI} is expected to override {@code getPreferredSize}
    2418      * to return an appropriate value.
    2419      *
    2420      * @return a dimension containing the size of the viewport needed
    2421      *          to display {@code visibleRowCount} rows
    2422      * @see #getPreferredScrollableViewportSize
    2423      * @see #setPrototypeCellValue
    2424      */
    2425     @BeanProperty(bound = false)
    2426     public Dimension getPreferredScrollableViewportSize()
    2427     {
    2428         if (getLayoutOrientation() != VERTICAL) {
    2429             return getPreferredSize();
    2430         }
    2431         Insets insets = getInsets();
    2432         int dx = insets.left + insets.right;
    2433         int dy = insets.top + insets.bottom;
    2434
    2435         int visibleRowCount = getVisibleRowCount();
    2436         int fixedCellWidth = getFixedCellWidth();
    2437         int fixedCellHeight = getFixedCellHeight();
    2438
    2439         if ((fixedCellWidth > 0) && (fixedCellHeight > 0)) {
    2440             int width = fixedCellWidth + dx;
    2441             int height = (visibleRowCount * fixedCellHeight) + dy;
    2442             return new Dimension(width, height);
    2443         }
    2444         else if (getModel().getSize() > 0) {
    2445             int width = getPreferredSize().width;
    2446             int height;
    2447             Rectangle r = getCellBounds(0, 0);
    2448             if (r != null) {
    2449                 height = (visibleRowCount * r.height) + dy;
    2450             }
    2451             else {
    2452                 // Will only happen if UI null, shouldn't matter what we return
    2453                 height = 1;
    2454             }
    2455             return new Dimension(width, height);
    2456         }
    2457         else {
    2458             fixedCellWidth = (fixedCellWidth > 0) ? fixedCellWidth : 256;
    2459             fixedCellHeight = (fixedCellHeight > 0) ? fixedCellHeight : 16;
    2460             return new Dimension(fixedCellWidth, fixedCellHeight * visibleRowCount);
    2461         }
    2462     }
    2463
    2464
    2465     /**
    2466      * Returns the distance to scroll to expose the next or previous
    2467      * row (for vertical scrolling) or column (for horizontal scrolling).
    2468      * <p>
    2469      * For horizontal scrolling, if the layout orientation is {@code VERTICAL},
    2470      * then the list's font size is returned (or {@code 1} if the font is
    2471      * {@code null}).
    2472      *
    2473      * @param visibleRect the view area visible within the viewport
    2474      * @param orientation {@code SwingConstants.HORIZONTAL} or
    2475      *                    {@code SwingConstants.VERTICAL}
    2476      * @param direction less or equal to zero to scroll up/back,
    2477      *                  greater than zero for down/forward
    2478      * @return the "unit" increment for scrolling in the specified direction;
    2479      *         always positive
    2480      * @see #getScrollableBlockIncrement
    2481      * @see Scrollable#getScrollableUnitIncrement
    2482      * @throws IllegalArgumentException if {@code visibleRect} is {@code null}, or
    2483      *         {@code orientation} isn't one of {@code SwingConstants.VERTICAL} or
    2484      *         {@code SwingConstants.HORIZONTAL}
    2485      */
    2486     public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction)
    2487     {
    2488         checkScrollableParameters(visibleRect, orientation);
    2489
    2490         if (orientation == SwingConstants.VERTICAL) {
    2491             int row = locationToIndex(visibleRect.getLocation());
    2492
    2493             if (row == -1) {
    2494                 return 0;
    2495             }
    2496             else {
    2497                 /* Scroll Down */
    2498                 if (direction > 0) {
    2499                     Rectangle r = getCellBounds(row, row);
    2500                     return (r == null) ? 0 : r.height - (visibleRect.y - r.y);
    2501                 }
    2502                 /* Scroll Up */
    2503                 else {
    2504                     Rectangle r = getCellBounds(row, row);
    2505
    2506                     /* The first row is completely visible and it's row 0.
    2507                      * We're done.
    2508                      */
    2509                     if ((r.y == visibleRect.y) && (row == 0))  {
    2510                         return 0;
    2511                     }
    2512                     /* The first row is completely visible, return the
    2513                      * height of the previous row or 0 if the first row
    2514                      * is the top row of the list.
    2515                      */
    2516                     else if (r.y == visibleRect.y) {
    2517                         Point loc = r.getLocation();
    2518                         loc.y--;
    2519                         int prevIndex = locationToIndex(loc);
    2520                         Rectangle prevR = getCellBounds(prevIndex, prevIndex);
    2521
    2522                         if (prevR == null || prevR.y >= r.y) {
    2523                             return 0;
    2524                         }
    2525                         return prevR.height;
    2526                     }
    2527                     /* The first row is partially visible, return the
    2528                      * height of hidden part.
    2529                      */
    2530                     else {
    2531                         return visibleRect.y - r.y;
    2532                     }
    2533                 }
    2534             }
    2535         } else if (orientation == SwingConstants.HORIZONTAL &&
    2536                            getLayoutOrientation() != JList.VERTICAL) {
    2537             boolean leftToRight = getComponentOrientation().isLeftToRight();
    2538             int index;
    2539             Point leadingPoint;
    2540
    2541             if (leftToRight) {
    2542                 leadingPoint = visibleRect.getLocation();
    2543             }
    2544             else {
    2545                 leadingPoint = new Point(visibleRect.x + visibleRect.width -1,
    2546                                          visibleRect.y);
    2547             }
    2548             index = locationToIndex(leadingPoint);
    2549
    2550             if (index != -1) {
    2551                 Rectangle cellBounds = getCellBounds(index, index);
    2552                 if (cellBounds != null && cellBounds.contains(leadingPoint)) {
    2553                     int leadingVisibleEdge;
    2554                     int leadingCellEdge;
    2555
    2556                     if (leftToRight) {
    2557                         leadingVisibleEdge = visibleRect.x;
    2558                         leadingCellEdge = cellBounds.x;
    2559                     }
    2560                     else {
    2561                         leadingVisibleEdge = visibleRect.x + visibleRect.width;
    2562                         leadingCellEdge = cellBounds.x + cellBounds.width;
    2563                     }
    2564
    2565                     if (leadingCellEdge != leadingVisibleEdge) {
    2566                         if (direction < 0) {
    2567                             // Show remainder of leading cell
    2568                             return Math.abs(leadingVisibleEdge - leadingCellEdge);
    2569
    2570                         }
    2571                         else if (leftToRight) {
    2572                             // Hide rest of leading cell
    2573                             return leadingCellEdge + cellBounds.width - leadingVisibleEdge;
    2574                         }
    2575                         else {
    2576                             // Hide rest of leading cell
    2577                             return leadingVisibleEdge - cellBounds.x;
    2578                         }
    2579                     }
    2580                     // ASSUME: All cells are the same width
    2581                     return cellBounds.width;
    2582                 }
    2583             }
    2584         }
    2585         Font f = getFont();
    2586         return (f != null) ? f.getSize() : 1;
    2587     }
    2588
    2589
    2590     /**
    2591      * Returns the distance to scroll to expose the next or previous block.
    2592      * <p>
    2593      * For vertical scrolling, the following rules are used:
    2594      * <ul>
    2595      * <li>if scrolling down, returns the distance to scroll so that the last
    2596      * visible element becomes the first completely visible element
    2597      * <li>if scrolling up, returns the distance to scroll so that the first
    2598      * visible element becomes the last completely visible element
    2599      * <li>returns {@code visibleRect.height} if the list is empty
    2600      * </ul>
    2601      * <p>
    2602      * For horizontal scrolling, when the layout orientation is either
    2603      * {@code VERTICAL_WRAP} or {@code HORIZONTAL_WRAP}:
    2604      * <ul>
    2605      * <li>if scrolling right, returns the distance to scroll so that the
    2606      * last visible element becomes
    2607      * the first completely visible element
    2608      * <li>if scrolling left, returns the distance to scroll so that the first
    2609      * visible element becomes the last completely visible element
    2610      * <li>returns {@code visibleRect.width} if the list is empty
    2611      * </ul>
    2612      * <p>
    2613      * For horizontal scrolling and {@code VERTICAL} orientation,
    2614      * returns {@code visibleRect.width}.
    2615      * <p>
    2616      * Note that the value of {@code visibleRect} must be the equal to
    2617      * {@code this.getVisibleRect()}.
    2618      *
    2619      * @param visibleRect the view area visible within the viewport
    2620      * @param orientation {@code SwingConstants.HORIZONTAL} or
    2621      *                    {@code SwingConstants.VERTICAL}
    2622      * @param direction less or equal to zero to scroll up/back,
    2623      *                  greater than zero for down/forward
    2624      * @return the "block" increment for scrolling in the specified direction;
    2625      *         always positive
    2626      * @see #getScrollableUnitIncrement
    2627      * @see Scrollable#getScrollableBlockIncrement
    2628      * @throws IllegalArgumentException if {@code visibleRect} is {@code null}, or
    2629      *         {@code orientation} isn't one of {@code SwingConstants.VERTICAL} or
    2630      *         {@code SwingConstants.HORIZONTAL}
    2631      */
    2632     public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
    2633         checkScrollableParameters(visibleRect, orientation);
    2634         if (orientation == SwingConstants.VERTICAL) {
    2635             int inc = visibleRect.height;
    2636             /* Scroll Down */
    2637             if (direction > 0) {
    2638                 // last cell is the lowest left cell
    2639                 int last = locationToIndex(new Point(visibleRect.x, visibleRect.y+visibleRect.height-1));
    2640                 if (last != -1) {
    2641                     Rectangle lastRect = getCellBounds(last,last);
    2642                     if (lastRect != null) {
    2643                         inc = lastRect.y - visibleRect.y;
    2644                         if ( (inc == 0) && (last < getModel().getSize()-1) ) {
    2645                             inc = lastRect.height;
    2646                         }
    2647                     }
    2648                 }
    2649             }
    2650             /* Scroll Up */
    2651             else {
    2652                 int newFirst = locationToIndex(new Point(visibleRect.x, visibleRect.y-visibleRect.height));
    2653                 int first = getFirstVisibleIndex();
    2654                 if (newFirst != -1) {
    2655                     if (first == -1) {
    2656                         first = locationToIndex(visibleRect.getLocation());
    2657                     }
    2658                     Rectangle newFirstRect = getCellBounds(newFirst,newFirst);
    2659                     Rectangle firstRect = getCellBounds(first,first);
    2660                     if ((newFirstRect != null) && (firstRect!=null)) {
    2661                         while ( (newFirstRect.y + visibleRect.height <
    2662                                  firstRect.y + firstRect.height) &&
    2663                                 (newFirstRect.y < firstRect.y) ) {
    2664                             newFirst++;
    2665                             newFirstRect = getCellBounds(newFirst,newFirst);
    2666                         }
    2667                         inc = visibleRect.y - newFirstRect.y;
    2668                         if ( (inc <= 0) && (newFirstRect.y > 0)) {
    2669                             newFirst--;
    2670                             newFirstRect = getCellBounds(newFirst,newFirst);
    2671                             if (newFirstRect != null) {
    2672                                 inc = visibleRect.y - newFirstRect.y;
    2673                             }
    2674                         }
    2675                     }
    2676                 }
    2677             }
    2678             return inc;
    2679         }
    2680         else if (orientation == SwingConstants.HORIZONTAL &&
    2681                  getLayoutOrientation() != JList.VERTICAL) {
    2682             boolean leftToRight = getComponentOrientation().isLeftToRight();
    2683             int inc = visibleRect.width;
    2684             /* Scroll Right (in ltr mode) or Scroll Left (in rtl mode) */
    2685             if (direction > 0) {
    2686                 // position is upper right if ltr, or upper left otherwise
    2687                 int x = visibleRect.x + (leftToRight ? (visibleRect.width - 1) : 0);
    2688                 int last = locationToIndex(new Point(x, visibleRect.y));
    2689
    2690                 if (last != -1) {
    2691                     Rectangle lastRect = getCellBounds(last,last);
    2692                     if (lastRect != null) {
    2693                         if (leftToRight) {
    2694                             inc = lastRect.x - visibleRect.x;
    2695                         } else {
    2696                             inc = visibleRect.x + visibleRect.width
    2697                                       - (lastRect.x + lastRect.width);
    2698                         }
    2699                         if (inc < 0) {
    2700                             inc += lastRect.width;
    2701                         } else if ( (inc == 0) && (last < getModel().getSize()-1) ) {
    2702                             inc = lastRect.width;
    2703                         }
    2704                     }
    2705                 }
    2706             }
    2707             /* Scroll Left (in ltr mode) or Scroll Right (in rtl mode) */
    2708             else {
    2709                 // position is upper left corner of the visibleRect shifted
    2710                 // left by the visibleRect.width if ltr, or upper right shifted
    2711                 // right by the visibleRect.width otherwise
    2712                 int x = visibleRect.x + (leftToRight
    2713                                          ? -visibleRect.width
    2714                                          : visibleRect.width - 1 + visibleRect.width);
    2715                 int first = locationToIndex(new Point(x, visibleRect.y));
    2716
    2717                 if (first != -1) {
    2718                     Rectangle firstRect = getCellBounds(first,first);
    2719                     if (firstRect != null) {
    2720                         // the right of the first cell
    2721                         int firstRight = firstRect.x + firstRect.width;
    2722
    2723                         if (leftToRight) {
    2724                             if ((firstRect.x < visibleRect.x - visibleRect.width)
    2725                                     && (firstRight < visibleRect.x)) {
    2726                                 inc = visibleRect.x - firstRight;
    2727                             } else {
    2728                                 inc = visibleRect.x - firstRect.x;
    2729                             }
    2730                         } else {
    2731                             int visibleRight = visibleRect.x + visibleRect.width;
    2732
    2733                             if ((firstRight > visibleRight + visibleRect.width)
    2734                                     && (firstRect.x > visibleRight)) {
    2735                                 inc = firstRect.x - visibleRight;
    2736                             } else {
    2737                                 inc = firstRight - visibleRight;
    2738                             }
    2739                         }
    2740                     }
    2741                 }
    2742             }
    2743             return inc;
    2744         }
    2745         return visibleRect.width;
    2746     }
    2747
    2748
    2749     /**
    2750      * Returns {@code true} if this {@code JList} is displayed in a
    2751      * {@code JViewport} and the viewport is wider than the list's
    2752      * preferred width, or if the layout orientation is {@code HORIZONTAL_WRAP}
    2753      * and {@code visibleRowCount <= 0}; otherwise returns {@code false}.
    2754      * <p>
    2755      * If {@code false}, then don't track the viewport's width. This allows
    2756      * horizontal scrolling if the {@code JViewport} is itself embedded in a
    2757      * {@code JScrollPane}.
    2758      *
    2759      * @return whether or not an enclosing viewport should force the list's
    2760      *         width to match its own
    2761      * @see Scrollable#getScrollableTracksViewportWidth
    2762      */
    2763     @BeanProperty(bound = false)
    2764     public boolean getScrollableTracksViewportWidth() {
    2765         if (getLayoutOrientation() == HORIZONTAL_WRAP &&
    2766                                       getVisibleRowCount() <= 0) {
    2767             return true;
    2768         }
    2769         Container parent = SwingUtilities.getUnwrappedParent(this);
    2770         if (parent instanceof JViewport) {
    2771             return parent.getWidth() > getPreferredSize().width;
    2772         }
    2773         return false;
    2774     }
    2775
    2776     /**
    2777      * Returns {@code true} if this {@code JList} is displayed in a
    2778      * {@code JViewport} and the viewport is taller than the list's
    2779      * preferred height, or if the layout orientation is {@code VERTICAL_WRAP}
    2780      * and {@code visibleRowCount <= 0}; otherwise returns {@code false}.
    2781      * <p>
    2782      * If {@code false}, then don't track the viewport's height. This allows
    2783      * vertical scrolling if the {@code JViewport} is itself embedded in a
    2784      * {@code JScrollPane}.
    2785      *
    2786      * @return whether or not an enclosing viewport should force the list's
    2787      *         height to match its own
    2788      * @see Scrollable#getScrollableTracksViewportHeight
    2789      */
    2790     @BeanProperty(bound = false)
    2791     public boolean getScrollableTracksViewportHeight() {
    2792         if (getLayoutOrientation() == VERTICAL_WRAP &&
    2793                      getVisibleRowCount() <= 0) {
    2794             return true;
    2795         }
    2796         Container parent = SwingUtilities.getUnwrappedParent(this);
    2797         if (parent instanceof JViewport) {
    2798             return parent.getHeight() > getPreferredSize().height;
    2799         }
    2800         return false;
    2801     }
    2802
    2803
    2804     /*
    2805      * See {@code readObject} and {@code writeObject} in {@code JComponent}
    2806      * for more information about serialization in Swing.
    2807      */
    2808     private void writeObject(ObjectOutputStream s) throws IOException {
    2809         s.defaultWriteObject();
    2810         if (getUIClassID().equals(uiClassID)) {
    2811             byte count = JComponent.getWriteObjCounter(this);
    2812             JComponent.setWriteObjCounter(this, --count);
    2813             if (count == 0 && ui != null) {
    2814                 ui.installUI(this);
    2815             }
    2816         }
    2817     }
    2818
    2819
    2820     /**
    2821      * Returns a {@code String} representation of this {@code JList}.
    2822      * This method is intended to be used only for debugging purposes,
    2823      * and the content and format of the returned {@code String} may vary
    2824      * between implementations. The returned {@code String} may be empty,
    2825      * but may not be {@code null}.
    2826      *
    2827      * @return  a {@code String} representation of this {@code JList}.
    2828      */
    2829     protected String paramString() {
    2830         String selectionForegroundString = (selectionForeground != null ?
    2831                                             selectionForeground.toString() :
    2832                                             "");
    2833         String selectionBackgroundString = (selectionBackground != null ?
    2834                                             selectionBackground.toString() :
    2835                                             "");
    2836
    2837         return super.paramString() +
    2838         ",fixedCellHeight=" + fixedCellHeight +
    2839         ",fixedCellWidth=" + fixedCellWidth +
    2840         ",horizontalScrollIncrement=" + horizontalScrollIncrement +
    2841         ",selectionBackground=" + selectionBackgroundString +
    2842         ",selectionForeground=" + selectionForegroundString +
    2843         ",visibleRowCount=" + visibleRowCount +
    2844         ",layoutOrientation=" + layoutOrientation;
    2845     }
    2846
    2847
    2848     /**
    2849      * --- Accessibility Support ---
    2850      */
    2851
    2852     /**
    2853      * Gets the {@code AccessibleContext} associated with this {@code JList}.
    2854      * For {@code JList}, the {@code AccessibleContext} takes the form of an
    2855      * {@code AccessibleJList}.
    2856      * <p>
    2857      * A new {@code AccessibleJList} instance is created if necessary.
    2858      *
    2859      * @return an {@code AccessibleJList} that serves as the
    2860      *         {@code AccessibleContext} of this {@code JList}
    2861      */
    2862     @BeanProperty(bound = false)
    2863     public AccessibleContext getAccessibleContext() {
    2864         if (accessibleContext == null) {
    2865             accessibleContext = new AccessibleJList();
    2866         }
    2867         return accessibleContext;
    2868     }
    2869
    2870     /**
    2871      * This class implements accessibility support for the
    2872      * {@code JList} class. It provides an implementation of the
    2873      * Java Accessibility API appropriate to list user-interface
    2874      * elements.
    2875      * <p>
    2876      * <strong>Warning:</strong>
    2877      * Serialized objects of this class will not be compatible with
    2878      * future Swing releases. The current serialization support is
    2879      * appropriate for short term storage or RMI between applications running
    2880      * the same version of Swing.  As of 1.4, support for long term storage
    2881      * of all JavaBeans&trade;
    2882      * has been added to the <code>java.beans</code> package.
    2883      * Please see {@link java.beans.XMLEncoder}.
    2884      */
    2885     @SuppressWarnings("serial") // Same-version serialization only
    2886     protected class AccessibleJList extends AccessibleJComponent
    2887         implements AccessibleSelection, PropertyChangeListener,
    2888         ListSelectionListener, ListDataListener {
    2889
    2890         int leadSelectionIndex;
    2891
    2892         /**
    2893          * Constructs an {@code AccessibleJList}.
    2894          */
    2895         public AccessibleJList() {
    2896             super();
    2897             JList.this.addPropertyChangeListener(this);
    2898             JList.this.getSelectionModel().addListSelectionListener(this);
    2899             JList.this.getModel().addListDataListener(this);
    2900             leadSelectionIndex = JList.this.getLeadSelectionIndex();
    2901         }
    2902
    2903         /**
    2904          * Property Change Listener change method. Used to track changes
    2905          * to the DataModel and ListSelectionModel, in order to re-set
    2906          * listeners to those for reporting changes there via the Accessibility
    2907          * PropertyChange mechanism.
    2908          *
    2909          * @param e PropertyChangeEvent
    2910          */
    2911         public void propertyChange(PropertyChangeEvent e) {
    2912             String name = e.getPropertyName();
    2913             Object oldValue = e.getOldValue();
    2914             Object newValue = e.getNewValue();
    2915
    2916                 // re-set listData listeners
    2917             if (name.compareTo("model") == 0) {
    2918
    2919                 if (oldValue != null && oldValue instanceof ListModel) {
    2920                     ((ListModel) oldValue).removeListDataListener(this);
    2921                 }
    2922                 if (newValue != null && newValue instanceof ListModel) {
    2923                     ((ListModel) newValue).addListDataListener(this);
    2924                 }
    2925
    2926                 // re-set listSelectionModel listeners
    2927             } else if (name.compareTo("selectionModel") == 0) {
    2928
    2929                 if (oldValue != null && oldValue instanceof ListSelectionModel) {
    2930                     ((ListSelectionModel) oldValue).removeListSelectionListener(this);
    2931                 }
    2932                 if (newValue != null && newValue instanceof ListSelectionModel) {
    2933                     ((ListSelectionModel) newValue).addListSelectionListener(this);
    2934                 }
    2935
    2936                 firePropertyChange(
    2937                     AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY,
    2938                     Boolean.valueOf(false), Boolean.valueOf(true));
    2939             }
    2940         }
    2941
    2942         /**
    2943          * List Selection Listener value change method. Used to fire
    2944          * the property change
    2945          *
    2946          * @param e ListSelectionEvent
    2947          *
    2948          */
    2949         public void valueChanged(ListSelectionEvent e) {
    2950             int oldLeadSelectionIndex = leadSelectionIndex;
    2951             leadSelectionIndex = JList.this.getLeadSelectionIndex();
    2952             if (oldLeadSelectionIndex != leadSelectionIndex) {
    2953                 Accessible oldLS, newLS;
    2954                 oldLS = (oldLeadSelectionIndex >= 0)
    2955                         ? getAccessibleChild(oldLeadSelectionIndex)
    2956                         : null;
    2957                 newLS = (leadSelectionIndex >= 0)
    2958                         ? getAccessibleChild(leadSelectionIndex)
    2959                         : null;
    2960                 firePropertyChange(AccessibleContext.ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY,
    2961                                    oldLS, newLS);
    2962             }
    2963
    2964             firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
    2965                                Boolean.valueOf(false), Boolean.valueOf(true));
    2966             firePropertyChange(AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY,
    2967                                Boolean.valueOf(false), Boolean.valueOf(true));
    2968
    2969             // Process the State changes for Multiselectable
    2970             AccessibleStateSet s = getAccessibleStateSet();
    2971             ListSelectionModel lsm = JList.this.getSelectionModel();
    2972             if (lsm.getSelectionMode() != ListSelectionModel.SINGLE_SELECTION) {
    2973                 if (!s.contains(AccessibleState.MULTISELECTABLE)) {
    2974                     s.add(AccessibleState.MULTISELECTABLE);
    2975                     firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
    2976                                        null, AccessibleState.MULTISELECTABLE);
    2977                 }
    2978             } else {
    2979                 if (s.contains(AccessibleState.MULTISELECTABLE)) {
    2980                     s.remove(AccessibleState.MULTISELECTABLE);
    2981                     firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
    2982                                        AccessibleState.MULTISELECTABLE, null);
    2983                 }
    2984             }
    2985         }
    2986
    2987         /**
    2988          * List Data Listener interval added method. Used to fire the visible data property change
    2989          *
    2990          * @param e ListDataEvent
    2991          *
    2992          */
    2993         public void intervalAdded(ListDataEvent e) {
    2994             firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
    2995                                Boolean.valueOf(false), Boolean.valueOf(true));
    2996         }
    2997
    2998         /**
    2999          * List Data Listener interval removed method. Used to fire the visible data property change
    3000          *
    3001          * @param e ListDataEvent
    3002          *
    3003          */
    3004         public void intervalRemoved(ListDataEvent e) {
    3005             firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
    3006                                Boolean.valueOf(false), Boolean.valueOf(true));
    3007         }
    3008
    3009         /**
    3010          * List Data Listener contents changed method. Used to fire the visible data property change
    3011          *
    3012          * @param e ListDataEvent
    3013          *
    3014          */
    3015          public void contentsChanged(ListDataEvent e) {
    3016              firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
    3017                                 Boolean.valueOf(false), Boolean.valueOf(true));
    3018          }
    3019
    3020     // AccessibleContext methods
    3021
    3022         /**
    3023          * Get the state set of this object.
    3024          *
    3025          * @return an instance of AccessibleState containing the current state
    3026          * of the object
    3027          * @see AccessibleState
    3028          */
    3029         public AccessibleStateSet getAccessibleStateSet() {
    3030             AccessibleStateSet states = super.getAccessibleStateSet();
    3031             if (selectionModel.getSelectionMode() !=
    3032                 ListSelectionModel.SINGLE_SELECTION) {
    3033                 states.add(AccessibleState.MULTISELECTABLE);
    3034             }
    3035             return states;
    3036         }
    3037
    3038         /**
    3039          * Get the role of this object.
    3040          *
    3041          * @return an instance of AccessibleRole describing the role of the
    3042          * object
    3043          * @see AccessibleRole
    3044          */
    3045         public AccessibleRole getAccessibleRole() {
    3046             return AccessibleRole.LIST;
    3047         }
    3048
    3049         /**
    3050          * Returns the <code>Accessible</code> child contained at
    3051          * the local coordinate <code>Point</code>, if one exists.
    3052          * Otherwise returns <code>null</code>.
    3053          *
    3054          * @return the <code>Accessible</code> at the specified
    3055          *    location, if it exists
    3056          */
    3057         public Accessible getAccessibleAt(Point p) {
    3058             int i = locationToIndex(p);
    3059             if (i >= 0) {
    3060                 return new AccessibleJListChild(JList.this, i);
    3061             } else {
    3062                 return null;
    3063             }
    3064         }
    3065
    3066         /**
    3067          * Returns the number of accessible children in the object.  If all
    3068          * of the children of this object implement Accessible, than this
    3069          * method should return the number of children of this object.
    3070          *
    3071          * @return the number of accessible children in the object.
    3072          */
    3073         public int getAccessibleChildrenCount() {
    3074             return getModel().getSize();
    3075         }
    3076
    3077         /**
    3078          * Return the nth Accessible child of the object.
    3079          *
    3080          * @param i zero-based index of child
    3081          * @return the nth Accessible child of the object
    3082          */
    3083         public Accessible getAccessibleChild(int i) {
    3084             if (i >= getModel().getSize()) {
    3085                 return null;
    3086             } else {
    3087                 return new AccessibleJListChild(JList.this, i);
    3088             }
    3089         }
    3090
    3091         /**
    3092          * Get the AccessibleSelection associated with this object.  In the
    3093          * implementation of the Java Accessibility API for this class,
    3094          * return this object, which is responsible for implementing the
    3095          * AccessibleSelection interface on behalf of itself.
    3096          *
    3097          * @return this object
    3098          */
    3099         public AccessibleSelection getAccessibleSelection() {
    3100             return this;
    3101         }
    3102
    3103
    3104     // AccessibleSelection methods
    3105
    3106         /**
    3107          * Returns the number of items currently selected.
    3108          * If no items are selected, the return value will be 0.
    3109          *
    3110          * @return the number of items currently selected.
    3111          */
    3112          public int getAccessibleSelectionCount() {
    3113              return JList.this.getSelectedIndices().length;
    3114          }
    3115
    3116         /**
    3117          * Returns an Accessible representing the specified selected item
    3118          * in the object.  If there isn't a selection, or there are
    3119          * fewer items selected than the integer passed in, the return
    3120          * value will be <code>null</code>.
    3121          *
    3122          * @param i the zero-based index of selected items
    3123          * @return an Accessible containing the selected item
    3124          */
    3125          public Accessible getAccessibleSelection(int i) {
    3126              int len = getAccessibleSelectionCount();
    3127              if (i < 0 || i >= len) {
    3128                  return null;
    3129              } else {
    3130                  return getAccessibleChild(JList.this.getSelectedIndices()[i]);
    3131              }
    3132          }
    3133
    3134         /**
    3135          * Returns true if the current child of this object is selected.
    3136          *
    3137          * @param i the zero-based index of the child in this Accessible
    3138          * object.
    3139          * @see AccessibleContext#getAccessibleChild
    3140          */
    3141         public boolean isAccessibleChildSelected(int i) {
    3142             return isSelectedIndex(i);
    3143         }
    3144
    3145         /**
    3146          * Adds the specified selected item in the object to the object's
    3147          * selection.  If the object supports multiple selections,
    3148          * the specified item is added to any existing selection, otherwise
    3149          * it replaces any existing selection in the object.  If the
    3150          * specified item is already selected, this method has no effect.
    3151          *
    3152          * @param i the zero-based index of selectable items
    3153          */
    3154          public void addAccessibleSelection(int i) {
    3155              JList.this.addSelectionInterval(i, i);
    3156          }
    3157
    3158         /**
    3159          * Removes the specified selected item in the object from the object's
    3160          * selection.  If the specified item isn't currently selected, this
    3161          * method has no effect.
    3162          *
    3163          * @param i the zero-based index of selectable items
    3164          */
    3165          public void removeAccessibleSelection(int i) {
    3166              JList.this.removeSelectionInterval(i, i);
    3167          }
    3168
    3169         /**
    3170          * Clears the selection in the object, so that nothing in the
    3171          * object is selected.
    3172          */
    3173          public void clearAccessibleSelection() {
    3174              JList.this.clearSelection();
    3175          }
    3176
    3177         /**
    3178          * Causes every selected item in the object to be selected
    3179          * if the object supports multiple selections.
    3180          */
    3181          public void selectAllAccessibleSelection() {
    3182              JList.this.addSelectionInterval(0, getAccessibleChildrenCount() -1);
    3183          }
    3184
    3185           /**
    3186            * This class implements accessibility support appropriate
    3187            * for list children.
    3188            */
    3189         protected class AccessibleJListChild extends AccessibleContext
    3190                 implements Accessible, AccessibleComponent, AccessibleAction {
    3191             private JList<E>     parent = null;
    3192             int indexInParent;
    3193             private Component component = null;
    3194             private AccessibleContext accessibleContext = null;
    3195             private ListModel<E> listModel;
    3196             private ListCellRenderer<? super E> cellRenderer = null;
    3197
    3198             /**
    3199              * Constructs an {@code AccessibleJListChild}.
    3200              * @param parent the parent
    3201              * @param indexInParent the index in the parent
    3202              */
    3203             public AccessibleJListChild(JList<E> parent, int indexInParent) {
    3204                 this.parent = parent;
    3205                 this.setAccessibleParent(parent);
    3206                 this.indexInParent = indexInParent;
    3207                 if (parent != null) {
    3208                     listModel = parent.getModel();
    3209                     cellRenderer = parent.getCellRenderer();
    3210                 }
    3211             }
    3212
    3213             private Component getCurrentComponent() {
    3214                 return getComponentAtIndex(indexInParent);
    3215             }
    3216
    3217             AccessibleContext getCurrentAccessibleContext() {
    3218                 Component c = getComponentAtIndex(indexInParent);
    3219                 if (c instanceof Accessible) {
    3220                     return c.getAccessibleContext();
    3221                 } else {
    3222                     return null;
    3223                 }
    3224             }
    3225
    3226             private Component getComponentAtIndex(int index) {
    3227                 if (index < 0 || index >= listModel.getSize()) {
    3228                     return null;
    3229                 }
    3230                 if ((parent != null)
    3231                         && (listModel != null)
    3232                         && cellRenderer != null) {
    3233                     E value = listModel.getElementAt(index);
    3234                     boolean isSelected = parent.isSelectedIndex(index);
    3235                     boolean isFocussed = parent.isFocusOwner()
    3236                             && (index == parent.getLeadSelectionIndex());
    3237                     return cellRenderer.getListCellRendererComponent(
    3238                             parent,
    3239                             value,
    3240                             index,
    3241                             isSelected,
    3242                             isFocussed);
    3243                 } else {
    3244                     return null;
    3245                 }
    3246             }
    3247
    3248
    3249             // Accessible Methods
    3250            /**
    3251             * Get the AccessibleContext for this object. In the
    3252             * implementation of the Java Accessibility API for this class,
    3253             * returns this object, which is its own AccessibleContext.
    3254             *
    3255             * @return this object
    3256             */
    3257             public AccessibleContext getAccessibleContext() {
    3258                 return this;
    3259             }
    3260
    3261
    3262             // AccessibleContext methods
    3263
    3264             public String getAccessibleName() {
    3265                 AccessibleContext ac = getCurrentAccessibleContext();
    3266                 if (ac != null) {
    3267                     return ac.getAccessibleName();
    3268                 } else {
    3269                     return null;
    3270                 }
    3271             }
    3272
    3273             public void setAccessibleName(String s) {
    3274                 AccessibleContext ac = getCurrentAccessibleContext();
    3275                 if (ac != null) {
    3276                     ac.setAccessibleName(s);
    3277                 }
    3278             }
    3279
    3280             public String getAccessibleDescription() {
    3281                 AccessibleContext ac = getCurrentAccessibleContext();
    3282                 if (ac != null) {
    3283                     return ac.getAccessibleDescription();
    3284                 } else {
    3285                     return null;
    3286                 }
    3287             }
    3288
    3289             public void setAccessibleDescription(String s) {
    3290                 AccessibleContext ac = getCurrentAccessibleContext();
    3291                 if (ac != null) {
    3292                     ac.setAccessibleDescription(s);
    3293                 }
    3294             }
    3295
    3296             public AccessibleRole getAccessibleRole() {
    3297                 AccessibleContext ac = getCurrentAccessibleContext();
    3298                 if (ac != null) {
    3299                     return ac.getAccessibleRole();
    3300                 } else {
    3301                     return null;
    3302                 }
    3303             }
    3304
    3305             public AccessibleStateSet getAccessibleStateSet() {
    3306                 AccessibleContext ac = getCurrentAccessibleContext();
    3307                 AccessibleStateSet s;
    3308                 if (ac != null) {
    3309                     s = ac.getAccessibleStateSet();
    3310                 } else {
    3311                     s = new AccessibleStateSet();
    3312                 }
    3313
    3314                 s.add(AccessibleState.SELECTABLE);
    3315                 if (parent.isFocusOwner()
    3316                     && (indexInParent == parent.getLeadSelectionIndex())) {
    3317                     s.add(AccessibleState.ACTIVE);
    3318                 }
    3319                 if (parent.isSelectedIndex(indexInParent)) {
    3320                     s.add(AccessibleState.SELECTED);
    3321                 }
    3322                 if (this.isShowing()) {
    3323                     s.add(AccessibleState.SHOWING);
    3324                 } else if (s.contains(AccessibleState.SHOWING)) {
    3325                     s.remove(AccessibleState.SHOWING);
    3326                 }
    3327                 if (this.isVisible()) {
    3328                     s.add(AccessibleState.VISIBLE);
    3329                 } else if (s.contains(AccessibleState.VISIBLE)) {
    3330                     s.remove(AccessibleState.VISIBLE);
    3331                 }
    3332                 s.add(AccessibleState.TRANSIENT); // cell-rendered
    3333                 return s;
    3334             }
    3335
    3336             public int getAccessibleIndexInParent() {
    3337                 return indexInParent;
    3338             }
    3339
    3340             public int getAccessibleChildrenCount() {
    3341                 AccessibleContext ac = getCurrentAccessibleContext();
    3342                 if (ac != null) {
    3343                     return ac.getAccessibleChildrenCount();
    3344                 } else {
    3345                     return 0;
    3346                 }
    3347             }
    3348
    3349             public Accessible getAccessibleChild(int i) {
    3350                 AccessibleContext ac = getCurrentAccessibleContext();
    3351                 if (ac != null) {
    3352                     Accessible accessibleChild = ac.getAccessibleChild(i);
    3353                     ac.setAccessibleParent(this);
    3354                     return accessibleChild;
    3355                 } else {
    3356                     return null;
    3357                 }
    3358             }
    3359
    3360             public Locale getLocale() {
    3361                 AccessibleContext ac = getCurrentAccessibleContext();
    3362                 if (ac != null) {
    3363                     return ac.getLocale();
    3364                 } else {
    3365                     return null;
    3366                 }
    3367             }
    3368
    3369             public void addPropertyChangeListener(PropertyChangeListener l) {
    3370                 AccessibleContext ac = getCurrentAccessibleContext();
    3371                 if (ac != null) {
    3372                     ac.addPropertyChangeListener(l);
    3373                 }
    3374             }
    3375
    3376             public void removePropertyChangeListener(PropertyChangeListener l) {
    3377                 AccessibleContext ac = getCurrentAccessibleContext();
    3378                 if (ac != null) {
    3379                     ac.removePropertyChangeListener(l);
    3380                 }
    3381             }
    3382
    3383            /**
    3384             * Get the AccessibleComponent associated with this object.  In the
    3385             * implementation of the Java Accessibility API for this class,
    3386             * return this object, which is responsible for implementing the
    3387             * AccessibleComponent interface on behalf of itself.
    3388             *
    3389             * @return this object
    3390             */
    3391             public AccessibleComponent getAccessibleComponent() {
    3392                 return this; // to override getBounds()
    3393             }
    3394
    3395             public AccessibleSelection getAccessibleSelection() {
    3396                 AccessibleContext ac = getCurrentAccessibleContext();
    3397                 return ac != null ? ac.getAccessibleSelection() : null;
    3398             }
    3399
    3400             public AccessibleText getAccessibleText() {
    3401                 AccessibleContext ac = getCurrentAccessibleContext();
    3402                 return ac != null ? ac.getAccessibleText() : null;
    3403             }
    3404
    3405             public AccessibleValue getAccessibleValue() {
    3406                 AccessibleContext ac = getCurrentAccessibleContext();
    3407                 return ac != null ? ac.getAccessibleValue() : null;
    3408             }
    3409
    3410
    3411             // AccessibleComponent methods
    3412
    3413             public Color getBackground() {
    3414                 AccessibleContext ac = getCurrentAccessibleContext();
    3415                 if (ac instanceof AccessibleComponent) {
    3416                     return ((AccessibleComponent) ac).getBackground();
    3417                 } else {
    3418                     Component c = getCurrentComponent();
    3419                     if (c != null) {
    3420                         return c.getBackground();
    3421                     } else {
    3422                         return null;
    3423                     }
    3424                 }
    3425             }
    3426
    3427             public void setBackground(Color c) {
    3428                 AccessibleContext ac = getCurrentAccessibleContext();
    3429                 if (ac instanceof AccessibleComponent) {
    3430                     ((AccessibleComponent) ac).setBackground(c);
    3431                 } else {
    3432                     Component cp = getCurrentComponent();
    3433                     if (cp != null) {
    3434                         cp.setBackground(c);
    3435                     }
    3436                 }
    3437             }
    3438
    3439             public Color getForeground() {
    3440                 AccessibleContext ac = getCurrentAccessibleContext();
    3441                 if (ac instanceof AccessibleComponent) {
    3442                     return ((AccessibleComponent) ac).getForeground();
    3443                 } else {
    3444                     Component c = getCurrentComponent();
    3445                     if (c != null) {
    3446                         return c.getForeground();
    3447                     } else {
    3448                         return null;
    3449                     }
    3450                 }
    3451             }
    3452
    3453             public void setForeground(Color c) {
    3454                 AccessibleContext ac = getCurrentAccessibleContext();
    3455                 if (ac instanceof AccessibleComponent) {
    3456                     ((AccessibleComponent) ac).setForeground(c);
    3457                 } else {
    3458                     Component cp = getCurrentComponent();
    3459                     if (cp != null) {
    3460                         cp.setForeground(c);
    3461                     }
    3462                 }
    3463             }
    3464
    3465             public Cursor getCursor() {
    3466                 AccessibleContext ac = getCurrentAccessibleContext();
    3467                 if (ac instanceof AccessibleComponent) {
    3468                     return ((AccessibleComponent) ac).getCursor();
    3469                 } else {
    3470                     Component c = getCurrentComponent();
    3471                     if (c != null) {
    3472                         return c.getCursor();
    3473                     } else {
    3474                         Accessible ap = getAccessibleParent();
    3475                         if (ap instanceof AccessibleComponent) {
    3476                             return ((AccessibleComponent) ap).getCursor();
    3477                         } else {
    3478                             return null;
    3479                         }
    3480                     }
    3481                 }
    3482             }
    3483
    3484             public void setCursor(Cursor c) {
    3485                 AccessibleContext ac = getCurrentAccessibleContext();
    3486                 if (ac instanceof AccessibleComponent) {
    3487                     ((AccessibleComponent) ac).setCursor(c);
    3488                 } else {
    3489                     Component cp = getCurrentComponent();
    3490                     if (cp != null) {
    3491                         cp.setCursor(c);
    3492                     }
    3493                 }
    3494             }
    3495
    3496             public Font getFont() {
    3497                 AccessibleContext ac = getCurrentAccessibleContext();
    3498                 if (ac instanceof AccessibleComponent) {
    3499                     return ((AccessibleComponent) ac).getFont();
    3500                 } else {
    3501                     Component c = getCurrentComponent();
    3502                     if (c != null) {
    3503                         return c.getFont();
    3504                     } else {
    3505                         return null;
    3506                     }
    3507                 }
    3508             }
    3509
    3510             public void setFont(Font f) {
    3511                 AccessibleContext ac = getCurrentAccessibleContext();
    3512                 if (ac instanceof AccessibleComponent) {
    3513                     ((AccessibleComponent) ac).setFont(f);
    3514                 } else {
    3515                     Component c = getCurrentComponent();
    3516                     if (c != null) {
    3517                         c.setFont(f);
    3518                     }
    3519                 }
    3520             }
    3521
    3522             public FontMetrics getFontMetrics(Font f) {
    3523                 AccessibleContext ac = getCurrentAccessibleContext();
    3524                 if (ac instanceof AccessibleComponent) {
    3525                     return ((AccessibleComponent) ac).getFontMetrics(f);
    3526                 } else {
    3527                     Component c = getCurrentComponent();
    3528                     if (c != null) {
    3529                         return c.getFontMetrics(f);
    3530                     } else {
    3531                         return null;
    3532                     }
    3533                 }
    3534             }
    3535
    3536             public boolean isEnabled() {
    3537                 AccessibleContext ac = getCurrentAccessibleContext();
    3538                 if (ac instanceof AccessibleComponent) {
    3539                     return ((AccessibleComponent) ac).isEnabled();
    3540                 } else {
    3541                     Component c = getCurrentComponent();
    3542                     if (c != null) {
    3543                         return c.isEnabled();
    3544                     } else {
    3545                         return false;
    3546                     }
    3547                 }
    3548             }
    3549
    3550             public void setEnabled(boolean b) {
    3551                 AccessibleContext ac = getCurrentAccessibleContext();
    3552                 if (ac instanceof AccessibleComponent) {
    3553                     ((AccessibleComponent) ac).setEnabled(b);
    3554                 } else {
    3555                     Component c = getCurrentComponent();
    3556                     if (c != null) {
    3557                         c.setEnabled(b);
    3558                     }
    3559                 }
    3560             }
    3561
    3562             public boolean isVisible() {
    3563                 int fi = parent.getFirstVisibleIndex();
    3564                 int li = parent.getLastVisibleIndex();
    3565                 // The UI incorrectly returns a -1 for the last
    3566                 // visible index if the list is smaller than the
    3567                 // viewport size.
    3568                 if (li == -1) {
    3569                     li = parent.getModel().getSize() - 1;
    3570                 }
    3571                 return ((indexInParent >= fi)
    3572                         && (indexInParent <= li));
    3573             }
    3574
    3575             public void setVisible(boolean b) {
    3576             }
    3577
    3578             public boolean isShowing() {
    3579                 return (parent.isShowing() && isVisible());
    3580             }
    3581
    3582             public boolean contains(Point p) {
    3583                 AccessibleContext ac = getCurrentAccessibleContext();
    3584                 if (ac instanceof AccessibleComponent) {
    3585                     Rectangle r = ((AccessibleComponent) ac).getBounds();
    3586                     return r.contains(p);
    3587                 } else {
    3588                     Component c = getCurrentComponent();
    3589                     if (c != null) {
    3590                         Rectangle r = c.getBounds();
    3591                         return r.contains(p);
    3592                     } else {
    3593                         return getBounds().contains(p);
    3594                     }
    3595                 }
    3596             }
    3597
    3598             public Point getLocationOnScreen() {
    3599                 if (parent != null) {
    3600                     Point listLocation;
    3601                     try {
    3602                         listLocation = parent.getLocationOnScreen();
    3603                     } catch (IllegalComponentStateException e) {
    3604                         // This can happen if the component isn't visisble
    3605                         return null;
    3606                     }
    3607                     Point componentLocation = parent.indexToLocation(indexInParent);
    3608                     if (componentLocation != null) {
    3609                         componentLocation.translate(listLocation.x, listLocation.y);
    3610                         return componentLocation;
    3611                     } else {
    3612                         return null;
    3613                     }
    3614                 } else {
    3615                     return null;
    3616                 }
    3617             }
    3618
    3619             public Point getLocation() {
    3620                 if (parent != null) {
    3621                     return parent.indexToLocation(indexInParent);
    3622                 } else {
    3623                     return null;
    3624                 }
    3625             }
    3626
    3627             public void setLocation(Point p) {
    3628                 if ((parent != null)  && (parent.contains(p))) {
    3629                     ensureIndexIsVisible(indexInParent);
    3630                 }
    3631             }
    3632
    3633             public Rectangle getBounds() {
    3634                 if (parent != null) {
    3635                     return parent.getCellBounds(indexInParent,indexInParent);
    3636                 } else {
    3637                     return null;
    3638                 }
    3639             }
    3640
    3641             public void setBounds(Rectangle r) {
    3642                 AccessibleContext ac = getCurrentAccessibleContext();
    3643                 if (ac instanceof AccessibleComponent) {
    3644                     ((AccessibleComponent) ac).setBounds(r);
    3645                 }
    3646             }
    3647
    3648             public Dimension getSize() {
    3649                 Rectangle cellBounds = this.getBounds();
    3650                 if (cellBounds != null) {
    3651                     return cellBounds.getSize();
    3652                 } else {
    3653                     return null;
    3654                 }
    3655             }
    3656
    3657             public void setSize (Dimension d) {
    3658                 AccessibleContext ac = getCurrentAccessibleContext();
    3659                 if (ac instanceof AccessibleComponent) {
    3660                     ((AccessibleComponent) ac).setSize(d);
    3661                 } else {
    3662                     Component c = getCurrentComponent();
    3663                     if (c != null) {
    3664                         c.setSize(d);
    3665                     }
    3666                 }
    3667             }
    3668
    3669             public Accessible getAccessibleAt(Point p) {
    3670                 AccessibleContext ac = getCurrentAccessibleContext();
    3671                 if (ac instanceof AccessibleComponent) {
    3672                     return ((AccessibleComponent) ac).getAccessibleAt(p);
    3673                 } else {
    3674                     return null;
    3675                 }
    3676             }
    3677
    3678             @SuppressWarnings("deprecation")
    3679             public boolean isFocusTraversable() {
    3680                 AccessibleContext ac = getCurrentAccessibleContext();
    3681                 if (ac instanceof AccessibleComponent) {
    3682                     return ((AccessibleComponent) ac).isFocusTraversable();
    3683                 } else {
    3684                     Component c = getCurrentComponent();
    3685                     if (c != null) {
    3686                         return c.isFocusTraversable();
    3687                     } else {
    3688                         return false;
    3689                     }
    3690                 }
    3691             }
    3692
    3693             public void requestFocus() {
    3694                 AccessibleContext ac = getCurrentAccessibleContext();
    3695                 if (ac instanceof AccessibleComponent) {
    3696                     ((AccessibleComponent) ac).requestFocus();
    3697                 } else {
    3698                     Component c = getCurrentComponent();
    3699                     if (c != null) {
    3700                         c.requestFocus();
    3701                     }
    3702                 }
    3703             }
    3704
    3705             public void addFocusListener(FocusListener l) {
    3706                 AccessibleContext ac = getCurrentAccessibleContext();
    3707                 if (ac instanceof AccessibleComponent) {
    3708                     ((AccessibleComponent) ac).addFocusListener(l);
    3709                 } else {
    3710                     Component c = getCurrentComponent();
    3711                     if (c != null) {
    3712                         c.addFocusListener(l);
    3713                     }
    3714                 }
    3715             }
    3716
    3717             public void removeFocusListener(FocusListener l) {
    3718                 AccessibleContext ac = getCurrentAccessibleContext();
    3719                 if (ac instanceof AccessibleComponent) {
    3720                     ((AccessibleComponent) ac).removeFocusListener(l);
    3721                 } else {
    3722                     Component c = getCurrentComponent();
    3723                     if (c != null) {
    3724                         c.removeFocusListener(l);
    3725                     }
    3726                 }
    3727             }
    3728
    3729             // TIGER - 4733624
    3730             /**
    3731              * Returns the icon for the element renderer, as the only item
    3732              * of an array of <code>AccessibleIcon</code>s or a <code>null</code> array
    3733              * if the renderer component contains no icons.
    3734              *
    3735              * @return an array containing the accessible icon
    3736              *         or a <code>null</code> array if none
    3737              * @since 1.3
    3738              */
    3739             public AccessibleIcon [] getAccessibleIcon() {
    3740                 AccessibleContext ac = getCurrentAccessibleContext();
    3741                 if (ac != null) {
    3742                     return ac.getAccessibleIcon();
    3743                 } else {
    3744                     return null;
    3745                 }
    3746             }
    3747
    3748             /**
    3749              * {@inheritDoc}
    3750              * @implSpec Returns the AccessibleAction for this AccessibleJListChild
    3751              * as follows:  First getListCellRendererComponent of the ListCellRenderer
    3752              * for the component at the "index in parent" of this child is called.
    3753              * Then its AccessibleContext is fetched and that AccessibleContext's
    3754              * AccessibleAction is returned.  Note that if an AccessibleAction
    3755              * is not found using this process then this object with its implementation
    3756              * of the AccessibleAction interface is returned.
    3757              * @since 9
    3758              */
    3759             @Override
    3760             public AccessibleAction getAccessibleAction() {
    3761                 AccessibleContext ac = getCurrentAccessibleContext();
    3762                 if (ac == null) {
    3763                     return null;
    3764                 } else {
    3765                     AccessibleAction aa = ac.getAccessibleAction();
    3766                     if (aa != null) {
    3767                         return aa;
    3768                     } else {
    3769                         return this;
    3770                     }
    3771                 }
    3772             }
    3773
    3774             /**
    3775              * {@inheritDoc}
    3776              * @implSpec If i == 0 selects this AccessibleJListChild by calling
    3777              * JList.this.setSelectedIndex(indexInParent) and then returns true;
    3778              * otherwise returns false.
    3779              * @since 9
    3780              */
    3781             @Override
    3782             public boolean doAccessibleAction(int i) {
    3783                 if (i == 0) {
    3784                     JList.this.setSelectedIndex(indexInParent);
    3785                     return true;
    3786                 } else {
    3787                     return false;
    3788                 }
    3789             }
    3790
    3791             /**
    3792              * {@inheritDoc}
    3793              * @implSpec If i == 0 returns the action description fetched from
    3794              * UIManager.getString("AbstractButton.clickText");
    3795              * otherwise returns null.
    3796              * @since 9
    3797              */
    3798             @Override
    3799             public String getAccessibleActionDescription(int i) {
    3800                 if (i == 0) {
    3801                     return UIManager.getString("AbstractButton.clickText");
    3802                 } else {
    3803                     return null;
    3804                 }
    3805             }
    3806
    3807             /**
    3808              * {@inheritDoc}
    3809              * @implSpec Returns 1, i.e. there is only one action.
    3810              * @since 9
    3811              */
    3812             @Override
    3813             public int getAccessibleActionCount() {
    3814                 return 1;
    3815             }
    3816
    3817         } // inner class AccessibleJListChild
    3818
    3819     } // inner class AccessibleJList
    3820 }
    --- EOF ---