KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > swing > JList


1 /*
2  * @(#)JList.java 1.112 04/05/05
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package javax.swing;
9
10 import java.awt.event.*;
11 import java.awt.*;
12
13 import java.util.Vector JavaDoc;
14 import java.util.Locale JavaDoc;
15
16 import java.beans.*;
17
18 import javax.swing.event.*;
19 import javax.accessibility.*;
20 import javax.swing.plaf.*;
21 import javax.swing.text.Position JavaDoc;
22
23 import java.io.ObjectOutputStream JavaDoc;
24 import java.io.ObjectInputStream JavaDoc;
25 import java.io.IOException JavaDoc;
26 import java.io.Serializable JavaDoc;
27
28
29 /**
30  * A component that allows the user to select one or more objects from a
31  * list. A separate model, <code>ListModel</code>, represents the contents
32  * of the list. It's easy to display an array or vector of objects, using
33  * a <code>JList</code> constructor that builds a <code>ListModel</code>
34  * instance for you:
35  * <pre>
36  * // Create a JList that displays the strings in data[]
37  *
38  * String[] data = {"one", "two", "three", "four"};
39  * JList dataList = new JList(data);
40  *
41  * // The value of the JList model property is an object that provides
42  * // a read-only view of the data. It was constructed automatically.
43  *
44  * for(int i = 0; i < dataList.getModel().getSize(); i++) {
45  * System.out.println(dataList.getModel().getElementAt(i));
46  * }
47  *
48  * // Create a JList that displays the superclass of JList.class.
49  * // We store the superclasses in a java.util.Vector.
50  *
51  * Vector superClasses = new Vector();
52  * Class rootClass = javax.swing.JList.class;
53  * for(Class cls = rootClass; cls != null; cls = cls.getSuperclass()) {
54  * superClasses.addElement(cls);
55  * }
56  * JList classList = new JList(superClasses);
57  * </pre>
58  * <p>
59  * <code>JList</code> doesn't support scrolling directly.
60  * To create a scrolling
61  * list you make the <code>JList</code> the viewport view of a
62  * <code>JScrollPane</code>. For example:
63  * <pre>
64  * JScrollPane scrollPane = new JScrollPane(dataList);
65  * // Or in two steps:
66  * JScrollPane scrollPane = new JScrollPane();
67  * scrollPane.getViewport().setView(dataList);
68  * </pre>
69  * <p>
70  * By default the <code>JList</code> selection model allows any
71  * combination of items to be selected at a time, using the constant
72  * <code>MULTIPLE_INTERVAL_SELECTION</code>.
73  * The selection state is actually managed
74  * by a separate delegate object, an instance of
75  * <code>ListSelectionModel</code>.
76  * However <code>JList</code> provides convenient properties for
77  * managing the selection.
78  * <pre>
79  * String[] data = {"one", "two", "three", "four"};
80  * JList dataList = new JList(data);
81  *
82  * dataList.setSelectedIndex(1); // select "two"
83  * dataList.getSelectedValue(); // returns "two"
84  * </pre>
85  * <p>
86  * The contents of a <code>JList</code> can be dynamic,
87  * in other words, the list elements can
88  * change value and the size of the list can change after the
89  * <code>JList</code> has
90  * been created. The <code>JList</code> observes changes in its model with a
91  * <code>swing.event.ListDataListener</code> implementation. A correct
92  * implementation of <code>ListModel</code> notifies
93  * it's listeners each time a change occurs. The changes are
94  * characterized by a <code>swing.event.ListDataEvent</code>, which identifies
95  * the range of list indices that have been modified, added, or removed.
96  * Simple dynamic-content <code>JList</code> applications can use the
97  * <code>DefaultListModel</code> class to store list elements. This class
98  * implements the <code>ListModel</code> interface and provides the
99  * <code>java.util.Vector</code> API as well. Applications that need to
100  * provide custom <code>ListModel</code> implementations can subclass
101  * <code>AbstractListModel</code>, which provides basic
102  * <code>ListDataListener</code> support. For example:
103  * <pre>
104  * // This list model has about 2^16 elements. Enjoy scrolling.
105  *
106  * <a name="prototype_example">
107  * ListModel bigData = new AbstractListModel() {
108  * public int getSize() { return Short.MAX_VALUE; }
109  * public Object getElementAt(int index) { return "Index " + index; }
110  * };
111  *
112  * JList bigDataList = new JList(bigData);
113  *
114  * // We don't want the JList implementation to compute the width
115  * // or height of all of the list cells, so we give it a string
116  * // that's as big as we'll need for any cell. It uses this to
117  * // compute values for the fixedCellWidth and fixedCellHeight
118  * // properties.
119  *
120  * bigDataList.setPrototypeCellValue("Index 1234567890");
121  * </pre>
122  * <p>
123  * <code>JList</code> uses a <code>java.awt.Component</code>, provided by
124  * a delegate called the
125  * <code>cellRendererer</code>, to paint the visible cells in the list.
126  * The cell renderer component is used like a "rubber stamp" to paint
127  * each visible row. Each time the <code>JList</code> needs to paint a cell
128  * it asks the cell renderer for the component, moves it into place
129  * using <code>setBounds()</code> and then draws it by calling its paint method.
130  * The default cell renderer uses a <code>JLabel</code> component to render
131  * the string value of each component. You can substitute your
132  * own cell renderer, using code like this:
133  * <pre>
134  * // Display an icon and a string for each object in the list.
135  *
136  * <a name="cellrenderer_example">
137  * class MyCellRenderer extends JLabel implements ListCellRenderer {
138  * final static ImageIcon longIcon = new ImageIcon("long.gif");
139  * final static ImageIcon shortIcon = new ImageIcon("short.gif");
140  *
141  * // This is the only method defined by ListCellRenderer.
142  * // We just reconfigure the JLabel each time we're called.
143  *
144  * public Component getListCellRendererComponent(
145  * JList list,
146  * Object value, // value to display
147  * int index, // cell index
148  * boolean isSelected, // is the cell selected
149  * boolean cellHasFocus) // the list and the cell have the focus
150  * {
151  * String s = value.toString();
152  * setText(s);
153  * setIcon((s.length() > 10) ? longIcon : shortIcon);
154  * if (isSelected) {
155  * setBackground(list.getSelectionBackground());
156  * setForeground(list.getSelectionForeground());
157  * }
158  * else {
159  * setBackground(list.getBackground());
160  * setForeground(list.getForeground());
161  * }
162  * setEnabled(list.isEnabled());
163  * setFont(list.getFont());
164  * setOpaque(true);
165  * return this;
166  * }
167  * }
168  *
169  * String[] data = {"one", "two", "three", "four"};
170  * JList dataList = new JList(data);
171  * dataList.setCellRenderer(new MyCellRenderer());
172  * </pre>
173  * <p>
174  * <code>JList</code> doesn't provide any special support for handling double or
175  * triple (or N) mouse clicks however it's easy to handle them using
176  * a <code>MouseListener</code>. Use the <code>JList</code> method
177  * <code>locationToIndex()</code> to
178  * determine what cell was clicked. For example:
179  * <pre>
180  * final JList list = new JList(dataModel);
181  * MouseListener mouseListener = new MouseAdapter() {
182  * public void mouseClicked(MouseEvent e) {
183  * if (e.getClickCount() == 2) {
184  * int index = list.locationToIndex(e.getPoint());
185  * System.out.println("Double clicked on Item " + index);
186  * }
187  * }
188  * };
189  * list.addMouseListener(mouseListener);
190  * </pre>
191  * Note that in this example the <code>dataList</code> is <code>final</code>
192  * because it's referred to by the anonymous <code>MouseListener</code> class.
193  * <p>
194  * <strong>Warning:</strong>
195  * Serialized objects of this class will not be compatible with
196  * future Swing releases. The current serialization support is
197  * appropriate for short term storage or RMI between applications running
198  * the same version of Swing. As of 1.4, support for long term storage
199  * of all JavaBeans<sup><font size="-2">TM</font></sup>
200  * has been added to the <code>java.beans</code> package.
201  * Please see {@link java.beans.XMLEncoder}.
202  *
203  * <p>
204  * See <a HREF="http://java.sun.com/docs/books/tutorial/uiswing/components/list.html">How to Use Lists</a>
205  * in <a HREF="http://java.sun.com/Series/Tutorial/index.html"><em>The Java Tutorial</em></a>
206  * for further documentation.
207  * Also see the article <a HREF="http://java.sun.com/products/jfc/tsc/tech_topics/jlist_1/jlist.html">Advanced JList Programming</a>
208  * in <a HREF="http://java.sun.com/products/jfc/tsc"><em>The Swing Connection</em></a>.
209  * <p>
210  * @see ListModel
211  * @see AbstractListModel
212  * @see DefaultListModel
213  * @see ListSelectionModel
214  * @see DefaultListSelectionModel
215  * @see ListCellRenderer
216  *
217  * @beaninfo
218  * attribute: isContainer false
219  * description: A component which allows for the selection of one or more objects from a list.
220  *
221  * @version 1.112 05/05/04
222  * @author Hans Muller
223  */

