3735 lines · 141.5 KB · Java
RawDownload
/* * Copyright (c) 1997, 2010, Oracle and/or its affiliates. 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.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package javax.swing; import java.awt.*;import java.awt.event.*; import java.util.Vector;import java.util.Locale;import java.util.ArrayList;import java.util.Collections;import java.util.List; import java.beans.PropertyChangeEvent;import java.beans.PropertyChangeListener;import java.beans.Transient; import javax.swing.event.*;import javax.accessibility.*;import javax.swing.plaf.*;import javax.swing.text.Position; import java.io.ObjectOutputStream;import java.io.ObjectInputStream;import java.io.IOException;import java.io.Serializable; import sun.swing.SwingUtilities2;import sun.swing.SwingUtilities2.Section;import static sun.swing.SwingUtilities2.Section.*;  /** * A component that displays a list of objects and allows the user to select * one or more items. A separate model, {@code ListModel}, maintains the * contents of the list. * <p> * It's easy to display an array or Vector of objects, using the {@code JList} * constructor that automatically builds a read-only {@code ListModel} instance * for you: * <pre> * {@code * // Create a JList that displays strings from an array * * String[] data = {"one", "two", "three", "four"}; * JList<String> myList = new JList<String>(data); * * // Create a JList that displays the superclasses of JList.class, by * // creating it with a Vector populated with this data * * Vector<Class<?>> superClasses = new Vector<Class<?>>(); * Class<JList> rootClass = javax.swing.JList.class; * for(Class<?> cls = rootClass; cls != null; cls = cls.getSuperclass()) { *     superClasses.addElement(cls); * } * JList<Class<?>> myList = new JList<Class<?>>(superClasses); * * // The automatically created model is stored in JList's "model" * // property, which you can retrieve * * ListModel<Class<?>> model = myList.getModel(); * for(int i = 0; i < model.getSize(); i++) { *     System.out.println(model.getElementAt(i)); * } * } * </pre> * <p> * A {@code ListModel} can be supplied directly to a {@code JList} by way of a * constructor or the {@code setModel} method. The contents need not be static - * the number of items, and the values of items can change over time. A correct * {@code ListModel} implementation notifies the set of * {@code javax.swing.event.ListDataListener}s that have been added to it, each * time a change occurs. These changes are characterized by a * {@code javax.swing.event.ListDataEvent}, which identifies the range of list * indices that have been modified, added, or removed. {@code JList}'s * {@code ListUI} is responsible for keeping the visual representation up to * date with changes, by listening to the model. * <p> * Simple, dynamic-content, {@code JList} applications can use the * {@code DefaultListModel} class to maintain list elements. This class * implements the {@code ListModel} interface and also provides a * <code>java.util.Vector</code>-like API. Applications that need a more * custom <code>ListModel</code> implementation may instead wish to subclass * {@code AbstractListModel}, which provides basic support for managing and * notifying listeners. For example, a read-only implementation of * {@code AbstractListModel}: * <pre> * {@code * // This list model has about 2^16 elements.  Enjoy scrolling. * * ListModel<String> bigData = new AbstractListModel<String>() { *     public int getSize() { return Short.MAX_VALUE; } *     public String getElementAt(int index) { return "Index " + index; } * }; * } * </pre> * <p> * The selection state of a {@code JList} is managed by another separate * model, an instance of {@code ListSelectionModel}. {@code JList} is * initialized with a selection model on construction, and also contains * methods to query or set this selection model. Additionally, {@code JList} * provides convenient methods for easily managing the selection. These methods, * such as {@code setSelectedIndex} and {@code getSelectedValue}, are cover * methods that take care of the details of interacting with the selection * model. By default, {@code JList}'s selection model is configured to allow any * combination of items to be selected at a time; selection mode * {@code MULTIPLE_INTERVAL_SELECTION}. The selection mode can be changed * on the selection model directly, or via {@code JList}'s cover method. * Responsibility for updating the selection model in response to user gestures * lies with the list's {@code ListUI}. * <p> * A correct {@code ListSelectionModel} implementation notifies the set of * {@code javax.swing.event.ListSelectionListener}s that have been added to it * each time a change to the selection occurs. These changes are characterized * by a {@code javax.swing.event.ListSelectionEvent}, which identifies the range * of the selection change. * <p> * The preferred way to listen for changes in list selection is to add * {@code ListSelectionListener}s directly to the {@code JList}. {@code JList} * then takes care of listening to the the selection model and notifying your * listeners of change. * <p> * Responsibility for listening to selection changes in order to keep the list's * visual representation up to date lies with the list's {@code ListUI}. * <p> * <a name="renderer"> * Painting of cells in a {@code JList} is handled by a delegate called a * cell renderer, installed on the list as the {@code cellRenderer} property. * The renderer provides a {@code java.awt.Component} that is used * like a "rubber stamp" to paint the cells. Each time a cell needs to be * painted, the list's {@code ListUI} asks the cell renderer for the component, * moves it into place, and has it paint the contents of the cell by way of its * {@code paint} method. A default cell renderer, which uses a {@code JLabel} * component to render, is installed by the lists's {@code ListUI}. You can * substitute your own renderer using code like this: * <pre> * {@code *  // Display an icon and a string for each object in the list. * * class MyCellRenderer extends JLabel implements ListCellRenderer<Object> { *     final static ImageIcon longIcon = new ImageIcon("long.gif"); *     final static ImageIcon shortIcon = new ImageIcon("short.gif"); * *     // This is the only method defined by ListCellRenderer. *     // We just reconfigure the JLabel each time we're called. * *     public Component getListCellRendererComponent( *       JList<?> list,           // the list *       Object value,            // value to display *       int index,               // cell index *       boolean isSelected,      // is the cell selected *       boolean cellHasFocus)    // does the cell have focus *     { *         String s = value.toString(); *         setText(s); *         setIcon((s.length() > 10) ? longIcon : shortIcon); *         if (isSelected) { *             setBackground(list.getSelectionBackground()); *             setForeground(list.getSelectionForeground()); *         } else { *             setBackground(list.getBackground()); *             setForeground(list.getForeground()); *         } *         setEnabled(list.isEnabled()); *         setFont(list.getFont()); *         setOpaque(true); *         return this; *     } * } * * myList.setCellRenderer(new MyCellRenderer()); * } * </pre> * <p> * Another job for the cell renderer is in helping to determine sizing * information for the list. By default, the list's {@code ListUI} determines * the size of cells by asking the cell renderer for its preferred * size for each list item. This can be expensive for large lists of items. * To avoid these calculations, you can set a {@code fixedCellWidth} and * {@code fixedCellHeight} on the list, or have these values calculated * automatically based on a single prototype value: * <a name="prototype_example"> * <pre> * {@code * JList<String> bigDataList = new JList<String>(bigData); * * // 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 * // that's as big as we'll need for any cell.  It uses this to * // compute values for the fixedCellWidth and fixedCellHeight * // properties. * * bigDataList.setPrototypeCellValue("Index 1234567890"); * } * </pre> * <p> * {@code JList} doesn't implement scrolling directly. To create a list that * scrolls, make it the viewport view of a {@code JScrollPane}. For example: * <pre> * JScrollPane scrollPane = new JScrollPane(myList); * * // Or in two steps: * JScrollPane scrollPane = new JScrollPane(); * scrollPane.getViewport().setView(myList); * </pre> * <p> * {@code JList} doesn't provide any special handling of double or triple * (or N) mouse clicks, but it's easy to add a {@code MouseListener} if you * wish to take action on these events. Use the {@code locationToIndex} * method to determine what cell was clicked. For example: * <pre> * MouseListener mouseListener = new MouseAdapter() { *     public void mouseClicked(MouseEvent e) { *         if (e.getClickCount() == 2) { *             int index = list.locationToIndex(e.getPoint()); *             System.out.println("Double clicked on Item " + index); *          } *     } * }; * list.addMouseListener(mouseListener); * </pre> * <p> * <strong>Warning:</strong> Swing is not thread safe. For more * information see <a * href="package-summary.html#threading">Swing's Threading * Policy</a>. * <p> * <strong>Warning:</strong> * Serialized objects of this class will not be compatible with * future Swing releases. The current serialization support is * appropriate for short term storage or RMI between applications running * the same version of Swing.  As of 1.4, support for long term storage * of all JavaBeans<sup><font size="-2">TM</font></sup> * has been added to the <code>java.beans</code> package. * Please see {@link java.beans.XMLEncoder}. * <p> * See <a href="http://java.sun.com/docs/books/tutorial/uiswing/components/list.html">How to Use Lists</a> * in <a href="http://java.sun.com/Series/Tutorial/index.html"><em>The Java Tutorial</em></a> * for further documentation. * Also see the article <a href="http://java.sun.com/products/jfc/tsc/tech_topics/jlist_1/jlist.html">Advanced JList Programming</a> * in <a href="http://java.sun.com/products/jfc/tsc"><em>The Swing Connection</em></a>. * <p> * @see ListModel * @see AbstractListModel * @see DefaultListModel * @see ListSelectionModel * @see DefaultListSelectionModel * @see ListCellRenderer * @see DefaultListCellRenderer * * @param <E> the type of the elements of this list * * @beaninfo *   attribute: isContainer false * description: A component which allows for the selection of one or more objects from a list. * * @author Hans Muller */public class JList<E> extends JComponent implements Scrollable, Accessible{    /**     * @see #getUIClassID     * @see #readObject     */    private static final String uiClassID = "ListUI";     /**     * Indicates a vertical layout of cells, in a single column;     * the default layout.     * @see #setLayoutOrientation     * @since 1.4     */    public static final int VERTICAL = 0;     /**     * Indicates a "newspaper style" layout with cells flowing vertically     * then horizontally.     * @see #setLayoutOrientation     * @since 1.4     */    public static final int VERTICAL_WRAP = 1;     /**     * Indicates a "newspaper style" layout with cells flowing horizontally     * then vertically.     * @see #setLayoutOrientation     * @since 1.4     */    public static final int HORIZONTAL_WRAP = 2;     private int fixedCellWidth = -1;    private int fixedCellHeight = -1;    private int horizontalScrollIncrement = -1;    private E prototypeCellValue;    private int visibleRowCount = 8;    private Color selectionForeground;    private Color selectionBackground;    private boolean dragEnabled;     private ListSelectionModel selectionModel;    private ListModel<E> dataModel;    private ListCellRenderer<? super E> cellRenderer;    private ListSelectionListener selectionListener;     /**     * How to lay out the cells; defaults to <code>VERTICAL</code>.     */    private int layoutOrientation;     /**     * The drop mode for this component.     */    private DropMode dropMode = DropMode.USE_SELECTION;     /**     * The drop location.     */    private transient DropLocation dropLocation;     /**     * A subclass of <code>TransferHandler.DropLocation</code> representing     * a drop location for a <code>JList</code>.     *     * @see #getDropLocation     * @since 1.6     */    public static final class DropLocation extends TransferHandler.DropLocation {        private final int index;        private final boolean isInsert;         private DropLocation(Point p, int index, boolean isInsert) {            super(p);            this.index = index;            this.isInsert = isInsert;        }         /**         * Returns the index where dropped data should be placed in the         * list. Interpretation of the value depends on the drop mode set on         * the associated component. If the drop mode is either         * <code>DropMode.USE_SELECTION</code> or <code>DropMode.ON</code>,         * the return value is an index of a row in the list. If the drop mode is         * <code>DropMode.INSERT</code>, the return value refers to the index         * where the data should be inserted. If the drop mode is         * <code>DropMode.ON_OR_INSERT</code>, the value of         * <code>isInsert()</code> indicates whether the index is an index         * of a row, or an insert index.         * <p>         * <code>-1</code> indicates that the drop occurred over empty space,         * and no index could be calculated.         *         * @return the drop index         */        public int getIndex() {            return index;        }         /**         * Returns whether or not this location represents an insert         * location.         *         * @return whether or not this is an insert location         */        public boolean isInsert() {            return isInsert;        }         /**         * Returns a string representation of this drop location.         * This method is intended to be used for debugging purposes,         * and the content and format of the returned string may vary         * between implementations.         *         * @return a string representation of this drop location         */        public String toString() {            return getClass().getName()                   + "[dropPoint=" + getDropPoint() + ","                   + "index=" + index + ","                   + "insert=" + isInsert + "]";        }    }     /**     * Constructs a {@code JList} that displays elements from the specified,     * {@code non-null}, model. All {@code JList} constructors delegate to     * this one.     * <p>     * This constructor registers the list with the {@code ToolTipManager},     * allowing for tooltips to be provided by the cell renderers.     *     * @param dataModel the model for the list     * @exception IllegalArgumentException if the model is {@code null}     */    public JList(ListModel<E> dataModel)    {        if (dataModel == null) {            throw new IllegalArgumentException("dataModel must be non null");        }         // Register with the ToolTipManager so that tooltips from the        // renderer show through.        ToolTipManager toolTipManager = ToolTipManager.sharedInstance();        toolTipManager.registerComponent(this);         layoutOrientation = VERTICAL;         this.dataModel = dataModel;        selectionModel = createSelectionModel();        setAutoscrolls(true);        setOpaque(true);        updateUI();    }      /**     * Constructs a <code>JList</code> that displays the elements in     * the specified array. This constructor creates a read-only model     * for the given array, and then delegates to the constructor that     * takes a {@code ListModel}.     * <p>     * Attempts to pass a {@code null} value to this method results in     * undefined behavior and, most likely, exceptions. The created model     * references the given array directly. Attempts to modify the array     * after constructing the list results in undefined behavior.     *     * @param  listData  the array of Objects to be loaded into the data model,     *                   {@code non-null}     */    public JList(final E[] listData)    {        this (            new AbstractListModel<E>() {                public int getSize() { return listData.length; }                public E getElementAt(int i) { return listData[i]; }            }        );    }      /**     * Constructs a <code>JList</code> that displays the elements in     * the specified <code>Vector</code>. This constructor creates a read-only     * model for the given {@code Vector}, and then delegates to the constructor     * that takes a {@code ListModel}.     * <p>     * Attempts to pass a {@code null} value to this method results in     * undefined behavior and, most likely, exceptions. The created model     * references the given {@code Vector} directly. Attempts to modify the     * {@code Vector} after constructing the list results in undefined behavior.     *     * @param  listData  the <code>Vector</code> to be loaded into the     *                   data model, {@code non-null}     */    public JList(final Vector<? extends E> listData) {        this (            new AbstractListModel<E>() {                public int getSize() { return listData.size(); }                public E getElementAt(int i) { return listData.elementAt(i); }            }        );    }      /**     * Constructs a <code>JList</code> with an empty, read-only, model.     */    public JList() {        this (            new AbstractListModel<E>() {              public int getSize() { return 0; }              public E getElementAt(int i) { throw new IndexOutOfBoundsException("No Data Model"); }            }        );    }  

Lines 1–500 of 3735.