6823603: Generics: JList

Reviewed-by: peterz, alexp
This commit is contained in:
Florian Brunner 2009-11-23 20:57:17 +03:00 committed by Pavel Porvatov
parent 92cb82eecb
commit 5db737cd4c
7 changed files with 409 additions and 94 deletions

View File

@ -42,9 +42,11 @@ import java.util.EventListener;
* has been added to the <code>java.beans</code> package. * has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}. * Please see {@link java.beans.XMLEncoder}.
* *
* @param <E> the type of the elements of this model
*
* @author Hans Muller * @author Hans Muller
*/ */
public abstract class AbstractListModel implements ListModel, Serializable public abstract class AbstractListModel<E> implements ListModel<E>, Serializable
{ {
protected EventListenerList listenerList = new EventListenerList(); protected EventListenerList listenerList = new EventListenerList();

View File

@ -71,7 +71,7 @@ import sun.swing.DefaultLookup;
* @author Hans Muller * @author Hans Muller
*/ */
public class DefaultListCellRenderer extends JLabel public class DefaultListCellRenderer extends JLabel
implements ListCellRenderer, Serializable implements ListCellRenderer<Object>, Serializable
{ {
/** /**
@ -111,7 +111,7 @@ public class DefaultListCellRenderer extends JLabel
} }
public Component getListCellRendererComponent( public Component getListCellRendererComponent(
JList list, JList<?> list,
Object value, Object value,
int index, int index,
boolean isSelected, boolean isSelected,

View File

@ -48,11 +48,13 @@ import javax.swing.event.*;
* has been added to the <code>java.beans</code> package. * has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}. * Please see {@link java.beans.XMLEncoder}.
* *
* @param <E> the type of the elements of this model
*
* @author Hans Muller * @author Hans Muller
*/ */
public class DefaultListModel extends AbstractListModel public class DefaultListModel<E> extends AbstractListModel<E>
{ {
private Vector delegate = new Vector(); private Vector<E> delegate = new Vector<E>();
/** /**
* Returns the number of components in this list. * Returns the number of components in this list.
@ -83,7 +85,7 @@ public class DefaultListModel extends AbstractListModel
* list * list
* @see #get(int) * @see #get(int)
*/ */
public Object getElementAt(int index) { public E getElementAt(int index) {
return delegate.elementAt(index); return delegate.elementAt(index);
} }
@ -175,7 +177,7 @@ public class DefaultListModel extends AbstractListModel
* @return an enumeration of the components of this list * @return an enumeration of the components of this list
* @see Vector#elements() * @see Vector#elements()
*/ */
public Enumeration<?> elements() { public Enumeration<E> elements() {
return delegate.elements(); return delegate.elements();
} }
@ -260,7 +262,7 @@ public class DefaultListModel extends AbstractListModel
* @see #get(int) * @see #get(int)
* @see Vector#elementAt(int) * @see Vector#elementAt(int)
*/ */
public Object elementAt(int index) { public E elementAt(int index) {
return delegate.elementAt(index); return delegate.elementAt(index);
} }
@ -271,7 +273,7 @@ public class DefaultListModel extends AbstractListModel
* @return the first component of this list * @return the first component of this list
* @see Vector#firstElement() * @see Vector#firstElement()
*/ */
public Object firstElement() { public E firstElement() {
return delegate.firstElement(); return delegate.firstElement();
} }
@ -283,13 +285,13 @@ public class DefaultListModel extends AbstractListModel
* @return the last component of the list * @return the last component of the list
* @see Vector#lastElement() * @see Vector#lastElement()
*/ */
public Object lastElement() { public E lastElement() {
return delegate.lastElement(); return delegate.lastElement();
} }
/** /**
* Sets the component at the specified <code>index</code> of this * Sets the component at the specified <code>index</code> of this
* list to be the specified object. The previous component at that * list to be the specified element. The previous component at that
* position is discarded. * position is discarded.
* <p> * <p>
* Throws an <code>ArrayIndexOutOfBoundsException</code> if the index * Throws an <code>ArrayIndexOutOfBoundsException</code> if the index
@ -300,13 +302,13 @@ public class DefaultListModel extends AbstractListModel
* <code>List</code> interface defined in the 1.2 Collections framework. * <code>List</code> interface defined in the 1.2 Collections framework.
* </blockquote> * </blockquote>
* *
* @param obj what the component is to be set to * @param element what the component is to be set to
* @param index the specified index * @param index the specified index
* @see #set(int,Object) * @see #set(int,Object)
* @see Vector#setElementAt(Object,int) * @see Vector#setElementAt(Object,int)
*/ */
public void setElementAt(Object obj, int index) { public void setElementAt(E element, int index) {
delegate.setElementAt(obj, index); delegate.setElementAt(element, index);
fireContentsChanged(this, index, index); fireContentsChanged(this, index, index);
} }
@ -331,7 +333,7 @@ public class DefaultListModel extends AbstractListModel
} }
/** /**
* Inserts the specified object as a component in this list at the * Inserts the specified element as a component in this list at the
* specified <code>index</code>. * specified <code>index</code>.
* <p> * <p>
* Throws an <code>ArrayIndexOutOfBoundsException</code> if the index * Throws an <code>ArrayIndexOutOfBoundsException</code> if the index
@ -342,26 +344,26 @@ public class DefaultListModel extends AbstractListModel
* <code>List</code> interface defined in the 1.2 Collections framework. * <code>List</code> interface defined in the 1.2 Collections framework.
* </blockquote> * </blockquote>
* *
* @param obj the component to insert * @param element the component to insert
* @param index where to insert the new component * @param index where to insert the new component
* @exception ArrayIndexOutOfBoundsException if the index was invalid * @exception ArrayIndexOutOfBoundsException if the index was invalid
* @see #add(int,Object) * @see #add(int,Object)
* @see Vector#insertElementAt(Object,int) * @see Vector#insertElementAt(Object,int)
*/ */
public void insertElementAt(Object obj, int index) { public void insertElementAt(E element, int index) {
delegate.insertElementAt(obj, index); delegate.insertElementAt(element, index);
fireIntervalAdded(this, index, index); fireIntervalAdded(this, index, index);
} }
/** /**
* Adds the specified component to the end of this list. * Adds the specified component to the end of this list.
* *
* @param obj the component to be added * @param element the component to be added
* @see Vector#addElement(Object) * @see Vector#addElement(Object)
*/ */
public void addElement(Object obj) { public void addElement(E element) {
int index = delegate.size(); int index = delegate.size();
delegate.addElement(obj); delegate.addElement(element);
fireIntervalAdded(this, index, index); fireIntervalAdded(this, index, index);
} }
@ -441,7 +443,7 @@ public class DefaultListModel extends AbstractListModel
* *
* @param index index of element to return * @param index index of element to return
*/ */
public Object get(int index) { public E get(int index) {
return delegate.elementAt(index); return delegate.elementAt(index);
} }
@ -457,8 +459,8 @@ public class DefaultListModel extends AbstractListModel
* @param element element to be stored at the specified position * @param element element to be stored at the specified position
* @return the element previously at the specified position * @return the element previously at the specified position
*/ */
public Object set(int index, Object element) { public E set(int index, E element) {
Object rv = delegate.elementAt(index); E rv = delegate.elementAt(index);
delegate.setElementAt(element, index); delegate.setElementAt(element, index);
fireContentsChanged(this, index, index); fireContentsChanged(this, index, index);
return rv; return rv;
@ -474,7 +476,7 @@ public class DefaultListModel extends AbstractListModel
* @param index index at which the specified element is to be inserted * @param index index at which the specified element is to be inserted
* @param element element to be inserted * @param element element to be inserted
*/ */
public void add(int index, Object element) { public void add(int index, E element) {
delegate.insertElementAt(element, index); delegate.insertElementAt(element, index);
fireIntervalAdded(this, index, index); fireIntervalAdded(this, index, index);
} }
@ -488,9 +490,10 @@ public class DefaultListModel extends AbstractListModel
* (<code>index &lt; 0 || index &gt;= size()</code>). * (<code>index &lt; 0 || index &gt;= size()</code>).
* *
* @param index the index of the element to removed * @param index the index of the element to removed
* @return the element previously at the specified position
*/ */
public Object remove(int index) { public E remove(int index) {
Object rv = delegate.elementAt(index); E rv = delegate.elementAt(index);
delegate.removeElementAt(index); delegate.removeElementAt(index);
fireIntervalRemoved(this, index, index); fireIntervalRemoved(this, index, index);
return rv; return rv;

View File

@ -25,11 +25,24 @@
package javax.swing; package javax.swing;
import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.GraphicsEnvironment;
import java.awt.HeadlessException;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.*; import java.awt.event.*;
import java.awt.*;
import java.util.Vector; import java.util.Vector;
import java.util.Locale; import java.util.Locale;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
@ -59,28 +72,30 @@ import static sun.swing.SwingUtilities2.Section.*;
* constructor that automatically builds a read-only {@code ListModel} instance * constructor that automatically builds a read-only {@code ListModel} instance
* for you: * for you:
* <pre> * <pre>
* {@code
* // Create a JList that displays strings from an array * // Create a JList that displays strings from an array
* *
* String[] data = {"one", "two", "three", "four"}; * String[] data = {"one", "two", "three", "four"};
* JList myList = new JList(data); * JList<String> myList = new JList<String>(data);
* *
* // Create a JList that displays the superclasses of JList.class, by * // Create a JList that displays the superclasses of JList.class, by
* // creating it with a Vector populated with this data * // creating it with a Vector populated with this data
* *
* Vector superClasses = new Vector(); * Vector<Class<?>> superClasses = new Vector<Class<?>>();
* Class rootClass = javax.swing.JList.class; * Class<JList> rootClass = javax.swing.JList.class;
* for(Class cls = rootClass; cls != null; cls = cls.getSuperclass()) { * for(Class<?> cls = rootClass; cls != null; cls = cls.getSuperclass()) {
* superClasses.addElement(cls); * superClasses.addElement(cls);
* } * }
* JList myList = new JList(superClasses); * JList<Class<?>> myList = new JList<Class<?>>(superClasses);
* *
* // The automatically created model is stored in JList's "model" * // The automatically created model is stored in JList's "model"
* // property, which you can retrieve * // property, which you can retrieve
* *
* ListModel model = myList.getModel(); * ListModel<Class<?>> model = myList.getModel();
* for(int i = 0; i < model.getSize(); i++) { * for(int i = 0; i < model.getSize(); i++) {
* System.out.println(model.getElementAt(i)); * System.out.println(model.getElementAt(i));
* } * }
* }
* </pre> * </pre>
* <p> * <p>
* A {@code ListModel} can be supplied directly to a {@code JList} by way of a * A {@code ListModel} can be supplied directly to a {@code JList} by way of a
@ -103,12 +118,14 @@ import static sun.swing.SwingUtilities2.Section.*;
* notifying listeners. For example, a read-only implementation of * notifying listeners. For example, a read-only implementation of
* {@code AbstractListModel}: * {@code AbstractListModel}:
* <pre> * <pre>
* {@code
* // This list model has about 2^16 elements. Enjoy scrolling. * // This list model has about 2^16 elements. Enjoy scrolling.
* *
* ListModel bigData = new AbstractListModel() { * ListModel<String> bigData = new AbstractListModel<String>() {
* public int getSize() { return Short.MAX_VALUE; } * public int getSize() { return Short.MAX_VALUE; }
* public Object getElementAt(int index) { return "Index " + index; } * public String getElementAt(int index) { return "Index " + index; }
* }; * };
* }
* </pre> * </pre>
* <p> * <p>
* The selection state of a {@code JList} is managed by another separate * The selection state of a {@code JList} is managed by another separate
@ -150,9 +167,10 @@ import static sun.swing.SwingUtilities2.Section.*;
* component to render, is installed by the lists's {@code ListUI}. You can * component to render, is installed by the lists's {@code ListUI}. You can
* substitute your own renderer using code like this: * substitute your own renderer using code like this:
* <pre> * <pre>
* {@code
* // Display an icon and a string for each object in the list. * // Display an icon and a string for each object in the list.
* *
* class MyCellRenderer extends JLabel implements ListCellRenderer { * class MyCellRenderer extends JLabel implements ListCellRenderer<Object> {
* final static ImageIcon longIcon = new ImageIcon("long.gif"); * final static ImageIcon longIcon = new ImageIcon("long.gif");
* final static ImageIcon shortIcon = new ImageIcon("short.gif"); * final static ImageIcon shortIcon = new ImageIcon("short.gif");
* *
@ -160,7 +178,7 @@ import static sun.swing.SwingUtilities2.Section.*;
* // We just reconfigure the JLabel each time we're called. * // We just reconfigure the JLabel each time we're called.
* *
* public Component getListCellRendererComponent( * public Component getListCellRendererComponent(
* JList list, // the list * JList<?> list, // the list
* Object value, // value to display * Object value, // value to display
* int index, // cell index * int index, // cell index
* boolean isSelected, // is the cell selected * boolean isSelected, // is the cell selected
@ -184,6 +202,7 @@ import static sun.swing.SwingUtilities2.Section.*;
* } * }
* *
* myList.setCellRenderer(new MyCellRenderer()); * myList.setCellRenderer(new MyCellRenderer());
* }
* </pre> * </pre>
* <p> * <p>
* Another job for the cell renderer is in helping to determine sizing * Another job for the cell renderer is in helping to determine sizing
@ -195,7 +214,8 @@ import static sun.swing.SwingUtilities2.Section.*;
* automatically based on a single prototype value: * automatically based on a single prototype value:
* <a name="prototype_example"> * <a name="prototype_example">
* <pre> * <pre>
* JList bigDataList = new JList(bigData); * {@code
* JList<String> bigDataList = new JList<String>(bigData);
* *
* // We don't want the JList implementation to compute the width * // We don't want the JList implementation to compute the width
* // or height of all of the list cells, so we give it a string * // or height of all of the list cells, so we give it a string
@ -204,6 +224,7 @@ import static sun.swing.SwingUtilities2.Section.*;
* // properties. * // properties.
* *
* bigDataList.setPrototypeCellValue("Index 1234567890"); * bigDataList.setPrototypeCellValue("Index 1234567890");
* }
* </pre> * </pre>
* <p> * <p>
* {@code JList} doesn't implement scrolling directly. To create a list that * {@code JList} doesn't implement scrolling directly. To create a list that
@ -260,13 +281,15 @@ import static sun.swing.SwingUtilities2.Section.*;
* @see ListCellRenderer * @see ListCellRenderer
* @see DefaultListCellRenderer * @see DefaultListCellRenderer
* *
* @param <E> the type of the elements of this list
*
* @beaninfo * @beaninfo
* attribute: isContainer false * attribute: isContainer false
* description: A component which allows for the selection of one or more objects from a list. * description: A component which allows for the selection of one or more objects from a list.
* *
* @author Hans Muller * @author Hans Muller
*/ */
public class JList extends JComponent implements Scrollable, Accessible public class JList<E> extends JComponent implements Scrollable, Accessible
{ {
/** /**
* @see #getUIClassID * @see #getUIClassID
@ -301,15 +324,15 @@ public class JList extends JComponent implements Scrollable, Accessible
private int fixedCellWidth = -1; private int fixedCellWidth = -1;
private int fixedCellHeight = -1; private int fixedCellHeight = -1;
private int horizontalScrollIncrement = -1; private int horizontalScrollIncrement = -1;
private Object prototypeCellValue; private E prototypeCellValue;
private int visibleRowCount = 8; private int visibleRowCount = 8;
private Color selectionForeground; private Color selectionForeground;
private Color selectionBackground; private Color selectionBackground;
private boolean dragEnabled; private boolean dragEnabled;
private ListSelectionModel selectionModel; private ListSelectionModel selectionModel;
private ListModel dataModel; private ListModel<E> dataModel;
private ListCellRenderer cellRenderer; private ListCellRenderer<? super E> cellRenderer;
private ListSelectionListener selectionListener; private ListSelectionListener selectionListener;
/** /**
@ -402,7 +425,7 @@ public class JList extends JComponent implements Scrollable, Accessible
* @param dataModel the model for the list * @param dataModel the model for the list
* @exception IllegalArgumentException if the model is {@code null} * @exception IllegalArgumentException if the model is {@code null}
*/ */
public JList(ListModel dataModel) public JList(ListModel<E> dataModel)
{ {
if (dataModel == null) { if (dataModel == null) {
throw new IllegalArgumentException("dataModel must be non null"); throw new IllegalArgumentException("dataModel must be non null");
@ -437,12 +460,12 @@ public class JList extends JComponent implements Scrollable, Accessible
* @param listData the array of Objects to be loaded into the data model, * @param listData the array of Objects to be loaded into the data model,
* {@code non-null} * {@code non-null}
*/ */
public JList(final Object[] listData) public JList(final E[] listData)
{ {
this ( this (
new AbstractListModel() { new AbstractListModel<E>() {
public int getSize() { return listData.length; } public int getSize() { return listData.length; }
public Object getElementAt(int i) { return listData[i]; } public E getElementAt(int i) { return listData[i]; }
} }
); );
} }
@ -462,11 +485,11 @@ public class JList extends JComponent implements Scrollable, Accessible
* @param listData the <code>Vector</code> to be loaded into the * @param listData the <code>Vector</code> to be loaded into the
* data model, {@code non-null} * data model, {@code non-null}
*/ */
public JList(final Vector<?> listData) { public JList(final Vector<? extends E> listData) {
this ( this (
new AbstractListModel() { new AbstractListModel<E>() {
public int getSize() { return listData.size(); } public int getSize() { return listData.size(); }
public Object getElementAt(int i) { return listData.elementAt(i); } public E getElementAt(int i) { return listData.elementAt(i); }
} }
); );
} }
@ -477,9 +500,9 @@ public class JList extends JComponent implements Scrollable, Accessible
*/ */
public JList() { public JList() {
this ( this (
new AbstractListModel() { new AbstractListModel<E>() {
public int getSize() { return 0; } public int getSize() { return 0; }
public Object getElementAt(int i) { return "No Data Model"; } public E getElementAt(int i) { throw new IndexOutOfBoundsException("No Data Model"); }
} }
); );
} }
@ -526,7 +549,7 @@ public class JList extends JComponent implements Scrollable, Accessible
public void updateUI() { public void updateUI() {
setUI((ListUI)UIManager.getUI(this)); setUI((ListUI)UIManager.getUI(this));
ListCellRenderer renderer = getCellRenderer(); ListCellRenderer<? super E> renderer = getCellRenderer();
if (renderer instanceof Component) { if (renderer instanceof Component) {
SwingUtilities.updateComponentTreeUI((Component)renderer); SwingUtilities.updateComponentTreeUI((Component)renderer);
} }
@ -560,8 +583,8 @@ public class JList extends JComponent implements Scrollable, Accessible
*/ */
private void updateFixedCellSize() private void updateFixedCellSize()
{ {
ListCellRenderer cr = getCellRenderer(); ListCellRenderer<? super E> cr = getCellRenderer();
Object value = getPrototypeCellValue(); E value = getPrototypeCellValue();
if ((cr != null) && (value != null)) { if ((cr != null) && (value != null)) {
Component c = cr.getListCellRendererComponent(this, value, 0, false, false); Component c = cr.getListCellRendererComponent(this, value, 0, false, false);
@ -592,7 +615,7 @@ public class JList extends JComponent implements Scrollable, Accessible
* @return the value of the {@code prototypeCellValue} property * @return the value of the {@code prototypeCellValue} property
* @see #setPrototypeCellValue * @see #setPrototypeCellValue
*/ */
public Object getPrototypeCellValue() { public E getPrototypeCellValue() {
return prototypeCellValue; return prototypeCellValue;
} }
@ -632,8 +655,8 @@ public class JList extends JComponent implements Scrollable, Accessible
* attribute: visualUpdate true * attribute: visualUpdate true
* description: The cell prototype value, used to compute cell width and height. * description: The cell prototype value, used to compute cell width and height.
*/ */
public void setPrototypeCellValue(Object prototypeCellValue) { public void setPrototypeCellValue(E prototypeCellValue) {
Object oldValue = this.prototypeCellValue; E oldValue = this.prototypeCellValue;
this.prototypeCellValue = prototypeCellValue; this.prototypeCellValue = prototypeCellValue;
/* If the prototypeCellValue has changed and is non-null, /* If the prototypeCellValue has changed and is non-null,
@ -727,7 +750,7 @@ public class JList extends JComponent implements Scrollable, Accessible
* @see #setCellRenderer * @see #setCellRenderer
*/ */
@Transient @Transient
public ListCellRenderer getCellRenderer() { public ListCellRenderer<? super E> getCellRenderer() {
return cellRenderer; return cellRenderer;
} }
@ -755,8 +778,8 @@ public class JList extends JComponent implements Scrollable, Accessible
* attribute: visualUpdate true * attribute: visualUpdate true
* description: The component used to draw the cells. * description: The component used to draw the cells.
*/ */
public void setCellRenderer(ListCellRenderer cellRenderer) { public void setCellRenderer(ListCellRenderer<? super E> cellRenderer) {
ListCellRenderer oldValue = this.cellRenderer; ListCellRenderer<? super E> oldValue = this.cellRenderer;
this.cellRenderer = cellRenderer; this.cellRenderer = cellRenderer;
/* If the cellRenderer has changed and prototypeCellValue /* If the cellRenderer has changed and prototypeCellValue
@ -1455,7 +1478,7 @@ public class JList extends JComponent implements Scrollable, Accessible
* @since 1.4 * @since 1.4
*/ */
public int getNextMatch(String prefix, int startIndex, Position.Bias bias) { public int getNextMatch(String prefix, int startIndex, Position.Bias bias) {
ListModel model = getModel(); ListModel<E> model = getModel();
int max = model.getSize(); int max = model.getSize();
if (prefix == null) { if (prefix == null) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
@ -1469,16 +1492,16 @@ public class JList extends JComponent implements Scrollable, Accessible
int increment = (bias == Position.Bias.Forward) ? 1 : -1; int increment = (bias == Position.Bias.Forward) ? 1 : -1;
int index = startIndex; int index = startIndex;
do { do {
Object o = model.getElementAt(index); E element = model.getElementAt(index);
if (o != null) { if (element != null) {
String string; String string;
if (o instanceof String) { if (element instanceof String) {
string = ((String)o).toUpperCase(); string = ((String)element).toUpperCase();
} }
else { else {
string = o.toString(); string = element.toString();
if (string != null) { if (string != null) {
string = string.toUpperCase(); string = string.toUpperCase();
} }
@ -1516,7 +1539,7 @@ public class JList extends JComponent implements Scrollable, Accessible
if(event != null) { if(event != null) {
Point p = event.getPoint(); Point p = event.getPoint();
int index = locationToIndex(p); int index = locationToIndex(p);
ListCellRenderer r = getCellRenderer(); ListCellRenderer<? super E> r = getCellRenderer();
Rectangle cellBounds; Rectangle cellBounds;
if (index != -1 && r != null && (cellBounds = if (index != -1 && r != null && (cellBounds =
@ -1634,7 +1657,7 @@ public class JList extends JComponent implements Scrollable, Accessible
* list of items * list of items
* @see #setModel * @see #setModel
*/ */
public ListModel getModel() { public ListModel<E> getModel() {
return dataModel; return dataModel;
} }
@ -1656,11 +1679,11 @@ public class JList extends JComponent implements Scrollable, Accessible
* attribute: visualUpdate true * attribute: visualUpdate true
* description: The object that contains the data to be drawn by this JList. * description: The object that contains the data to be drawn by this JList.
*/ */
public void setModel(ListModel model) { public void setModel(ListModel<E> model) {
if (model == null) { if (model == null) {
throw new IllegalArgumentException("model must be non null"); throw new IllegalArgumentException("model must be non null");
} }
ListModel oldValue = dataModel; ListModel<E> oldValue = dataModel;
dataModel = model; dataModel = model;
firePropertyChange("model", oldValue, dataModel); firePropertyChange("model", oldValue, dataModel);
clearSelection(); clearSelection();
@ -1668,7 +1691,7 @@ public class JList extends JComponent implements Scrollable, Accessible
/** /**
* Constructs a read-only <code>ListModel</code> from an array of objects, * Constructs a read-only <code>ListModel</code> from an array of items,
* and calls {@code setModel} with this model. * and calls {@code setModel} with this model.
* <p> * <p>
* Attempts to pass a {@code null} value to this method results in * Attempts to pass a {@code null} value to this method results in
@ -1676,15 +1699,15 @@ public class JList extends JComponent implements Scrollable, Accessible
* references the given array directly. Attempts to modify the array * references the given array directly. Attempts to modify the array
* after invoking this method results in undefined behavior. * after invoking this method results in undefined behavior.
* *
* @param listData an array of {@code Objects} containing the items to * @param listData an array of {@code E} containing the items to
* display in the list * display in the list
* @see #setModel * @see #setModel
*/ */
public void setListData(final Object[] listData) { public void setListData(final E[] listData) {
setModel ( setModel (
new AbstractListModel() { new AbstractListModel<E>() {
public int getSize() { return listData.length; } public int getSize() { return listData.length; }
public Object getElementAt(int i) { return listData[i]; } public E getElementAt(int i) { return listData[i]; }
} }
); );
} }
@ -1703,11 +1726,11 @@ public class JList extends JComponent implements Scrollable, Accessible
* display in the list * display in the list
* @see #setModel * @see #setModel
*/ */
public void setListData(final Vector<?> listData) { public void setListData(final Vector<? extends E> listData) {
setModel ( setModel (
new AbstractListModel() { new AbstractListModel<E>() {
public int getSize() { return listData.size(); } public int getSize() { return listData.size(); }
public Object getElementAt(int i) { return listData.elementAt(i); } public E getElementAt(int i) { return listData.elementAt(i); }
} }
); );
} }
@ -2235,10 +2258,13 @@ public class JList extends JComponent implements Scrollable, Accessible
* @see #isSelectedIndex * @see #isSelectedIndex
* @see #getModel * @see #getModel
* @see #addListSelectionListener * @see #addListSelectionListener
*
* @deprecated As of JDK 1.7, replaced by {@link #getSelectedValuesList()}
*/ */
@Deprecated
public Object[] getSelectedValues() { public Object[] getSelectedValues() {
ListSelectionModel sm = getSelectionModel(); ListSelectionModel sm = getSelectionModel();
ListModel dm = getModel(); ListModel<E> dm = getModel();
int iMin = sm.getMinSelectionIndex(); int iMin = sm.getMinSelectionIndex();
int iMax = sm.getMaxSelectionIndex(); int iMax = sm.getMaxSelectionIndex();
@ -2259,6 +2285,37 @@ public class JList extends JComponent implements Scrollable, Accessible
return rv; return rv;
} }
/**
* Returns a list of all the selected items, in increasing order based
* on their indices in the list.
*
* @return the selected items, or an empty list if nothing is selected
* @see #isSelectedIndex
* @see #getModel
* @see #addListSelectionListener
*
* @since 1.7
*/
public List<E> getSelectedValuesList() {
ListSelectionModel sm = getSelectionModel();
ListModel<E> dm = getModel();
int iMin = sm.getMinSelectionIndex();
int iMax = sm.getMaxSelectionIndex();
if ((iMin < 0) || (iMax < 0)) {
return Collections.emptyList();
}
List<E> selectedItems = new ArrayList<E>();
for(int i = iMin; i <= iMax; i++) {
if (sm.isSelectedIndex(i)) {
selectedItems.add(dm.getElementAt(i));
}
}
return selectedItems;
}
/** /**
* Returns the smallest selected cell index; <i>the selection</i> when only * Returns the smallest selected cell index; <i>the selection</i> when only
@ -2291,7 +2348,7 @@ public class JList extends JComponent implements Scrollable, Accessible
* @see #getModel * @see #getModel
* @see #addListSelectionListener * @see #addListSelectionListener
*/ */
public Object getSelectedValue() { public E getSelectedValue() {
int i = getMinSelectionIndex(); int i = getMinSelectionIndex();
return (i == -1) ? null : getModel().getElementAt(i); return (i == -1) ? null : getModel().getElementAt(i);
} }
@ -2309,7 +2366,7 @@ public class JList extends JComponent implements Scrollable, Accessible
setSelectedIndex(-1); setSelectedIndex(-1);
else if(!anObject.equals(getSelectedValue())) { else if(!anObject.equals(getSelectedValue())) {
int i,c; int i,c;
ListModel dm = getModel(); ListModel<E> dm = getModel();
for(i=0,c=dm.getSize();i<c;i++) for(i=0,c=dm.getSize();i<c;i++)
if(anObject.equals(dm.getElementAt(i))){ if(anObject.equals(dm.getElementAt(i))){
setSelectedIndex(i); setSelectedIndex(i);
@ -3138,14 +3195,14 @@ public class JList extends JComponent implements Scrollable, Accessible
*/ */
protected class AccessibleJListChild extends AccessibleContext protected class AccessibleJListChild extends AccessibleContext
implements Accessible, AccessibleComponent { implements Accessible, AccessibleComponent {
private JList parent = null; private JList<E> parent = null;
private int indexInParent; private int indexInParent;
private Component component = null; private Component component = null;
private AccessibleContext accessibleContext = null; private AccessibleContext accessibleContext = null;
private ListModel listModel; private ListModel<E> listModel;
private ListCellRenderer cellRenderer = null; private ListCellRenderer<? super E> cellRenderer = null;
public AccessibleJListChild(JList parent, int indexInParent) { public AccessibleJListChild(JList<E> parent, int indexInParent) {
this.parent = parent; this.parent = parent;
this.setAccessibleParent(parent); this.setAccessibleParent(parent);
this.indexInParent = indexInParent; this.indexInParent = indexInParent;
@ -3175,7 +3232,7 @@ public class JList extends JComponent implements Scrollable, Accessible
if ((parent != null) if ((parent != null)
&& (listModel != null) && (listModel != null)
&& cellRenderer != null) { && cellRenderer != null) {
Object value = listModel.getElementAt(index); E value = listModel.getElementAt(index);
boolean isSelected = parent.isSelectedIndex(index); boolean isSelected = parent.isSelectedIndex(index);
boolean isFocussed = parent.isFocusOwner() boolean isFocussed = parent.isFocusOwner()
&& (index == parent.getLeadSelectionIndex()); && (index == parent.getLeadSelectionIndex());

View File

@ -33,12 +33,13 @@ import java.awt.Component;
* the cells in a JList. For example, to use a JLabel as a * the cells in a JList. For example, to use a JLabel as a
* ListCellRenderer, you would write something like this: * ListCellRenderer, you would write something like this:
* <pre> * <pre>
* class MyCellRenderer extends JLabel implements ListCellRenderer { * {@code
* class MyCellRenderer extends JLabel implements ListCellRenderer<Object> {
* public MyCellRenderer() { * public MyCellRenderer() {
* setOpaque(true); * setOpaque(true);
* } * }
* *
* public Component getListCellRendererComponent(JList list, * public Component getListCellRendererComponent(JList<?> list,
* Object value, * Object value,
* int index, * int index,
* boolean isSelected, * boolean isSelected,
@ -75,14 +76,17 @@ import java.awt.Component;
* return this; * return this;
* } * }
* } * }
* }
* </pre> * </pre>
* *
* @param <E> the type of values this renderer can be used for
*
* @see JList * @see JList
* @see DefaultListCellRenderer * @see DefaultListCellRenderer
* *
* @author Hans Muller * @author Hans Muller
*/ */
public interface ListCellRenderer public interface ListCellRenderer<E>
{ {
/** /**
* Return a component that has been configured to display the specified * Return a component that has been configured to display the specified
@ -104,8 +108,8 @@ public interface ListCellRenderer
* @see ListModel * @see ListModel
*/ */
Component getListCellRendererComponent( Component getListCellRendererComponent(
JList list, JList<? extends E> list,
Object value, E value,
int index, int index,
boolean isSelected, boolean isSelected,
boolean cellHasFocus); boolean cellHasFocus);

View File

@ -35,10 +35,12 @@ import javax.swing.event.ListDataListener;
* length of the data model must be reported to all of the * length of the data model must be reported to all of the
* ListDataListeners. * ListDataListeners.
* *
* @param <E> the type of the elements of this model
*
* @author Hans Muller * @author Hans Muller
* @see JList * @see JList
*/ */
public interface ListModel public interface ListModel<E>
{ {
/** /**
* Returns the length of the list. * Returns the length of the list.
@ -51,7 +53,7 @@ public interface ListModel
* @param index the requested index * @param index the requested index
* @return the value at <code>index</code> * @return the value at <code>index</code>
*/ */
Object getElementAt(int index); E getElementAt(int index);
/** /**
* Adds a listener to the list that's notified each time a change * Adds a listener to the list that's notified each time a change

View File

@ -0,0 +1,247 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
/* @test
@bug 6823603
@summary Generics: JList
@author Florian Brunner
@run main bug6823603
*/
import java.util.Arrays;
import java.util.List;
import java.util.Vector;
import java.util.Enumeration;
import java.awt.*;
import javax.swing.*;
public class bug6823603 {
private static final String TEST_ELEMENT = "Test1";
/**
* @param args the command line arguments
*/
@SuppressWarnings("unchecked")
public static void main(String[] args) {
testRawSignatures();
testGenericSignatures();
testGetSelectedValuesList(); // new method
}
@SuppressWarnings("unchecked")
private static void testRawSignatures() {
// Test JList
ListModel rawTestModel = new DefaultListModel();
new JList();
new JList(rawTestModel);
new JList(new Object[]{TEST_ELEMENT});
JList rawTestList = new JList(new Vector());
rawTestList.getPrototypeCellValue();
rawTestList.setPrototypeCellValue(TEST_ELEMENT);
rawTestList.getCellRenderer();
rawTestList.setCellRenderer(new DefaultListCellRenderer());
rawTestList.getModel();
rawTestList.setModel(rawTestModel);
rawTestList.setListData(new Object[]{TEST_ELEMENT});
rawTestList.setListData(new Vector());
@SuppressWarnings("deprecation")
Object[] selectedValues = rawTestList.getSelectedValues();
rawTestList.getSelectedValue();
// Test ListCellRenderer
ListCellRenderer rawTestCellRenderer = new DefaultListCellRenderer();
String testEntry = "Test";
@SuppressWarnings("unchecked")
JList rawJList = new JList(new Object[]{testEntry});
rawTestCellRenderer.getListCellRendererComponent(rawJList,
testEntry, 0, true, true);
// Test ListModel
DefaultListModel testModel = new DefaultListModel();
testModel.addElement(TEST_ELEMENT);
rawTestModel = testModel;
rawTestModel.getElementAt(0);
// Test DefaultListModel
DefaultListModel defaultListModel = new DefaultListModel();
defaultListModel.addElement(TEST_ELEMENT);
defaultListModel.getElementAt(0);
defaultListModel.elements();
defaultListModel.elementAt(0);
defaultListModel.firstElement();
defaultListModel.lastElement();
String testElement2 = "Test2";
defaultListModel.setElementAt(testElement2, 0);
defaultListModel.insertElementAt(TEST_ELEMENT, 0);
defaultListModel.get(0);
defaultListModel.set(0, testElement2);
defaultListModel.add(0, TEST_ELEMENT);
defaultListModel.remove(0);
// Test AbstractListModel
@SuppressWarnings("serial")
ListModel abstractListModel = new AbstractListModel() {
public int getSize() {
throw new UnsupportedOperationException("Not supported yet.");
}
public Object getElementAt(int index) {
throw new UnsupportedOperationException("Not supported yet.");
}
};
// Test DefaultListCellRenderer
DefaultListCellRenderer cellRenderer = new DefaultListCellRenderer();
@SuppressWarnings("unchecked")
JList list = new JList(new Object[]{testEntry});
cellRenderer.getListCellRendererComponent(rawJList, testEntry, 0, true, true);
}
private static <E> void testGenericSignatures() {
// Test JList
ListModel<String> stringListModel = new DefaultListModel<String>();
new JList<String>();
new JList<String>(stringListModel);
new JList<String>(new String[]{TEST_ELEMENT});
JList<String> stringTestList = new JList<String>(new Vector<String>());
stringTestList.getPrototypeCellValue();
stringTestList.setPrototypeCellValue(TEST_ELEMENT);
ListCellRenderer<? super String> cellRenderer = stringTestList.getCellRenderer();
stringTestList.setCellRenderer(new DefaultListCellRenderer());
ListModel<String> model = stringTestList.getModel();
stringTestList.setModel(stringListModel);
stringTestList.setListData(new String[]{TEST_ELEMENT});
stringTestList.setListData(new Vector<String>());
@SuppressWarnings("deprecation")
Object[] selectedValues = stringTestList.getSelectedValues();
stringTestList.getSelectedValue();
// Test ListCellRenderer
ListCellRenderer<Object> stringTestCellRenderer =
new DefaultListCellRenderer();
String testEntry = "Test";
JList<String> stringJList = new JList<String>(new String[]{testEntry});
Component listCellRendererComponent2 =
stringTestCellRenderer.getListCellRendererComponent(stringJList,
testEntry, 0, true, true);
// Test ListModel
DefaultListModel<String> testModel = new DefaultListModel<String>();
testModel.addElement(TEST_ELEMENT);
stringListModel = testModel;
String element1 = stringListModel.getElementAt(0);
// Test DefaultListModel
DefaultListModel<String> stringTestModel = new DefaultListModel<String>();
stringTestModel.addElement(TEST_ELEMENT);
element1 = stringTestModel.getElementAt(0);
Enumeration<String> elements = stringTestModel.elements();
String element2 = stringTestModel.elementAt(0);
String firstElement = stringTestModel.firstElement();
String lastElement = stringTestModel.lastElement();
String testElement2 = "Test2";
stringTestModel.setElementAt(testElement2, 0);
stringTestModel.insertElementAt(TEST_ELEMENT, 0);
String element3 = stringTestModel.get(0);
String element4 = stringTestModel.set(0, testElement2);
stringTestModel.add(0, TEST_ELEMENT);
String removedElement = stringTestModel.remove(0);
// Test AbstractListModel
stringListModel = new AbstractListModel<String>() {
public int getSize() {
throw new UnsupportedOperationException("Not supported yet.");
}
public String getElementAt(int index) {
throw new UnsupportedOperationException("Not supported yet.");
}
};
@SuppressWarnings("serial")
ListModel<E> genericTestModel = new AbstractListModel<E>() {
public int getSize() {
throw new UnsupportedOperationException("Not supported yet.");
}
public E getElementAt(int index) {
throw new UnsupportedOperationException("Not supported yet.");
}
};
// Test DefaultListCellRenderer
cellRenderer = new DefaultListCellRenderer();
stringJList = new JList<String>(new String[]{testEntry});
listCellRendererComponent2 = cellRenderer.getListCellRendererComponent(stringJList, testEntry, 0, true, true);
}
private static void testGetSelectedValuesList() {
Vector<Integer> data = new Vector<Integer>();
for (int i = 0; i < 10; i++) {
data.add(i);
}
JList<Integer> list = new JList<Integer>(data);
list.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
list.setSelectedIndices(new int[]{1, 2, 3, 5, 6, 8});
@SuppressWarnings("deprecation")
Object[] expectedSelectedValues = list.getSelectedValues();
List<Integer> selectedValuesList = list.getSelectedValuesList();
assertEquals(expectedSelectedValues, selectedValuesList.toArray());
}
private static void assertEquals(Object[] expectedArray,
Object[] actualArray) {
if (!Arrays.equals(expectedArray, actualArray)) {
throw new RuntimeException("Expected: " + Arrays.toString(
expectedArray) + " but was: " + Arrays.toString(actualArray));
}
}
}