224 public class JList extends JComponent JavaDoc implements Scrollable JavaDoc, Accessible
225 {
226     /**
227      * @see #getUIClassID
228      * @see #readObject
229      */

230     private static final String JavaDoc uiClassID = "ListUI";
231
232     /**
233      * Indicates the default layout: one column of cells.
234      * @see #setLayoutOrientation
235      * @since 1.4
236      */

237     public static final int VERTICAL = 0;
238
239     /**
240      * Indicates "newspaper style" layout with the cells flowing vertically
241      * then horizontally.
242      * @see #setLayoutOrientation
243      * @since 1.4
244      */

245     public static final int VERTICAL_WRAP = 1;
246
247     /**
248      * Indicates "newspaper style" with the cells flowing horizontally
249      * then vertically.
250      * @see #setLayoutOrientation
251      * @since 1.4
252      */

253     public static final int HORIZONTAL_WRAP = 2;
254
255     private int fixedCellWidth = -1;
256     private int fixedCellHeight = -1;
257     private int horizontalScrollIncrement = -1;
258     private Object JavaDoc prototypeCellValue;
259     private int visibleRowCount = 8;
260     private Color selectionForeground;
261     private Color selectionBackground;
262     private boolean dragEnabled;
263
264     private ListSelectionModel JavaDoc selectionModel;
265     private ListModel JavaDoc dataModel;
266     private ListCellRenderer JavaDoc cellRenderer;
267     private ListSelectionListener selectionListener;
268
269     /**
270      * How to layout the cells, defaults to <code>VERTICAL</code>.
271      */

272     private int layoutOrientation;
273
274     /**
275      * Constructs a <code>JList</code> that displays the elements in the
276      * specified, non-<code>null</code> model.
277      * All <code>JList</code> constructors delegate to this one.
278      *
279      * @param dataModel the data model for this list
280      * @exception IllegalArgumentException if <code>dataModel</code>
281      * is <code>null</code>
282      */

283     public JList(ListModel JavaDoc dataModel)
284     {
285         if (dataModel == null) {
286             throw new IllegalArgumentException JavaDoc("dataModel must be non null");
287         }
288
289         // Register with the ToolTipManager so that tooltips from the
290
// renderer show through.
291
ToolTipManager JavaDoc toolTipManager = ToolTipManager.sharedInstance();
292         toolTipManager.registerComponent(this);
293         
294         layoutOrientation = VERTICAL;
295
296         this.dataModel = dataModel;
297         selectionModel = createSelectionModel();
298         setAutoscrolls(true);
299         setOpaque(true);
300         updateUI();
301     }
302
303
304     /**
305      * Constructs a <code>JList</code> that displays the elements in
306      * the specified array. This constructor just delegates to the
307      * <code>ListModel</code> constructor.
308      *
309      * @param listData the array of Objects to be loaded into the data model
310      */

311     public JList(final Object JavaDoc[] listData)
312     {
313         this (
314             new AbstractListModel JavaDoc() {
315                 public int getSize() { return listData.length; }
316                 public Object JavaDoc getElementAt(int i) { return listData[i]; }
317             }
318         );
319     }
320
321
322     /**
323      * Constructs a <code>JList</code> that displays the elements in
324      * the specified <code>Vector</code>. This constructor just
325      * delegates to the <code>ListModel</code> constructor.
326      *
327      * @param listData the <code>Vector</code> to be loaded into the
328      * data model
329      */

330     public JList(final Vector JavaDoc<?> listData) {
331         this (
332             new AbstractListModel JavaDoc() {
333                 public int getSize() { return listData.size(); }
334                 public Object JavaDoc getElementAt(int i) { return listData.elementAt(i); }
335             }
336         );
337     }
338
339
340     /**
341      * Constructs a <code>JList</code> with an empty model.
342      */

343     public JList() {
344         this (
345             new AbstractListModel JavaDoc() {
346               public int getSize() { return 0; }
347               public Object JavaDoc getElementAt(int i) { return "No Data Model"; }
348             }
349         );
350     }
351
352
353     /**
354      * Returns the look and feel (L&F) object that renders this component.
355      *
356      * @return the <code>ListUI</code> object that renders this component
357      */

358     public ListUI getUI() {
359         return (ListUI)ui;
360     }
361
362
363     /**
364      * Sets the look and feel (L&F) object that renders this component.
365      *
366      * @param ui the <code>ListUI</code> L&F object
367      * @see UIDefaults#getUI
368      * @beaninfo
369      * bound: true
370      * hidden: true
371      * attribute: visualUpdate true
372      * description: The UI object that implements the Component's LookAndFeel.
373      */

374     public void setUI(ListUI ui) {
375         super.setUI(ui);
376     }
377
378
379     /**
380      * Resets the UI property with the value from the current look and feel.
381      *
382      * @see UIManager#getUI
383      */

384     public void updateUI() {
385         setUI((ListUI)UIManager.getUI(this));
386         invalidate();
387     }
388
389
390     /**
391      * Returns the suffix used to construct the name of the look and feel
392      * (L&F) class used to render this component.
393      *
394      * @return the string "ListUI"
395      * @see JComponent#getUIClassID
396      * @see UIDefaults#getUI
397      */

398     public String JavaDoc getUIClassID() {
399         return uiClassID;
400     }
401
402
403     /* -----private-----
404      * This method is called by setPrototypeCellValue and setCellRenderer
405      * to update the fixedCellWidth and fixedCellHeight properties from the
406      * current value of prototypeCellValue (if it's non null).
407      * <p>
408      * This method sets fixedCellWidth and fixedCellHeight but does <b>not</b>
409      * generate PropertyChangeEvents for them.
410      *
411      * @see #setPrototypeCellValue
412      * @see #setCellRenderer
413      */

414     private void updateFixedCellSize()
415     {
416         ListCellRenderer JavaDoc cr = getCellRenderer();
417         Object JavaDoc value = getPrototypeCellValue();
418
419         if ((cr != null) && (value != null)) {
420             Component c = cr.getListCellRendererComponent(this, value, 0, false, false);
421
422             /* The ListUI implementation will add Component c to its private
423              * CellRendererPane however we can't assume that's already
424              * been done here. So we temporarily set the one "inherited"
425              * property that may affect the renderer components preferred size:
426              * its font.
427              */

428             Font f = c.getFont();
429             c.setFont(getFont());
430
431             Dimension d = c.getPreferredSize();
432             fixedCellWidth = d.width;
433             fixedCellHeight = d.height;
434
435             c.setFont(f);
436         }
437     }
438
439
440     /**
441      * Returns the cell width of the "prototypical cell" -- a cell used
442      * for the calculation of cell widths, because it has the same value
443      * as all other list items.
444      *
445      * @return the value of the <code>prototypeCellValue</code> property
446      * @see #setPrototypeCellValue
447      */

448     public Object JavaDoc getPrototypeCellValue() {
449         return prototypeCellValue;
450     }
451
452     /**
453      * Computes the <code>fixedCellWidth</code> and
454      * <code>fixedCellHeight</code> properties
455      * by configuring the <code>cellRenderer</code> to index equals
456      * zero for the specified value and then computing the renderer
457      * component's preferred size. These properties are useful when the
458      * list is too long to allow <code>JList</code> to compute the
459      * width/height of each cell and there is a single cell value that is
460      * known to occupy as much space as any of the others.
461      * <p>
462      * Note that we do set the <code>fixedCellWidth</code> and
463      * <code>fixedCellHeight</code> properties here but only a
464      * <code>prototypeCellValue PropertyChangeEvent</code> is fired.
465      * <p>
466      * To see an example which sets this property,
467      * see the <a href = #prototype_example>class description</a> above.
468      * <p>
469      * The default value of this property is <code>null</code>.
470      * <p>
471      * This is a JavaBeans bound property.
472      *
473      * @param prototypeCellValue the value on which to base
474      * <code>fixedCellWidth</code> and
475      * <code>fixedCellHeight</code>
476      * @see #getPrototypeCellValue
477      * @see #setFixedCellWidth
478      * @see #setFixedCellHeight
479      * @see JComponent#addPropertyChangeListener
480      * @beaninfo
481      * bound: true
482      * attribute: visualUpdate true
483      * description: The cell prototype value, used to compute cell width and height.
484      */

485     public void setPrototypeCellValue(Object JavaDoc prototypeCellValue) {
486         Object JavaDoc oldValue = this.prototypeCellValue;
487         this.prototypeCellValue = prototypeCellValue;
488
489         /* If the cellRenderer has changed and prototypeCellValue
490          * was set, then recompute fixedCellWidth and fixedCellHeight.
491          */

492
493         if ((prototypeCellValue != null) && !prototypeCellValue.equals(oldValue)) {
494             updateFixedCellSize();
495         }
496
497         firePropertyChange("prototypeCellValue", oldValue, prototypeCellValue);
498     }
499
500
501     /**
502      * Returns the fixed cell width value -- the value specified by setting
503      * the <code>fixedCellWidth</code> property, rather than that calculated
504      * from the list elements.
505      *
506      * @return the fixed cell width
507      * @see #setFixedCellWidth
508      */

509     public int getFixedCellWidth() {
510         return fixedCellWidth;
511     }
512
513     /**
514      * Sets the width of every cell in the list. If <code>width</code> is -1,
515      * cell widths are computed by applying <code>getPreferredSize</code>
516      * to the <code>cellRenderer</code> component for each list element.
517      * <p>
518      * The default value of this property is -1.
519      * <p>
520      * This is a JavaBeans bound property.
521      *
522      * @param width the width, in pixels, for all cells in this list
523      * @see #getPrototypeCellValue
524      * @see #setFixedCellWidth
525      * @see JComponent#addPropertyChangeListener
526      * @beaninfo
527      * bound: true
528      * attribute: visualUpdate true
529      * description: Defines a fixed cell width when greater than zero.
530      */

531     public void setFixedCellWidth(int width) {
532         int oldValue = fixedCellWidth;
533         fixedCellWidth = width;
534         firePropertyChange("fixedCellWidth", oldValue, fixedCellWidth);
535     }
536
537
538     /**
539      * Returns the fixed cell height value -- the value specified by setting
540      * the <code>fixedCellHeight</code> property,
541      * rather than that calculated from the list elements.
542      *
543      * @return the fixed cell height, in pixels
544      * @see #setFixedCellHeight
545      */

546     public int getFixedCellHeight() {
547         return fixedCellHeight;
548     }
549
550     /**
551      * Sets the height of every cell in the list. If <code>height</code>
552      * is -1, cell
553      * heights are computed by applying <code>getPreferredSize</code>
554      * to the <code>cellRenderer</code> component for each list element.
555      * <p>
556      * The default value of this property is -1.
557      * <p>
558      * This is a JavaBeans bound property.
559      *
560      * @param height an integer giving the height, in pixels, for all cells
561      * in this list
562      * @see #getPrototypeCellValue
563      * @see #setFixedCellWidth
564      * @see JComponent#addPropertyChangeListener
565      * @beaninfo
566      * bound: true
567      * attribute: visualUpdate true
568      * description: Defines a fixed cell height when greater than zero.
569      */

570     public void setFixedCellHeight(int height) {
571         int oldValue = fixedCellHeight;
572         fixedCellHeight = height;
573         firePropertyChange("fixedCellHeight", oldValue, fixedCellHeight);
574     }
575
576
577     /**
578      * Returns the object that renders the list items.
579      *
580      * @return the <code>ListCellRenderer</code>
581      * @see #setCellRenderer
582      */

583     public ListCellRenderer JavaDoc getCellRenderer() {
584         return cellRenderer;
585     }
586
587     /**
588      * Sets the delegate that's used to paint each cell in the list. If
589      * <code>prototypeCellValue</code> was set then the
590      * <code>fixedCellWidth</code> and <code>fixedCellHeight</code>
591      * properties are set as well. Only one <code>PropertyChangeEvent</code>
592      * is generated however - for the <code>cellRenderer</code> property.
593      * <p>
594      * The default value of this property is provided by the ListUI
595      * delegate, i.e. by the look and feel implementation.
596      * <p>
597      * To see an example which sets the cell renderer,
598      * see the <a href = #cellrenderer_example>class description</a> above.
599      * <p>
600      * This is a JavaBeans bound property.
601      *
602      * @param cellRenderer the <code>ListCellRenderer</code>
603      * that paints list cells
604      * @see #getCellRenderer
605      * @beaninfo
606      * bound: true
607      * attribute: visualUpdate true
608      * description: The component used to draw the cells.
609      */

610     public void setCellRenderer(ListCellRenderer JavaDoc cellRenderer) {
611         ListCellRenderer JavaDoc oldValue = this.cellRenderer;
612         this.cellRenderer = cellRenderer;
613
614         /* If the cellRenderer has changed and prototypeCellValue
615          * was set, then recompute fixedCellWidth and fixedCellHeight.
616          */

617         if ((cellRenderer != null) && !cellRenderer.equals(oldValue)) {
618             updateFixedCellSize();
619         }
620
621         firePropertyChange("cellRenderer", oldValue, cellRenderer);
622     }
623
624
625     /**
626      * Returns the selection foreground color.
627      *
628      * @return the <code>Color</code> object for the foreground property
629      * @see #setSelectionForeground
630      * @see #setSelectionBackground
631      */

632     public Color getSelectionForeground() {
633         return selectionForeground;
634     }
635
636
637     /**
638      * Sets the foreground color for selected cells. Cell renderers
639      * can use this color to render text and graphics for selected
640      * cells.
641      * <p>
642      * The default value of this property is defined by the look
643      * and feel implementation.
644      * <p>
645      * This is a JavaBeans bound property.
646      *
647      * @param selectionForeground the <code>Color</code> to use in the foreground
648      * for selected list items
649      * @see #getSelectionForeground
650      * @see #setSelectionBackground
651      * @see #setForeground
652      * @see #setBackground
653      * @see #setFont
654      * @beaninfo
655      * bound: true
656      * attribute: visualUpdate true
657      * description: The foreground color of selected cells.
658      */

659     public void setSelectionForeground(Color selectionForeground) {
660         Color oldValue = this.selectionForeground;
661         this.selectionForeground = selectionForeground;
662         firePropertyChange("selectionForeground", oldValue, selectionForeground);
663     }
664
665
666     /**
667      * Returns the background color for selected cells.
668      *
669      * @return the <code>Color</code> used for the background of
670      * selected list items
671      * @see #setSelectionBackground
672      * @see #setSelectionForeground
673      */

674     public Color getSelectionBackground() {
675         return selectionBackground;
676     }
677
678
679     /**
680      * Sets the background color for selected cells. Cell renderers
681      * can use this color to the fill selected cells.
682      * <p>
683      * The default value of this property is defined by the look
684      * and feel implementation.
685      * <p>
686      * This is a JavaBeans bound property.
687      *
688      * @param selectionBackground the <code>Color</code> to use for the
689      * background of selected cells
690      * @see #getSelectionBackground
691      * @see #setSelectionForeground
692      * @see #setForeground
693      * @see #setBackground
694      * @see #setFont
695      * @beaninfo
696      * bound: true
697      * attribute: visualUpdate true
698      * description: The background color of selected cells.
699      */

700     public void setSelectionBackground(Color selectionBackground) {
701         Color oldValue = this.selectionBackground;
702         this.selectionBackground = selectionBackground;
703         firePropertyChange("selectionBackground", oldValue, selectionBackground);
704     }
705
706
707     /**
708      * Returns the preferred number of visible rows.
709      *
710      * @return an integer indicating the preferred number of rows to display
711      * without using a scroll bar
712      * @see #setVisibleRowCount
713      */

714     public int getVisibleRowCount() {
715         return visibleRowCount;
716     }
717
718     /**
719      * Sets the preferred number of rows in the list that can be displayed
720      * without a scrollbar, as determined by the nearest
721      * <code>JViewport</code> ancestor, if any.
722      * The value of this property only affects the value of
723      * the <code>JList</code>'s <code>preferredScrollableViewportSize</code>.
724      * <p>
725      * The default value of this property is 8.
726      * <p>
727      * This is a JavaBeans bound property.
728      *
729      * @param visibleRowCount an integer specifying the preferred number of
730      * visible rows
731      * @see #getVisibleRowCount
732      * @see JComponent#getVisibleRect
733      * @see JViewport
734      * @beaninfo
735      * bound: true
736      * attribute: visualUpdate true
737      * description: The preferred number of cells that can be displayed without a scroll bar.
738      */

739     public void setVisibleRowCount(int visibleRowCount) {
740         int oldValue = this.visibleRowCount;
741         this.visibleRowCount = Math.max(0, visibleRowCount);
742         firePropertyChange("visibleRowCount", oldValue, visibleRowCount);
743     }
744
745
746     /**
747      * Returns <code>JList.VERTICAL</code> if the layout is a single
748      * column of cells, or <code>JList.VERTICAL_WRAP</code> if the layout
749      * is "newspaper style" with the content flowing vertically then
750      * horizontally or <code>JList.HORIZONTAL_WRAP</code> if the layout is
751      * "newspaper style" with the content flowing horizontally then
752      * vertically.
753      *
754      * @return the value of the layoutOrientation property
755      * @see #setLayoutOrientation
756      * @since 1.4
757      */

758     public int getLayoutOrientation() {
759     return layoutOrientation;
760     }
761
762
763     /**
764      * Defines the way list cells are layed out. Consider a <code>JList</code>
765      * with four cells, this can be layed out in one of the following ways:
766      * <pre>
767      * 0
768      * 1
769      * 2
770      * 3
771      * </pre>
772      * <pre>
773      * 0 1
774      * 2 3
775      * </pre>
776      * <pre>
777      * 0 2
778      * 1 3
779      * </pre>
780      * <p>
781      * These correspond to the following values:
782      *
783      * <table border="1"
784      * summary="Describes layouts VERTICAL, HORIZONTAL_WRAP, and VERTICAL_WRAP">
785      * <tr><th><p align="left">Value</p></th><th><p align="left">Description</p></th></tr>
786      * <tr><td><code>JList.VERTICAL</code>
787      * <td>The cells should be layed out vertically in one column.
788      * <tr><td><code>JList.HORIZONTAL_WRAP</code>
789      * <td>The cells should be layed out horizontally, wrapping to
790      * a new row as necessary. The number
791      * of rows to use will either be defined by
792      * <code>getVisibleRowCount</code> if > 0, otherwise the
793      * number of rows will be determined by the width of the
794      * <code>JList</code>.
795      * <tr><td><code>JList.VERTICAL_WRAP</code>
796      * <td>The cells should be layed out vertically, wrapping to a
797      * new column as necessary. The number
798      * of rows to use will either be defined by
799      * <code>getVisibleRowCount</code> if > 0, otherwise the
800      * number of rows will be determined by the height of the
801      * <code>JList</code>.
802      * </table>
803      * The default value of this property is <code>JList.VERTICAL</code>.
804      * <p>
805      * This will throw an <code>IllegalArgumentException</code> if
806      * <code>layoutOrientation</code> is not one of
807      * <code>JList.HORIZONTAL_WRAP</code> or <code>JList.VERTICAL</code> or
808      * <code>JList.VERTICAL_WRAP</code>
809      *
810      * @param layoutOrientation New orientation, one of
811      * <code>JList.HORIZONTAL_WRAP</code>, <code>JList.VERTICAL</code>
812      * or <code>JList.VERTICAL_WRAP</code>.
813      * @see #getLayoutOrientation
814      * @see #setVisibleRowCount
815      * @see #getScrollableTracksViewportHeight
816      * @since 1.4
817      * @beaninfo
818      * bound: true
819      * attribute: visualUpdate true
820      * description: Defines the way list cells are layed out.
821      * enum: VERTICAL JList.VERTICAL
822      * HORIZONTAL_WRAP JList.HORIZONTAL_WRAP
823      * VERTICAL_WRAP JList.VERTICAL_WRAP
824      */

825     public void setLayoutOrientation(int layoutOrientation) {
826     int oldValue = this.layoutOrientation;
827     switch (layoutOrientation) {
828     case VERTICAL:
829     case VERTICAL_WRAP:
830         case HORIZONTAL_WRAP:
831         this.layoutOrientation = layoutOrientation;
832         firePropertyChange("layoutOrientation", oldValue, layoutOrientation);
833         break;
834     default:
835             throw new IllegalArgumentException JavaDoc("layoutOrientation must be one of: VERTICAL, HORIZONTAL_WRAP or VERTICAL_WRAP");
836     }
837     }
838
839
840     /**
841      * Returns the index of the first visible cell. The cell considered
842      * to be "first" depends on the list's <code>componentOrientation</code>
843      * property. If the orientation is horizontal left-to-right, then
844      * the first visible cell is in the list's upper-left corner. If
845      * the orientation is horizontal right-to-left, then the first
846      * visible cell is in the list's upper-right corner. If nothing is
847      * visible or the list is empty, a -1 is returned. Note that the returned
848      * cell may only be partially visible.
849      *
850      * @return the index of the first visible cell
851      * @see #getLastVisibleIndex
852      * @see JComponent#getVisibleRect
853      */

854     public int getFirstVisibleIndex() {
855     Rectangle r = getVisibleRect();
856         int first;
857         if (this.getComponentOrientation().isLeftToRight()) {
858             first = locationToIndex(r.getLocation());
859         } else {
860             first = locationToIndex(new Point((r.x + r.width) - 1, r.y));
861         }
862     if (first != -1) {
863         Rectangle bounds = getCellBounds(first, first);
864         if (bounds != null) {
865                 SwingUtilities.computeIntersection(r.x, r.y, r.width, r.height, bounds);
866                 if (bounds.width == 0 || bounds.height == 0) {
867             first = -1;
868         }
869         }
870     }
871     return first;
872     }
873
874
875     /**
876      * Returns the index of the last visible cell. The cell considered
877      * to be "last" depends on the list's <code>componentOrientation</code>
878      * property. If the orientation is horizontal left-to-right, then
879      * the last visible cell is in the JList's lower-right corner. If
880      * the orientation is horizontal right-to-left, then the last visible
881      * cell is in the JList's lower-left corner. If nothing is visible
882      * or the list is empty, a -1 is returned. Note that the returned
883      * cell may only be partially visible.
884      *
885      * @return the index of the last visible cell
886      * @see #getFirstVisibleIndex
887      * @see JComponent#getVisibleRect
888      */

889     public int getLastVisibleIndex() {
890         boolean leftToRight = this.getComponentOrientation().isLeftToRight();
891         Rectangle r = getVisibleRect();
892         Point lastPoint;
893         if (leftToRight) {
894             lastPoint = new Point((r.x + r.width) - 1, (r.y + r.height) - 1);
895         } else {
896             lastPoint = new Point(r.x, (r.y + r.height) - 1);
897         }
898         int location = locationToIndex(lastPoint);
899
900         if (location != -1) {
901             Rectangle bounds = getCellBounds(location, location);
902
903             if (bounds != null) {
904                 SwingUtilities.computeIntersection(r.x, r.y, r.width, r.height, bounds);
905                 if (bounds.width == 0 || bounds.height == 0) {
906             // Try the lower left corner, and then go across checking
907
// each cell.
908
Point visibleLL = new Point(r.x, lastPoint.y);
909             int last;
910             int llIndex = -1;
911             int lrIndex = location;
912             location = -1;
913
914             do {
915             last = llIndex;
916             llIndex = locationToIndex(visibleLL);
917
918             if (llIndex != -1) {
919                 bounds = getCellBounds(llIndex, llIndex);
920                 if (llIndex != lrIndex && bounds != null &&
921                 bounds.contains(visibleLL)) {
922                 location = llIndex;
923                 visibleLL.x = bounds.x + bounds.width + 1;
924                 if (visibleLL.x >= lastPoint.x) {
925                                 // Past visible region, bail.
926
last = llIndex;
927                 }
928                 }
929                 else {
930                 last = llIndex;
931                 }
932             }
933             } while (llIndex != -1 && last != llIndex);
934         }
935             }
936         }
937         return location;
938     }
939
940
941     /**
942      * Scrolls the viewport to make the specified cell completely visible.
943      * Note, for this method to work, the <code>JList</code> must be
944      * displayed within a <code>JViewport</code>.
945      *
946      * @param index the index of the cell to make visible
947      * @see JComponent#scrollRectToVisible
948      * @see #getVisibleRect
949      */

950     public void ensureIndexIsVisible(int index) {
951         Rectangle cellBounds = getCellBounds(index, index);
952         if (cellBounds != null) {
953             scrollRectToVisible(cellBounds);
954         }
955     }
956
957     /**
958      * Sets the <code>dragEnabled</code> property,
959      * which must be <code>true</code> to enable
960      * automatic drag handling (the first part of drag and drop)
961      * on this component.
962      * The <code>transferHandler</code> property needs to be set
963      * to a non-<code>null</code> value for the drag to do
964      * anything. The default value of the <code>dragEnabled</code>
965      * property
966      * is <code>false</code>.
967      *
968      * <p>
969      *
970      * When automatic drag handling is enabled,
971      * most look and feels begin a drag-and-drop operation
972      * whenever the user presses the mouse button over a selection
973      * and then moves the mouse a few pixels.
974      * Setting this property to <code>true</code>
975      * can therefore have a subtle effect on
976      * how selections behave.
977      *
978      * <p>
979      *
980      * Some look and feels might not support automatic drag and drop;
981      * they will ignore this property. You can work around such
982      * look and feels by modifying the component
983      * to directly call the <code>exportAsDrag</code> method of a
984      * <code>TransferHandler</code>.
985      *
986      * @param b the value to set the <code>dragEnabled</code> property to
987      * @exception HeadlessException if
988      * <code>b</code> is <code>true</code> and
989      * <code>GraphicsEnvironment.isHeadless()</code>
990      * returns <code>true</code>
991      * @see java.awt.GraphicsEnvironment#isHeadless
992      * @see #getDragEnabled
993      * @see #setTransferHandler
994      * @see TransferHandler
995      * @since 1.4
996      *
997      * @beaninfo
998      * description: determines whether automatic drag handling is enabled
999      * bound: false
1000     */

1001    public void setDragEnabled(boolean b) {
1002        if (b && GraphicsEnvironment.isHeadless()) {
1003            throw new HeadlessException();
1004        }
1005    dragEnabled = b;
1006    }
1007
1008    /**
1009     * Gets the <code>dragEnabled</code> property.
1010     *
1011     * @return the value of the <code>dragEnabled</code> property
1012     * @see #setDragEnabled
1013     * @since 1.4
1014     */

1015    public boolean getDragEnabled() {
1016    return dragEnabled;
1017    }
1018
1019    /**
1020     * Returns the next list element that starts with
1021     * a prefix.
1022     *
1023     * @param prefix the string to test for a match
1024     * @param startIndex the index for starting the search
1025     * @param bias the search direction, either
1026     * Position.Bias.Forward or Position.Bias.Backward.
1027     * @return the index of the next list element that
1028     * starts with the prefix; otherwise -1
1029     * @exception IllegalArgumentException if prefix is null
1030     * or startIndex is out of bounds
1031     * @since 1.4
1032     */

1033    public int getNextMatch(String JavaDoc prefix, int startIndex, Position.Bias JavaDoc bias) {
1034    ListModel JavaDoc model = getModel();
1035    int max = model.getSize();
1036    if (prefix == null) {
1037        throw new IllegalArgumentException JavaDoc();
1038    }
1039    if (startIndex < 0 || startIndex >= max) {
1040        throw new IllegalArgumentException JavaDoc();
1041    }
1042    prefix = prefix.toUpperCase();
1043
1044    // start search from the next element after the selected element
1045
int increment = (bias == Position.Bias.Forward) ? 1 : -1;
1046    int index = startIndex;
1047    do {
1048        Object JavaDoc o = model.getElementAt(index);
1049        
1050        if (o != null) {
1051        String JavaDoc string;
1052        
1053        if (o instanceof String JavaDoc) {
1054            string = ((String JavaDoc)o).toUpperCase();
1055        }
1056        else {
1057            string = o.toString();
1058         &nb