OSDN Git Service

Add NIOS2 support. Code from SourceyG++.
[pf3gnuchains/gcc-fork.git] / libjava / classpath / javax / swing / JList.java
1 /* JList.java --
2    Copyright (C) 2002, 2003, 2004, 2005, 2006,  Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37
38
39 package javax.swing;
40
41 import gnu.java.lang.CPStringBuilder;
42
43 import java.awt.Color;
44 import java.awt.Component;
45 import java.awt.ComponentOrientation;
46 import java.awt.Cursor;
47 import java.awt.Dimension;
48 import java.awt.Font;
49 import java.awt.FontMetrics;
50 import java.awt.Point;
51 import java.awt.Rectangle;
52 import java.awt.event.FocusListener;
53 import java.beans.PropertyChangeEvent;
54 import java.beans.PropertyChangeListener;
55 import java.util.Locale;
56 import java.util.Vector;
57
58 import javax.accessibility.Accessible;
59 import javax.accessibility.AccessibleComponent;
60 import javax.accessibility.AccessibleContext;
61 import javax.accessibility.AccessibleRole;
62 import javax.accessibility.AccessibleSelection;
63 import javax.accessibility.AccessibleState;
64 import javax.accessibility.AccessibleStateSet;
65 import javax.swing.event.ListDataEvent;
66 import javax.swing.event.ListDataListener;
67 import javax.swing.event.ListSelectionEvent;
68 import javax.swing.event.ListSelectionListener;
69 import javax.swing.plaf.ListUI;
70 import javax.swing.text.Position;
71
72 /**
73  * <p>This class is a facade over three separate objects: {@link
74  * javax.swing.ListModel}, {@link javax.swing.ListSelectionModel} and
75  * {@link javax.swing.plaf.ListUI}. The facade represents a unified "list"
76  * concept, with independently replacable (possibly client-provided) models
77  * for its contents and its current selection. In addition, each element in
78  * the list is rendered via a strategy class {@link
79  * javax.swing.ListCellRenderer}.</p>
80  *
81  * <p>Lists have many properties, some of which are stored in this class
82  * while others are delegated to the list's model or selection. The
83  * following properties are available:</p>
84  *
85  * <table>
86  * <tr><th>Property                       </th><th>Stored in</th><th>Bound?</th></tr>
87  * <tr><td>accessibleContext              </td><td>list     </td><td>no    </td></tr>
88  * <tr><td>anchorSelectionIndex           </td><td>selection</td><td>no    </td></tr>
89  * <tr><td>cellRenderer                   </td><td>list     </td><td>yes   </td></tr>
90  * <tr><td>dragEnabled                    </td><td>list     </td><td>no    </td></tr>
91  * <tr><td>firstVisibleIndex              </td><td>list     </td><td>no    </td></tr>
92  * <tr><td>fixedCellHeight                </td><td>list     </td><td>yes   </td></tr>
93  * <tr><td>fixedCellWidth                 </td><td>list     </td><td>yes   </td></tr>
94  * <tr><td>lastVisibleIndex               </td><td>list     </td><td>no    </td></tr>
95  * <tr><td>layoutOrientation              </td><td>list     </td><td>yes   </td></tr>
96  * <tr><td>leadSelectionIndex             </td><td>selection</td><td>no    </td></tr>
97  * <tr><td>maxSelectionIndex              </td><td>selection</td><td>no    </td></tr>
98  * <tr><td>minSelectionIndex              </td><td>selection</td><td>no    </td></tr>
99  * <tr><td>model                          </td><td>list     </td><td>yes   </td></tr>
100  * <tr><td>opaque                         </td><td>list     </td><td>no    </td></tr>
101  * <tr><td>preferredScrollableViewportSize</td><td>list     </td><td>no    </td></tr>
102  * <tr><td>prototypeCellValue             </td><td>list     </td><td>yes   </td></tr>
103  * <tr><td>scrollableTracksViewportHeight </td><td>list     </td><td>no    </td></tr>
104  * <tr><td>scrollableTracksViewportWidth  </td><td>list     </td><td>no    </td></tr>
105  * <tr><td>selectedIndex                  </td><td>selection</td><td>no    </td></tr>
106  * <tr><td>selectedIndices                </td><td>selection</td><td>no    </td></tr>
107  * <tr><td>selectedValue                  </td><td>model    </td><td>no    </td></tr>
108  * <tr><td>selectedValues                 </td><td>model    </td><td>no    </td></tr>
109  * <tr><td>selectionBackground            </td><td>list     </td><td>yes   </td></tr>
110  * <tr><td>selectionEmpty                 </td><td>selection</td><td>no    </td></tr>
111  * <tr><td>selectionForeground            </td><td>list     </td><td>yes   </td></tr>
112  * <tr><td>selectionMode                  </td><td>selection</td><td>no    </td></tr>
113  * <tr><td>selectionModel                 </td><td>list     </td><td>yes   </td></tr>
114  * <tr><td>UI                             </td><td>list     </td><td>yes   </td></tr>
115  * <tr><td>UIClassID                      </td><td>list     </td><td>no    </td></tr>
116  * <tr><td>valueIsAdjusting               </td><td>list     </td><td>no    </td></tr>
117  * <tr><td>visibleRowCount                </td><td>list     </td><td>no    </td></tr>
118  * </table> 
119  *
120  * @author Graydon Hoare (graydon@redhat.com)
121  */
122
123 public class JList extends JComponent implements Accessible, Scrollable
124 {
125
126   /**
127    * Provides accessibility support for <code>JList</code>.
128    */
129   protected class AccessibleJList extends AccessibleJComponent
130     implements AccessibleSelection, PropertyChangeListener,
131                ListSelectionListener, ListDataListener
132   {
133
134     /**
135      * Provides accessibility support for list elements in <code>JList</code>s.
136      */
137     protected class AccessibleJListChild extends AccessibleContext
138       implements Accessible, AccessibleComponent
139     {
140
141       /**
142        * The parent list.
143        */
144       JList parent;
145
146       /**
147        * The index in the list for that child.
148        */
149       int listIndex;
150
151       /**
152        * The cursor for this list child.
153        */
154       // TODO: Testcases show that this class somehow stores state about the
155       // cursor. I cannot make up though how that could affect
156       // the actual list.
157       Cursor cursor = Cursor.getDefaultCursor();
158
159       /**
160        * Creates a new instance of <code>AccessibleJListChild</code>.
161        *
162        * @param list the list of which this is an accessible child
163        * @param index the list index for this child
164        */
165       public AccessibleJListChild(JList list, int index)
166       {
167         parent = list;
168         listIndex = index;
169       }
170
171       /**
172        * Returns the accessible context of this object. Returns
173        * <code>this</code> since <code>AccessibleJListChild</code>s are their
174        * own accessible contexts.
175        *
176        * @return the accessible context of this object, <code>this</code>
177        */
178       public AccessibleContext getAccessibleContext()
179       {
180         return this;
181       }
182
183       /**
184        * Returns the background color for this list child. This returns the
185        * background of the <code>JList</code> itself since the background
186        * cannot be set on list children individually
187        *
188        * @return the background color for this list child
189        */
190       public Color getBackground()
191       {
192         return parent.getBackground();
193       }
194
195       /**
196        * Calling this method has no effect, since the background color cannot be
197        * set on list children individually.
198        *
199        * @param color not used here.
200        */
201       public void setBackground(Color color)
202       {
203         // Calling this method has no effect, since the background color cannot
204         // be set on list children individually.
205       }
206
207       /**
208        * Returns the foreground color for this list child. This returns the
209        * background of the <code>JList</code> itself since the foreground
210        * cannot be set on list children individually.
211        *
212        * @return the background color for this list child
213        */
214       public Color getForeground()
215       {
216         return parent.getForeground();
217       }
218
219       /**
220        * Calling this method has no effect, since the foreground color cannot be
221        * set on list children individually.
222        *
223        * @param color not used here.
224        */
225       public void setForeground(Color color)
226       {
227         // Calling this method has no effect, since the foreground color cannot
228         // be set on list children individually.
229       }
230
231       /**
232        * Returns the cursor for this list child.
233        *
234        * @return the cursor for this list child
235        */
236       public Cursor getCursor()
237       {
238         // TODO: Testcases show that this method returns the cursor that has
239         // been set by setCursor. I cannot make up though how that could affect
240         // the actual list.
241         return cursor;
242       }
243
244       /**
245        * Sets the cursor for this list child.
246        */
247       public void setCursor(Cursor cursor)
248       {
249         this.cursor = cursor;
250         // TODO: Testcases show that this method returns the cursor that has
251         // been set by setCursor. I cannot make up though how that could affect
252         // the actual list.
253       }
254
255       /**
256        * Returns the font of the <code>JList</code> since it is not possible to
257        * set fonts for list children individually.
258        *
259        * @return the font of the <code>JList</code>
260        */
261       public Font getFont()
262       {
263         return parent.getFont();
264       }
265
266       /**
267        * Does nothing since it is not possible to set the font on list children
268        * individually.
269        *
270        * @param font not used here
271        */
272       public void setFont(Font font)
273       {
274         // Does nothing since it is not possible to set the font on list
275         // children individually.
276       }
277
278       /**
279        * Returns the font metrics for the specified font. This method forwards
280        * to the parent <code>JList</code>. 
281        *
282        * @param font the font for which the font metrics is queried
283        *
284        * @return the font metrics for the specified font
285        */
286       public FontMetrics getFontMetrics(Font font)
287       {
288         return parent.getFontMetrics(font);
289       }
290
291       /**
292        * Returns <code>true</code> if the parent <code>JList</code> is enabled,
293        * <code>false</code> otherwise. The list children cannot have an enabled
294        * flag set individually.
295        *
296        * @return <code>true</code> if the parent <code>JList</code> is enabled,
297        *         <code>false</code> otherwise
298        */
299       public boolean isEnabled()
300       {
301         return parent.isEnabled();
302       }
303
304       /**
305        * Does nothing since the enabled flag cannot be set for list children
306        * individually.
307        *
308        * @param b not used here
309        */
310       public void setEnabled(boolean b)
311       {
312         // Does nothing since the enabled flag cannot be set for list children
313         // individually.
314       }
315
316       /**
317        * Returns <code>true</code> if this list child is visible,
318        * <code>false</code> otherwise. The value of this property depends
319        * on {@link JList#getFirstVisibleIndex()} and
320        * {@link JList#getLastVisibleIndex()}.
321        *
322        * @return <code>true</code> if this list child is visible,
323        *         <code>false</code> otherwise
324        */
325       public boolean isVisible()
326       {
327         return listIndex >= parent.getFirstVisibleIndex()
328                && listIndex <= parent.getLastVisibleIndex();
329       }
330
331       /**
332        * The value of the visible property cannot be modified, so this method
333        * does nothing.
334        *
335        * @param b not used here
336        */
337       public void setVisible(boolean b)
338       {
339         // The value of the visible property cannot be modified, so this method
340         // does nothing.
341       }
342
343       /**
344        * Returns <code>true</code> if this list child is currently showing on
345        * screen and <code>false</code> otherwise. The list child is showing if
346        * it is visible and if it's parent JList is currently showing.
347        *
348        * @return <code>true</code> if this list child is currently showing on
349        *         screen and <code>false</code> otherwise
350        */
351       public boolean isShowing()
352       {
353         return isVisible() && parent.isShowing();
354       }
355
356       /**
357        * Returns <code>true</code> if this list child covers the screen location
358        * <code>point</code> (relative to the <code>JList</code> coordinate
359        * system, <code>false</code> otherwise.
360        *
361        * @return <code>true</code> if this list child covers the screen location
362        *         <code>point</code> , <code>false</code> otherwise
363        */
364       public boolean contains(Point point)
365       {
366         return getBounds().contains(point);
367       }
368
369       /**
370        * Returns the absolute screen location of this list child.
371        *
372        * @return the absolute screen location of this list child
373        */
374       public Point getLocationOnScreen()
375       {
376         Point loc = getLocation();
377         SwingUtilities.convertPointToScreen(loc, parent);
378         return loc;
379       }
380
381       /**
382        * Returns the screen location of this list child relative to it's parent.
383        *
384        * @return the location of this list child relative to it's parent
385        *
386        * @see JList#indexToLocation(int)
387        */
388       public Point getLocation()
389       {
390         return parent.indexToLocation(listIndex);
391       }
392
393       /**
394        * Does nothing since the screen location cannot be set on list children
395        * explictitly.
396        *
397        * @param point not used here
398        */
399       public void setLocation(Point point)
400       {
401         // Does nothing since the screen location cannot be set on list children
402         // explictitly.
403       }
404
405       /**
406        * Returns the bounds of this list child.
407        *
408        * @return the bounds of this list child
409        *
410        * @see JList#getCellBounds(int, int)
411        */
412       public Rectangle getBounds()
413       {
414         return parent.getCellBounds(listIndex, listIndex);
415       }
416
417       /**
418        * Does nothing since the bounds cannot be set on list children
419        * individually.
420        *
421        * @param rectangle not used here
422        */
423       public void setBounds(Rectangle rectangle)
424       {
425         // Does nothing since the bounds cannot be set on list children
426         // individually.
427       }
428
429       /**
430        * Returns the size of this list child.
431        *
432        * @return the size of this list child
433        */
434       public Dimension getSize()
435       {
436         Rectangle b = getBounds();
437         return b.getSize();
438       }
439
440       /**
441        * Does nothing since the size cannot be set on list children
442        * individually.
443        *
444        * @param dimension not used here
445        */
446       public void setSize(Dimension dimension)
447       {
448         // Does nothing since the size cannot be set on list children
449         // individually.
450       }
451
452       /**
453        * Returns <code>null</code> because list children do not have children
454        * themselves
455        *
456        * @return <code>null</code>
457        */
458       public Accessible getAccessibleAt(Point point)
459       {
460         return null;
461       }
462
463       /**
464        * Returns <code>true</code> since list children are focus traversable.
465        *
466        * @return true
467        */
468       public boolean isFocusTraversable()
469       {
470         // TODO: Is this 100% ok?
471         return true;
472       }
473
474       /**
475        * Requests focus on the parent list. List children cannot request focus
476        * individually.
477        */
478       public void requestFocus()
479       {
480         // TODO: Is this 100% ok?
481         parent.requestFocus();
482       }
483
484       /**
485        * Adds a focus listener to the parent list. List children do not have
486        * their own focus management.
487        *
488        * @param listener the focus listener to add
489        */
490       public void addFocusListener(FocusListener listener)
491       {
492         // TODO: Is this 100% ok?
493         parent.addFocusListener(listener);
494       }
495
496       /**
497        * Removes a focus listener from the parent list. List children do not
498        * have their own focus management.
499        *
500        * @param listener the focus listener to remove
501        */
502       public void removeFocusListener(FocusListener listener)
503       {
504         // TODO: Is this 100%
505         parent.removeFocusListener(listener);
506       }
507
508       /**
509        * Returns the accessible role of this list item, which is
510        * {@link AccessibleRole#LABEL}.
511        *
512        * @return {@link AccessibleRole#LABEL}
513        */
514       public AccessibleRole getAccessibleRole()
515       {
516         return AccessibleRole.LABEL;
517       }
518
519       /**
520        * Returns the accessible state set of this list item.
521        *
522        * @return the accessible state set of this list item
523        */
524       public AccessibleStateSet getAccessibleStateSet()
525       {
526         AccessibleStateSet states = new AccessibleStateSet();
527         if (isVisible())
528           states.add(AccessibleState.VISIBLE);
529         if (isShowing())
530           states.add(AccessibleState.SHOWING);
531         if (isFocusTraversable())
532           states.add(AccessibleState.FOCUSABLE);
533         // TODO: How should the active state be handled? The API docs
534         // suggest that this state is set on the activated list child,
535         // that is the one that is drawn with a box. However, I don't know how
536         // to implement this.
537
538         // TODO: We set the selectable state here because list children are
539         // selectable. Is there a way to disable single children?
540         if (parent.isEnabled())
541           states.add(AccessibleState.SELECTABLE);
542  
543         if (parent.isSelectedIndex(listIndex))
544           states.add(AccessibleState.SELECTED);
545
546         // TODO: Handle more states here?
547         return states;
548       }
549
550       /**
551        * Returns the index of this list child within it's parent list.
552        *
553        * @return the index of this list child within it's parent list
554        */
555       public int getAccessibleIndexInParent()
556       {
557         return listIndex;
558       }
559
560       /**
561        * Returns <code>0</code> since list children don't have children
562        * themselves.
563        *
564        * @return <code>0</code>
565        */
566       public int getAccessibleChildrenCount()
567       {
568         return 0;
569       }
570
571       /**
572        * Returns <code>null</code> since list children don't have children
573        * themselves.
574        *
575        * @return <code>null</code>
576        */
577       public Accessible getAccessibleChild(int i)
578       {
579         return null;
580       }
581
582       /**
583        * Returns the locale of this component. This call is forwarded to the
584        * parent list since list children don't have a separate locale setting.
585        *
586        * @return the locale of this component
587        */
588       public Locale getLocale()
589       {
590         return parent.getLocale();
591       }
592
593       /**
594        * This method does
595        * nothing, list children are transient accessible objects which means
596        * that they don't fire property change events.
597        *
598        * @param l not used here
599        */
600       public void addPropertyChangeListener(PropertyChangeListener l)
601       {
602         // Do nothing here.
603       }
604
605       /**
606        * This method does
607        * nothing, list children are transient accessible objects which means
608        * that they don't fire property change events.
609        *
610        * @param l not used here
611        */
612       public void removePropertyChangeListener(PropertyChangeListener l)
613       {
614         // Do nothing here.
615       }
616       
617       // TODO: Implement the remaining methods of this class.
618     }
619     
620     /**
621      * Create a new AccessibleJList.
622      */
623     public AccessibleJList()
624     {
625       // Nothing to do here.
626     }
627
628     /**
629      * Returns the number of selected accessible children.
630      *
631      * @return the number of selected accessible children
632      */
633     public int getAccessibleSelectionCount()
634     {
635       return getSelectedIndices().length;
636     }
637
638     /**
639      * Returns the n-th selected accessible child.
640      *
641      * @param n the index of the selected child to return
642      *
643      * @return the n-th selected accessible child
644      */
645     public Accessible getAccessibleSelection(int n)
646     {
647       return new AccessibleJListChild(JList.this, getSelectedIndices()[n]);
648     }
649
650     /**
651      * Returns <code>true</code> if the n-th child is selected,
652      * <code>false</code> otherwise.
653      *
654      * @param n the index of the child of which the selected state is queried
655      *
656      * @return <code>true</code> if the n-th child is selected,
657      *         <code>false</code> otherwise
658      */
659     public boolean isAccessibleChildSelected(int n)
660     {
661       return isSelectedIndex(n);
662     }
663
664     /**
665      * Adds the accessible item with the specified index to the selected items.
666      * If multiple selections are supported, the item is added to the selection,
667      * otherwise the item replaces the current selection.
668      *
669      * @param i the index of the item to add to the selection
670      */
671     public void addAccessibleSelection(int i)
672     {
673       addSelectionInterval(i, i);
674     }
675
676     /**
677      * Removes the accessible item with the specified index to the selection.
678      *
679      * @param i the index of the item to be removed from the selection
680      */
681     public void removeAccessibleSelection(int i)
682     {
683       removeSelectionInterval(i, i);
684     }
685
686     /**
687      * Remove all selection items from the selection.
688      */
689     public void clearAccessibleSelection()
690     {
691       clearSelection();
692     }
693
694     /**
695      * Selects all items if multiple selections are supported.
696      * Otherwise do nothing.
697      */
698     public void selectAllAccessibleSelection()
699     {
700       addSelectionInterval(0, getModel().getSize());
701     }
702
703     /**
704      * Receices notification when the list selection is changed. This method
705      * fires two property change events, the first with
706      * {@link AccessibleContext#ACCESSIBLE_VISIBLE_DATA_PROPERTY} and the second
707      * with {@link AccessibleContext#ACCESSIBLE_SELECTION_PROPERTY}.
708      *
709      * @param event the list selection event
710      */
711     public void valueChanged(ListSelectionEvent event)
712     {
713       firePropertyChange(ACCESSIBLE_VISIBLE_DATA_PROPERTY, Boolean.FALSE,
714                          Boolean.TRUE);
715       firePropertyChange(ACCESSIBLE_SELECTION_PROPERTY, Boolean.FALSE,
716                          Boolean.TRUE);
717     }
718
719     /**
720      * Receives notification when items have changed in the
721      * <code>JList</code>. This method fires a property change event with
722      * {@link AccessibleContext#ACCESSIBLE_VISIBLE_DATA_PROPERTY}.
723      *
724      * @param event the list data event
725      */
726     public void contentsChanged(ListDataEvent event)
727     {
728       firePropertyChange(ACCESSIBLE_VISIBLE_DATA_PROPERTY, Boolean.FALSE,
729                          Boolean.TRUE);
730     }
731
732     /**
733      * Receives notification when items are inserted into the
734      * <code>JList</code>. This method fires a property change event with
735      * {@link AccessibleContext#ACCESSIBLE_VISIBLE_DATA_PROPERTY}.
736      *
737      * @param event the list data event
738      */
739     public void intervalAdded(ListDataEvent event)
740     {
741       firePropertyChange(ACCESSIBLE_VISIBLE_DATA_PROPERTY, Boolean.FALSE,
742                          Boolean.TRUE);
743     }
744
745     /**
746      * Receives notification when items are removed from the
747      * <code>JList</code>. This method fires a property change event with
748      * {@link AccessibleContext#ACCESSIBLE_VISIBLE_DATA_PROPERTY}.
749      *
750      * @param event the list data event
751      */
752     public void intervalRemoved(ListDataEvent event)
753     {
754       firePropertyChange(ACCESSIBLE_VISIBLE_DATA_PROPERTY, Boolean.FALSE,
755                          Boolean.TRUE);
756     }
757
758
759     /**
760      * Receives notification about changes of the <code>JList</code>'s
761      * properties. This is used to re-register this object as listener to
762      * the data model and selection model when the data model or selection model
763      * changes.
764      *
765      * @param e the property change event
766      */
767     public void propertyChange(PropertyChangeEvent e)
768     {
769       String propertyName = e.getPropertyName();
770       if (propertyName.equals("model"))
771         {
772           ListModel oldModel = (ListModel) e.getOldValue();
773           oldModel.removeListDataListener(this);
774           ListModel newModel = (ListModel) e.getNewValue();
775           newModel.addListDataListener(this);
776         }
777       else if (propertyName.equals("selectionModel"))
778         {
779           ListSelectionModel oldModel = (ListSelectionModel) e.getOldValue();
780           oldModel.removeListSelectionListener(this);
781           ListSelectionModel newModel = (ListSelectionModel) e.getNewValue();
782           oldModel.addListSelectionListener(this);
783         }
784     }
785
786     /**
787      * Return the state set of the <code>JList</code>.
788      *
789      * @return the state set of the <code>JList</code>
790      */
791     public AccessibleStateSet getAccessibleStateSet()
792     {
793       // TODO: Figure out if there is possibly more state that must be
794       // handled here.
795       AccessibleStateSet s = super.getAccessibleStateSet();
796       if (getSelectionMode() != ListSelectionModel.SINGLE_SELECTION)
797         s.add(AccessibleState.MULTISELECTABLE);
798       return s;
799     }
800
801     /**
802      * Returns the accessible role for <code>JList</code>,
803      * {@link AccessibleRole#LIST}.
804      *
805      * @return the accessible role for <code>JList</code>
806      */
807     public AccessibleRole getAccessibleRole()
808     {
809       return AccessibleRole.LIST;
810     }
811
812     /**
813      * Returns the accessible child at the visual location <code>p</code>
814      * (relative to the upper left corner of the <code>JList</code>). If there
815      * is no child at that location, this returns <code>null</code>.
816      *
817      * @param p the screen location for which to return the accessible child
818      *
819      * @return the accessible child at the specified location, or
820      *         <code>null</code> if there is no child at that location
821      */
822     public Accessible getAccessibleAt(Point p)
823     {
824       int childIndex = locationToIndex(p);
825       return getAccessibleChild(childIndex);
826     }
827
828     /**
829      * Returns the number of accessible children in the <code>JList</code>.
830      *
831      * @return the number of accessible children in the <code>JList</code>
832      */
833     public int getAccessibleChildrenCount()
834     {
835       return getModel().getSize();
836     }
837
838     /**
839      * Returns the n-th accessible child of this <code>JList</code>. This will
840      * be an instance of {@link AccessibleJListChild}. If there is no child
841      * at that index, <code>null</code> is returned.
842      *
843      * @param n the index of the child to return
844      *
845      * @return the n-th accessible child of this <code>JList</code>
846      */
847     public Accessible getAccessibleChild(int n)
848     {
849       if (getModel().getSize() <= n)
850         return null;
851       return new AccessibleJListChild(JList.this, n);
852     }
853   }
854
855   private static final long serialVersionUID = 4406629526391098046L;
856
857   /** 
858    * Constant value used in "layoutOrientation" property. This value means
859    * that cells are laid out in a single vertical column. This is the default. 
860    */
861   public static final int VERTICAL = 0;
862
863   /** 
864    * Constant value used in "layoutOrientation" property. This value means
865    * that cells are laid out in multiple columns "newspaper style", filling
866    * vertically first, then horizontally. 
867    */
868   public static final int VERTICAL_WRAP = 1;
869   
870   /** 
871    * Constant value used in "layoutOrientation" property. This value means
872    * that cells are laid out in multiple columns "newspaper style",
873    * filling horizontally first, then vertically. 
874    */
875   public static final int HORIZONTAL_WRAP = 2;
876
877   /**
878    * This property indicates whether "drag and drop" functions are enabled
879    * on the list.
880    */
881   boolean dragEnabled;
882
883   /** This property provides a strategy for rendering cells in the list. */
884   ListCellRenderer cellRenderer;
885
886   /**
887    * This property indicates an fixed width to assign to all cells in the
888    * list. If its value is <code>-1</code>, no width has been
889    * assigned. This value can be set explicitly, or implicitly by setting
890    * the {@link #prototypeCellValue} property.
891    */
892   int fixedCellWidth;
893   
894   /**
895    * This property indicates an fixed height to assign to all cells in the
896    * list. If its value is <code>-1</code>, no height has been
897    * assigned. This value can be set explicitly, or implicitly by setting
898    * the {@link #prototypeCellValue} property.
899    */
900   int fixedCellHeight;
901
902   /** 
903    * This property holds the current layout orientation of the list, which
904    * is one of the integer constants {@link #VERTICAL}, {@link
905    * #VERTICAL_WRAP}, or {@link #HORIZONTAL_WRAP}. 
906    */
907   int layoutOrientation;
908   
909   /** This property holds the data elements displayed by the list. */
910   ListModel model;
911
912   /**
913    * <p>This property holds a reference to a "prototype" data value --
914    * typically a String -- which is used to calculate the {@link
915    * #fixedCellWidth} and {@link #fixedCellHeight} properties, using the
916    * {@link #cellRenderer} property to acquire a component to render the
917    * prototype.</p>
918    *
919    * <p>It is important that you <em>not</em> set this value to a
920    * component. It has to be a <em>data value</em> such as the objects you
921    * would find in the list's model. Setting it to a component will have
922    * undefined (and undesirable) affects. </p>
923    */
924   Object prototypeCellValue;
925
926   /** 
927    * This property specifies a foreground color for the selected cells in
928    * the list. When {@link ListCellRenderer#getListCellRendererComponent}
929    * is called with a selected cell object, the component returned will
930    * have its "foreground" set to this color.
931    */
932   Color selectionBackground;
933
934   /** 
935    * This property specifies a background color for the selected cells in
936    * the list. When {@link ListCellRenderer#getListCellRendererComponent}
937    * is called with a selected cell object, the component returned will
938    * have its "background" property set to this color.
939    */
940   Color selectionForeground;
941
942   /** 
943    * This property holds a description of which data elements in the {@link
944    * #model} property should be considered "selected", when displaying and
945    * interacting with the list.
946    */
947   ListSelectionModel selectionModel;
948
949   /** 
950    * This property indicates a <em>preference</em> for the number of rows
951    * displayed in the list, and will scale the
952    * {@link #getPreferredScrollableViewportSize} property accordingly. The actual
953    * number of displayed rows, when the list is placed in a real {@link
954    * JViewport} or other component, may be greater or less than this number.
955    */
956   int visibleRowCount;
957
958   /**
959    * Fire a {@link ListSelectionEvent} to all the registered 
960    * ListSelectionListeners.
961    * 
962    * @param firstIndex  the lowest index covering the selection change.
963    * @param lastIndex  the highest index covering the selection change.
964    * @param isAdjusting  a flag indicating if this event is one in a series
965    *     of events updating the selection.
966    */
967   protected void fireSelectionValueChanged(int firstIndex, int lastIndex, 
968                                            boolean isAdjusting) 
969   {
970     ListSelectionEvent evt = new ListSelectionEvent(this, firstIndex, 
971                                                     lastIndex, isAdjusting);
972     ListSelectionListener listeners[] = getListSelectionListeners();
973     for (int i = 0; i < listeners.length; ++i)
974       {
975         listeners[i].valueChanged(evt);
976       }
977   }
978
979   /**
980    * This private listener propagates {@link ListSelectionEvent} events
981    * from the list's "selectionModel" property to the list's {@link
982    * ListSelectionListener} listeners. It also listens to {@link
983    * ListDataEvent} events from the list's {@link #model} property. If this
984    * class receives either type of event, it triggers repainting of the
985    * list.
986    */
987   private class ListListener 
988     implements ListSelectionListener, ListDataListener
989   {
990     // ListDataListener events
991     public void contentsChanged(ListDataEvent event)
992     {
993       JList.this.revalidate();
994       JList.this.repaint();
995     }
996     public void intervalAdded(ListDataEvent event)
997     {
998       JList.this.revalidate();
999       JList.this.repaint();
1000     }
1001     public void intervalRemoved(ListDataEvent event)
1002     {
1003       JList.this.revalidate();
1004       JList.this.repaint();
1005     }
1006     // ListSelectionListener events
1007     public void valueChanged(ListSelectionEvent event)
1008     {
1009       JList.this.fireSelectionValueChanged(event.getFirstIndex(),
1010                                            event.getLastIndex(),
1011                                            event.getValueIsAdjusting());
1012       JList.this.repaint();
1013     }
1014   }
1015
1016   /** 
1017    * Shared ListListener instance, subscribed to both the current {@link
1018    * #model} and {@link #selectionModel} properties of the list.
1019    */
1020   ListListener listListener;
1021
1022
1023   /**
1024    * Creates a new <code>JList</code> object.
1025    */
1026   public JList()
1027   {
1028     init(new DefaultListModel());
1029   }
1030
1031   /**
1032    * Creates a new <code>JList</code> object.
1033    *
1034    * @param items  the initial list items.
1035    */
1036   public JList(Object[] items)
1037   {
1038     init(createListModel(items));
1039   }
1040
1041   /**
1042    * Creates a new <code>JList</code> object.
1043    *
1044    * @param items  the initial list items.
1045    */
1046   public JList(Vector<?> items)
1047   {
1048     init(createListModel(items));
1049   }
1050
1051   /**
1052    * Creates a new <code>JList</code> object.
1053    *
1054    * @param model  a model containing the list items (<code>null</code> not
1055    *     permitted).
1056    *     
1057    * @throws IllegalArgumentException if <code>model</code> is 
1058    *     <code>null</code>.
1059    */
1060   public JList(ListModel model)
1061   {
1062     init(model);
1063   }
1064
1065   /**
1066    * Initializes the list.
1067    *
1068    * @param m  the list model (<code>null</code> not permitted).
1069    */
1070   private void init(ListModel m)
1071   {
1072     if (m == null)
1073       throw new IllegalArgumentException("Null model not permitted.");
1074     dragEnabled = false;
1075     fixedCellHeight = -1;
1076     fixedCellWidth = -1;
1077     layoutOrientation = VERTICAL;
1078     opaque = true;
1079     visibleRowCount = 8;
1080
1081     cellRenderer = new DefaultListCellRenderer();
1082     listListener = new ListListener();
1083
1084     model = m;
1085     if (model != null)
1086       model.addListDataListener(listListener);
1087
1088     selectionModel = createSelectionModel();
1089     if (selectionModel != null)
1090       {
1091         selectionModel.addListSelectionListener(listListener);
1092         selectionModel.setSelectionMode
1093                               (ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
1094       }
1095     setLayout(null);
1096     
1097     updateUI();
1098   }
1099
1100   /**
1101    * Creates the default <code>ListSelectionModel</code>.
1102    *
1103    * @return the <code>ListSelectionModel</code>
1104    */
1105   protected ListSelectionModel createSelectionModel()
1106   {
1107     return new DefaultListSelectionModel();
1108   }
1109   
1110   /**
1111    * Gets the value of the {@link #fixedCellHeight} property. This property
1112    * may be <code>-1</code> to indicate that no cell height has been
1113    * set. This property is also set implicitly when the
1114    * {@link #prototypeCellValue} property is set.
1115    *
1116    * @return The current value of the property 
1117    * 
1118    * @see #fixedCellHeight
1119    * @see #setFixedCellHeight
1120    * @see #setPrototypeCellValue
1121    */
1122   public int getFixedCellHeight()
1123   {
1124     return fixedCellHeight;
1125   }
1126
1127   /**
1128    * Sets the value of the {@link #fixedCellHeight} property. This property
1129    * may be <code>-1</code> to indicate that no cell height has been
1130    * set. This property is also set implicitly when the {@link
1131    * #prototypeCellValue} property is set, but setting it explicitly
1132    * overrides the height computed from {@link #prototypeCellValue}.
1133    *
1134    * @param h  the height.
1135    * 
1136    * @see #getFixedCellHeight
1137    * @see #getPrototypeCellValue
1138    */
1139   public void setFixedCellHeight(int h)
1140   {
1141     if (fixedCellHeight == h)
1142       return;
1143
1144     int old = fixedCellHeight;
1145     fixedCellHeight = h;
1146     firePropertyChange("fixedCellHeight", old, h);
1147   }
1148
1149
1150   /**
1151    * Gets the value of the {@link #fixedCellWidth} property. This property
1152    * may be <code>-1</code> to indicate that no cell width has been
1153    * set. This property is also set implicitly when the {@link
1154    * #prototypeCellValue} property is set.
1155    *
1156    * @return The current value of the property 
1157    * 
1158    * @see #setFixedCellWidth
1159    * @see #setPrototypeCellValue
1160    */
1161   public int getFixedCellWidth()
1162   {
1163     return fixedCellWidth;
1164   }
1165
1166   /**
1167    * Sets the value of the {@link #fixedCellWidth} property. This property
1168    * may be <code>-1</code> to indicate that no cell width has been
1169    * set. This property is also set implicitly when the {@link
1170    * #prototypeCellValue} property is set, but setting it explicitly
1171    * overrides the width computed from {@link #prototypeCellValue}.
1172    *
1173    * @param w  the width.
1174    * 
1175    * @see #getFixedCellHeight
1176    * @see #getPrototypeCellValue
1177    */
1178   public void setFixedCellWidth(int w)
1179   {
1180     if (fixedCellWidth == w)
1181       return;
1182     
1183     int old = fixedCellWidth;
1184     fixedCellWidth = w;
1185     firePropertyChange("fixedCellWidth", old, w);
1186   }
1187
1188   /** 
1189    * Gets the value of the {@link #visibleRowCount} property.  The default 
1190    * value is 8.
1191    *
1192    * @return the current value of the property.
1193    * 
1194    * @see #setVisibleRowCount(int)
1195    */
1196   public int getVisibleRowCount()
1197   {
1198     return visibleRowCount;
1199   }
1200
1201   /**
1202    * Sets the value of the {@link #visibleRowCount} property. 
1203    *
1204    * @param vc The new property value
1205    * 
1206    * @see #getVisibleRowCount()
1207    */
1208   public void setVisibleRowCount(int vc)
1209   {
1210     if (visibleRowCount != vc)
1211       {
1212         int oldValue = visibleRowCount;
1213         visibleRowCount = Math.max(vc, 0);
1214         firePropertyChange("visibleRowCount", oldValue, vc);
1215         revalidate();
1216         repaint();
1217       }
1218   }
1219
1220   /**
1221    * Adds a {@link ListSelectionListener} to the listener list for this
1222    * list. The listener will be called back with a {@link
1223    * ListSelectionEvent} any time the list's {@link #selectionModel}
1224    * property changes. The source of such events will be the JList,
1225    * not the selection model.
1226    *
1227    * @param listener The new listener to add
1228    */
1229   public void addListSelectionListener(ListSelectionListener listener)
1230   {
1231     listenerList.add (ListSelectionListener.class, listener);
1232   }
1233
1234   /**
1235    * Removes a {@link ListSelectionListener} from the listener list for
1236    * this list. The listener will no longer be called when the list's
1237    * {@link #selectionModel} changes.
1238    *
1239    * @param listener The listener to remove
1240    */
1241   public void removeListSelectionListener(ListSelectionListener listener)
1242   {
1243     listenerList.remove(ListSelectionListener.class, listener);
1244   }
1245
1246   /**
1247    * Returns an array of all ListSelectionListeners subscribed to this
1248    * list. 
1249    *
1250    * @return The current subscribed listeners
1251    *
1252    * @since 1.4
1253    */
1254   public ListSelectionListener[] getListSelectionListeners()
1255   {
1256     return (ListSelectionListener[]) getListeners(ListSelectionListener.class);
1257   }
1258
1259   /**
1260    * Returns the selection mode for the list (one of: 
1261    * {@link ListSelectionModel#SINGLE_SELECTION}, 
1262    * {@link ListSelectionModel#SINGLE_INTERVAL_SELECTION} and 
1263    * {@link ListSelectionModel#MULTIPLE_INTERVAL_SELECTION}).
1264    * 
1265    * @return The selection mode.
1266    * 
1267    * @see #setSelectionMode(int)
1268    */
1269   public int getSelectionMode()
1270   {
1271     return selectionModel.getSelectionMode();
1272   }
1273   
1274   /**
1275    * Sets the list's "selectionMode" property, which simply mirrors the
1276    * same property on the list's {@link #selectionModel} property. This
1277    * property should be one of the integer constants
1278    * <code>SINGLE_SELECTION</code>, <code>SINGLE_INTERVAL_SELECTION</code>,
1279    * or <code>MULTIPLE_INTERVAL_SELECTION</code> from the {@link
1280    * ListSelectionModel} interface.
1281    *
1282    * @param a The new selection mode
1283    */
1284   public void setSelectionMode(int a)
1285   {
1286     selectionModel.setSelectionMode(a);
1287   }
1288
1289   /**
1290    * Adds the interval <code>[a,a]</code> to the set of selections managed
1291    * by this list's {@link #selectionModel} property. Depending on the
1292    * selection mode, this may cause existing selections to become invalid,
1293    * or may simply expand the set of selections. 
1294    *
1295    * @param a A number in the half-open range <code>[0, x)</code> where
1296    * <code>x = getModel.getSize()</code>, indicating the index of an
1297    * element in the list to select. When &lt; 0 the selection is cleared.
1298    *
1299    * @see #setSelectionMode
1300    * @see #selectionModel
1301    */
1302   public void setSelectedIndex(int a)
1303   {
1304     if (a < 0)
1305       selectionModel.clearSelection();
1306     else
1307       selectionModel.setSelectionInterval(a, a);
1308   }
1309
1310   /**
1311    * For each element <code>a[i]</code> of the provided array
1312    * <code>a</code>, calls {@link #setSelectedIndex} on <code>a[i]</code>.
1313    *
1314    * @param a  an array of selected indices (<code>null</code> not permitted).
1315    * 
1316    * @throws NullPointerException if <code>a</code> is <code>null</code>.
1317    * @see #setSelectionMode
1318    * @see #selectionModel
1319    */
1320   public void setSelectedIndices(int [] a)
1321   {
1322     for (int i = 0; i < a.length; ++i)
1323       setSelectedIndex(a[i]);
1324   }
1325
1326   /**
1327    * Returns the minimum index of an element in the list which is currently
1328    * selected.
1329    *
1330    * @return A number in the half-open range <code>[0, x)</code> where
1331    * <code>x = getModel.getSize()</code>, indicating the minimum index of
1332    * an element in the list for which the element is selected, or
1333    * <code>-1</code> if no elements are selected
1334    */
1335   public int getSelectedIndex()
1336   {
1337     return selectionModel.getMinSelectionIndex();
1338   }
1339
1340   /**
1341    * Returns <code>true</code> if the model's selection is empty, otherwise
1342    * <code>false</code>. 
1343    *
1344    * @return The return value of {@link ListSelectionModel#isSelectionEmpty}
1345    */
1346   public boolean isSelectionEmpty()
1347   {
1348     return selectionModel.isSelectionEmpty();
1349   }
1350
1351   /**
1352    * Returns the list index of the upper left or upper right corner of the
1353    * visible rectangle of this list, depending on the {@link
1354    * Component#getComponentOrientation} property.
1355    *
1356    * @return The index of the first visible list cell, or <code>-1</code>
1357    * if none is visible.
1358    */
1359   public int getFirstVisibleIndex()
1360   {
1361     ComponentOrientation or = getComponentOrientation();
1362     Rectangle r = getVisibleRect();
1363     if (or == ComponentOrientation.RIGHT_TO_LEFT)
1364       r.translate((int) r.getWidth() - 1, 0);
1365     return getUI().locationToIndex(this, r.getLocation());      
1366   }
1367
1368
1369   /**
1370    * Returns index of the cell to which specified location is closest to. If
1371    * the location is outside the bounds of the list, then the greatest index
1372    * in the list model is returned. If the list model is empty, then
1373    * <code>-1</code> is returned.
1374    *
1375    * @param location for which to look for in the list
1376    * 
1377    * @return index of the cell to which specified location is closest to.
1378    */
1379    public int locationToIndex(Point location)
1380    {
1381      return getUI().locationToIndex(this, location);      
1382    }
1383
1384   /**
1385    * Returns location of the cell located at the specified index in the list.
1386    * @param index of the cell for which location will be determined
1387    * 
1388    * @return location of the cell located at the specified index in the list.
1389    */
1390    public Point indexToLocation(int index)
1391    {
1392      return getUI().indexToLocation(this, index);
1393    }
1394
1395   /**
1396    * Returns the list index of the lower right or lower left corner of the
1397    * visible rectangle of this list, depending on the {@link
1398    * Component#getComponentOrientation} property.
1399    *
1400    * @return The index of the last visible list cell, or <code>-1</code>
1401    * if none is visible.
1402    */
1403   public int getLastVisibleIndex()
1404   {
1405     ComponentOrientation or = getComponentOrientation();
1406     Rectangle r = getVisibleRect();
1407     r.translate(0, (int) r.getHeight() - 1);
1408     if (or == ComponentOrientation.LEFT_TO_RIGHT)
1409       r.translate((int) r.getWidth() - 1, 0);
1410     if (getUI().locationToIndex(this, r.getLocation()) == -1
1411         && indexToLocation(getModel().getSize() - 1).y < r.y)
1412       return getModel().getSize() - 1;
1413     return getUI().locationToIndex(this, r.getLocation());
1414   }
1415
1416   /**
1417    * Returns the indices of values in the {@link #model} property which are
1418    * selected.
1419    *
1420    * @return An array of model indices, each of which is selected according
1421    *         to the {@link #getSelectedValues} property
1422    */
1423   public int[] getSelectedIndices()
1424   {
1425     int lo, hi, n, i, j;
1426     if (selectionModel.isSelectionEmpty())
1427       return new int[0];
1428     lo = selectionModel.getMinSelectionIndex();
1429     hi = selectionModel.getMaxSelectionIndex();
1430     n = 0;
1431     for (i = lo; i <= hi; ++i)
1432       if (selectionModel.isSelectedIndex(i))
1433         n++;
1434     int [] v = new int[n];
1435     j = 0;
1436     for (i = lo; i <= hi; ++i)
1437       if (selectionModel.isSelectedIndex(i))
1438         v[j++] = i;
1439     return v;
1440   }
1441
1442   /**
1443    * Indicates whether the list element at a given index value is
1444    * currently selected.
1445    *
1446    * @param a The index to check 
1447    * @return <code>true</code> if <code>a</code> is the index of a selected
1448    * list element
1449    */
1450   public boolean isSelectedIndex(int a)
1451   {
1452     return selectionModel.isSelectedIndex(a);
1453   }
1454
1455   /**
1456    * Returns the first value in the list's {@link #model} property which is
1457    * selected, according to the list's {@link #selectionModel} property.
1458    * This is equivalent to calling
1459    * <code>getModel()getElementAt(getSelectedIndex())</code>, with a check
1460    * for the special index value of <code>-1</code> which returns null
1461    * <code>null</code>.
1462    *
1463    * @return The first selected element, or <code>null</code> if no element
1464    * is selected.
1465    *
1466    * @see #getSelectedValues
1467    */
1468   public Object getSelectedValue()
1469   {
1470     int index = getSelectedIndex();
1471     if (index == -1)
1472       return null;
1473     return getModel().getElementAt(index);
1474   }
1475
1476   /**
1477    * Returns all the values in the list's {@link #model} property which are
1478    * selected, according to the list's {@link #selectionModel} property.
1479    * 
1480    * @return An array containing all the selected values
1481    * @see #setSelectedValue
1482    */
1483   public Object[] getSelectedValues()
1484   {
1485     int[] idx = getSelectedIndices();
1486     Object[] v = new Object[idx.length];
1487     for (int i = 0; i < idx.length; ++i)
1488       v[i] = getModel().getElementAt(idx[i]);
1489     return v;
1490   }
1491
1492   /**
1493    * Gets the value of the {@link #selectionBackground} property.
1494    *
1495    * @return The current value of the property
1496    */
1497   public Color getSelectionBackground()
1498   {
1499     return selectionBackground;
1500   }
1501
1502   /**
1503    * Sets the value of the {@link #selectionBackground} property.
1504    *
1505    * @param c The new value of the property
1506    */
1507   public void setSelectionBackground(Color c)
1508   {
1509     if (selectionBackground == c)
1510       return;
1511
1512     Color old = selectionBackground;
1513     selectionBackground = c;
1514     firePropertyChange("selectionBackground", old, c);
1515     repaint();
1516   }
1517
1518   /**
1519    * Gets the value of the {@link #selectionForeground} property.
1520    *
1521    * @return The current value of the property
1522    */
1523   public Color getSelectionForeground()
1524   {
1525     return selectionForeground;
1526   }
1527   
1528   /**
1529    * Sets the value of the {@link #selectionForeground} property.
1530    *
1531    * @param c The new value of the property
1532    */
1533   public void setSelectionForeground(Color c)
1534   {
1535     if (selectionForeground == c)
1536       return;
1537
1538     Color old = selectionForeground;
1539     selectionForeground = c;
1540     firePropertyChange("selectionForeground", old, c);
1541   }
1542
1543   /**
1544    * Sets the selection to cover only the specified value, if it
1545    * exists in the model. 
1546    *
1547    * @param obj The object to select
1548    * @param scroll Whether to scroll the list to make the newly selected
1549    * value visible
1550    *
1551    * @see #ensureIndexIsVisible
1552    */
1553
1554   public void setSelectedValue(Object obj, boolean scroll)
1555   {
1556     for (int i = 0; i < model.getSize(); ++i)
1557       {
1558         if (model.getElementAt(i).equals(obj))
1559           {
1560             setSelectedIndex(i);
1561             if (scroll)
1562               ensureIndexIsVisible(i);
1563             break;
1564           }
1565       }
1566   }
1567
1568   /**
1569    * Scrolls this list to make the specified cell visible. This
1570    * only works if the list is contained within a viewport.
1571    *
1572    * @param i The list index to make visible
1573    *
1574    * @see JComponent#scrollRectToVisible
1575    */
1576   public void ensureIndexIsVisible(int i)
1577   {
1578     Rectangle r = getUI().getCellBounds(this, i, i);
1579     if (r != null)
1580       scrollRectToVisible(r);
1581   }
1582
1583   /**
1584    * Sets the {@link #model} property of the list to a new anonymous
1585    * {@link AbstractListModel} subclass which accesses the provided Object
1586    * array directly.
1587    *
1588    * @param listData The object array to build a new list model on
1589    * @see #setModel
1590    */
1591   public void setListData(Object[] listData)
1592   {
1593     setModel(createListModel(listData));
1594   }
1595
1596   /**
1597    * Returns a {@link ListModel} backed by the specified array.
1598    * 
1599    * @param items  the list items (don't use <code>null</code>).
1600    * 
1601    * @return A list model containing the specified items.
1602    */
1603   private ListModel createListModel(final Object[] items)
1604   {
1605     return new AbstractListModel()
1606       {
1607         public int getSize()
1608         {
1609           return items.length;
1610         }
1611         public Object getElementAt(int i)
1612         {
1613           return items[i];
1614         }
1615       };
1616   }
1617   
1618   /**
1619    * Returns a {@link ListModel} backed by the specified vector.
1620    * 
1621    * @param items  the list items (don't use <code>null</code>).
1622    * 
1623    * @return A list model containing the specified items.
1624    */
1625   private ListModel createListModel(final Vector items)
1626   {
1627     return new AbstractListModel()
1628       {
1629         public int getSize()
1630         {
1631           return items.size();
1632         }
1633         public Object getElementAt(int i)
1634         {
1635           return items.get(i);
1636         }
1637       };
1638   }
1639
1640   /**
1641    * Sets the {@link #model} property of the list to a new anonymous {@link
1642    * AbstractListModel} subclass which accesses the provided vector
1643    * directly.
1644    *
1645    * @param listData The object array to build a new list model on
1646    * @see #setModel
1647    */
1648   public void setListData(final Vector<?> listData)
1649   {
1650     setModel(new AbstractListModel()
1651       {
1652         public int getSize()
1653         {
1654           return listData.size();
1655         }
1656         
1657         public Object getElementAt(int i)
1658         {
1659           return listData.elementAt(i);
1660         }
1661       });
1662   }
1663
1664   /**
1665    * Gets the value of the {@link #cellRenderer} property. 
1666    *
1667    * @return The current value of the property
1668    */
1669   public ListCellRenderer getCellRenderer()
1670   {
1671     return cellRenderer;
1672   }
1673
1674   /**
1675    * Sets the value of the {@link #getCellRenderer} property.
1676    *
1677    * @param renderer The new property value
1678    */
1679   public void setCellRenderer(ListCellRenderer renderer)
1680   {
1681     if (cellRenderer == renderer)
1682       return;
1683     
1684     ListCellRenderer old = cellRenderer;
1685     cellRenderer = renderer;
1686     firePropertyChange("cellRenderer", old, renderer);
1687     revalidate();
1688     repaint();
1689   }
1690
1691   /**
1692    * Gets the value of the {@link #model} property. 
1693    *
1694    * @return The current value of the property
1695    */
1696   public ListModel getModel()
1697   {
1698     return model;
1699   }
1700
1701   /**
1702    * Sets the value of the {@link #model} property. The list's {@link
1703    * #listListener} is unsubscribed from the existing model, if it exists,
1704    * and re-subscribed to the new model.
1705    *
1706    * @param model  the new model (<code>null</code> not permitted).
1707    * 
1708    * @throws IllegalArgumentException if <code>model</code> is 
1709    *         <code>null</code>.
1710    */
1711   public void setModel(ListModel model)
1712   {
1713     if (model == null) 
1714       throw new IllegalArgumentException("Null 'model' argument.");
1715     if (this.model == model)
1716       return;
1717     
1718     if (this.model != null)
1719       this.model.removeListDataListener(listListener);
1720     
1721     ListModel old = this.model;
1722     this.model = model;
1723     
1724     if (this.model != null)
1725       this.model.addListDataListener(listListener);
1726     
1727     firePropertyChange("model", old, model);
1728     revalidate();
1729     repaint();
1730   }
1731
1732   /**
1733    * Returns the selection model for the {@link JList} component.  Note that
1734    * this class contains a range of convenience methods for configuring the
1735    * selection model:<br>
1736    * <ul>
1737    *   <li>{@link #clearSelection()};</li>
1738    *   <li>{@link #setSelectionMode(int)};</li>
1739    *   <li>{@link #addSelectionInterval(int, int)};</li>
1740    *   <li>{@link #setSelectedIndex(int)};</li>
1741    *   <li>{@link #setSelectedIndices(int[])};</li>
1742    *   <li>{@link #setSelectionInterval(int, int)}.</li>
1743    * </ul>
1744    * 
1745    * @return The selection model.
1746    */
1747   public ListSelectionModel getSelectionModel()
1748   {
1749     return selectionModel;
1750   }
1751
1752   /**
1753    * Sets the value of the {@link #selectionModel} property. The list's
1754    * {@link #listListener} is unsubscribed from the existing selection
1755    * model, if it exists, and re-subscribed to the new selection model.
1756    *
1757    * @param model The new property value
1758    */
1759   public void setSelectionModel(ListSelectionModel model)
1760   {
1761     if (selectionModel == model)
1762       return;
1763     
1764     if (selectionModel != null)
1765       selectionModel.removeListSelectionListener(listListener);
1766     
1767     ListSelectionModel old = selectionModel;
1768     selectionModel = model;
1769     
1770     if (selectionModel != null)
1771       selectionModel.addListSelectionListener(listListener);
1772     
1773     firePropertyChange("selectionModel", old, model);
1774     revalidate();
1775     repaint();
1776   }
1777
1778   /**
1779    * Gets the value of the UI property.
1780    *
1781    * @return The current property value
1782    */
1783   public ListUI getUI()
1784   {
1785     return (ListUI) ui;
1786   }
1787
1788   /**
1789    * Sets the value of the UI property.
1790    *
1791    * @param ui The new property value
1792    */
1793   public void setUI(ListUI ui)
1794   {
1795     super.setUI(ui);
1796   }
1797
1798   /**
1799    * Calls {@link #setUI} with the {@link ListUI} subclass
1800    * returned from calling {@link UIManager#getUI}.
1801    */
1802   public void updateUI()
1803   {
1804     setUI((ListUI) UIManager.getUI(this));
1805   }
1806
1807   /**
1808    * Return the class identifier for the list's UI property.  This should
1809    * be the constant string <code>"ListUI"</code>, and map to an
1810    * appropriate UI class in the {@link UIManager}.
1811    *
1812    * @return The class identifier
1813    */
1814   public String getUIClassID()
1815   {
1816     return "ListUI";
1817   }
1818
1819
1820   /**
1821    * Returns the current value of the {@link #prototypeCellValue}
1822    * property. This property holds a reference to a "prototype" data value
1823    * -- typically a String -- which is used to calculate the {@link
1824    * #fixedCellWidth} and {@link #fixedCellHeight} properties, using the
1825    * {@link #cellRenderer} property to acquire a component to render the
1826    * prototype.
1827    *
1828    * @return The current prototype cell value
1829    * @see #setPrototypeCellValue
1830    */
1831   public Object getPrototypeCellValue()
1832   {
1833     return prototypeCellValue;
1834   }
1835
1836   /**
1837    * <p>Set the {@link #prototypeCellValue} property. This property holds a
1838    * reference to a "prototype" data value -- typically a String -- which
1839    * is used to calculate the {@link #fixedCellWidth} and {@link
1840    * #fixedCellHeight} properties, using the {@link #cellRenderer} property
1841    * to acquire a component to render the prototype.</p>
1842    *
1843    * <p>It is important that you <em>not</em> set this value to a
1844    * component. It has to be a <em>data value</em> such as the objects you
1845    * would find in the list's model. Setting it to a component will have
1846    * undefined (and undesirable) affects. </p>
1847    *
1848    * @param obj The new prototype cell value
1849    * @see #getPrototypeCellValue
1850    */
1851   public void setPrototypeCellValue(Object obj)
1852   {
1853     if (prototypeCellValue == obj)
1854       return;
1855
1856     Object old = prototypeCellValue;
1857     Component comp = getCellRenderer()
1858       .getListCellRendererComponent(this, obj, 0, false, false); 
1859     Dimension d = comp.getPreferredSize();
1860     fixedCellWidth = d.width;
1861     fixedCellHeight = d.height;
1862     prototypeCellValue = obj;
1863     firePropertyChange("prototypeCellValue", old, obj);
1864   }
1865
1866   public AccessibleContext getAccessibleContext()
1867   {
1868     return new AccessibleJList();
1869   }
1870
1871   /**
1872    * Returns a size indicating how much space this list would like to
1873    * consume, when contained in a scrollable viewport. This is part of the
1874    * {@link Scrollable} interface, which interacts with {@link
1875    * ScrollPaneLayout} and {@link JViewport} to define scrollable objects.
1876    *
1877    * @return The preferred size
1878    */
1879   public Dimension getPreferredScrollableViewportSize()
1880   {
1881     //If the layout orientation is not VERTICAL, then this will 
1882     //return the value from getPreferredSize. The current ListUI is 
1883     //expected to override getPreferredSize to return an appropriate value.
1884     if (getLayoutOrientation() != VERTICAL)
1885       return getPreferredSize();        
1886
1887     int size = getModel().getSize();
1888     
1889     // Trivial case: if fixedCellWidth and fixedCellHeight were set 
1890     // just use them
1891     if (fixedCellHeight != -1 && fixedCellWidth != -1)
1892       return new Dimension(fixedCellWidth, size * fixedCellHeight);
1893         
1894     // If the model is empty we use 16 * the number of visible rows
1895     // for the height and either fixedCellWidth (if set) or 256
1896     // for the width
1897     if (size == 0)
1898       {
1899         if (fixedCellWidth == -1)
1900           return new Dimension(256, 16 * getVisibleRowCount());
1901         else
1902           return new Dimension(fixedCellWidth, 16 * getVisibleRowCount());
1903       }
1904
1905     // Calculate the width: if fixedCellWidth was set use that, otherwise
1906     // use the preferredWidth
1907     int prefWidth;
1908     if (fixedCellWidth != -1)
1909       prefWidth = fixedCellWidth;
1910     else
1911       prefWidth = getPreferredSize().width;
1912
1913     // Calculate the height: if fixedCellHeight was set use that, otherwise
1914     // use the height of the first row multiplied by the number of visible
1915     // rows
1916     int prefHeight;
1917     if (fixedCellHeight != -1)
1918       prefHeight = fixedCellHeight;
1919     else
1920       prefHeight = getVisibleRowCount() * getCellBounds(0, 0).height;
1921
1922     return new Dimension (prefWidth, prefHeight);
1923   }
1924
1925   /**
1926    * <p>Return the number of pixels the list must scroll in order to move a
1927    * "unit" of the list into the provided visible rectangle. When the
1928    * provided direction is positive, the call describes a "downwards"
1929    * scroll, which will be exposing a cell at a <em>greater</em> index in
1930    * the list than those elements currently showing. Then the provided
1931    * direction is negative, the call describes an "upwards" scroll, which
1932    * will be exposing a cell at a <em>lesser</em> index in the list than
1933    * those elements currently showing.</p>
1934    *
1935    * <p>If the provided orientation is <code>HORIZONTAL</code>, the above
1936    * comments refer to "rightwards" for positive direction, and "leftwards"
1937    * for negative.</p>
1938    * 
1939    *
1940    * @param visibleRect The rectangle to scroll an element into
1941    * @param orientation One of the numeric consants <code>VERTICAL</code>
1942    * or <code>HORIZONTAL</code>
1943    * @param direction An integer indicating the scroll direction: positive means
1944    * forwards (down, right), negative means backwards (up, left)
1945    *
1946    * @return The scrollable unit increment, in pixels
1947    */
1948   public int getScrollableUnitIncrement(Rectangle visibleRect,
1949                                         int orientation, int direction)
1950   {
1951     int unit = -1;
1952     if (orientation == SwingConstants.VERTICAL)
1953       {
1954         int row = getFirstVisibleIndex();
1955         if (row == -1)
1956           unit = 0;
1957         else if (direction > 0)
1958           {
1959             // Scrolling down.
1960             Rectangle bounds = getCellBounds(row, row);
1961             if (bounds != null)
1962               unit = bounds.height - (visibleRect.y - bounds.y);
1963             else
1964               unit = 0;
1965           }
1966         else
1967           {
1968             // Scrolling up.
1969             Rectangle bounds = getCellBounds(row, row);
1970             // First row.
1971             if (row == 0 && bounds.y == visibleRect.y)
1972               unit = 0; // No need to scroll.
1973             else if (bounds.y == visibleRect.y)
1974               {
1975                 // Scroll to previous row.
1976                 Point loc = bounds.getLocation();
1977                 loc.y--;
1978                 int prev = locationToIndex(loc);
1979                 Rectangle prevR = getCellBounds(prev, prev);
1980                 if (prevR == null || prevR.y >= bounds.y)
1981                   unit = 0; // For multicolumn lists.
1982                 else
1983                   unit = prevR.height;
1984               }
1985             else
1986               unit = visibleRect.y - bounds.y;
1987           }
1988       }
1989     else if (orientation == SwingConstants.HORIZONTAL && getLayoutOrientation() != VERTICAL)
1990       {
1991         // Horizontal scrolling.
1992         int i = locationToIndex(visibleRect.getLocation());
1993         if (i != -1)
1994           {
1995             Rectangle b = getCellBounds(i, i);
1996             if (b != null)
1997               {
1998                 if (b.x != visibleRect.x)
1999                   {
2000                     if (direction < 0)
2001                       unit = Math.abs(b.x - visibleRect.x);
2002                     else
2003                       unit = b.width + b.x - visibleRect.x;
2004                   }
2005                 else
2006                   unit = b.width;
2007               }
2008           }
2009       }
2010
2011     if (unit == -1)
2012       {
2013         // This fallback seems to be used by the RI for the degenerate cases
2014         // not covered above.
2015         Font f = getFont();
2016         unit = f != null ? f.getSize() : 1;
2017       }
2018     return unit;
2019   }
2020
2021   /**
2022    * <p>Return the number of pixels the list must scroll in order to move a
2023    * "block" of the list into the provided visible rectangle. When the
2024    * provided direction is positive, the call describes a "downwards"
2025    * scroll, which will be exposing a cell at a <em>greater</em> index in
2026    * the list than those elements currently showing. Then the provided
2027    * direction is negative, the call describes an "upwards" scroll, which
2028    * will be exposing a cell at a <em>lesser</em> index in the list than
2029    * those elements currently showing.</p>
2030    *
2031    * <p>If the provided orientation is <code>HORIZONTAL</code>, the above
2032    * comments refer to "rightwards" for positive direction, and "leftwards"
2033    * for negative.</p>
2034    * 
2035    *
2036    * @param visibleRect The rectangle to scroll an element into
2037    * @param orientation One of the numeric consants <code>VERTICAL</code>
2038    * or <code>HORIZONTAL</code>
2039    * @param direction An integer indicating the scroll direction: positive means
2040    * forwards (down, right), negative means backwards (up, left)
2041    *
2042    * @return The scrollable unit increment, in pixels
2043    */
2044   public int getScrollableBlockIncrement(Rectangle visibleRect,
2045                                          int orientation, int direction)
2046   {
2047     int block = -1;
2048     if (orientation == SwingConstants.VERTICAL)
2049       {
2050         // Default block scroll. Special cases are handled below for
2051         // better usability.
2052         block = visibleRect.height;
2053         if (direction > 0)
2054           {
2055             // Scroll down.
2056             // Scroll so that after scrolling the last line aligns with
2057             // the lower boundary of the visible area.
2058             Point p = new Point(visibleRect.x,
2059                                 visibleRect.y + visibleRect.height - 1);
2060             int last = locationToIndex(p);
2061             if (last != -1)
2062               {
2063                 Rectangle lastR = getCellBounds(last, last);
2064                 if (lastR != null)
2065                   {
2066                     block = lastR.y - visibleRect.y;
2067                     if (block == 0&& last < getModel().getSize() - 1)
2068                       block = lastR.height;
2069                   }
2070               }
2071           }
2072         else
2073           {
2074             // Scroll up.
2075             // Scroll so that after scrolling the first line aligns with
2076             // the upper boundary of the visible area.
2077             Point p = new Point(visibleRect.x,
2078                                 visibleRect.y - visibleRect.height);
2079             int newFirst = locationToIndex(p);
2080             if (newFirst != -1)
2081               {
2082                 int first = getFirstVisibleIndex();
2083                 if (first == -1)
2084                   first = locationToIndex(visibleRect.getLocation());
2085                 Rectangle newFirstR = getCellBounds(newFirst, newFirst);
2086                 Rectangle firstR = getCellBounds(first, first);
2087                 if (newFirstR != null && firstR != null)
2088                   {
2089                     // Search first item that would left the current first
2090                     // item visible when scrolled to.
2091                     while (newFirstR.y + visibleRect.height
2092                            < firstR.y + firstR.height
2093                            && newFirstR.y < firstR.y)
2094                       {
2095                         newFirst++;
2096                         newFirstR = getCellBounds(newFirst, newFirst);
2097                       }
2098                     block = visibleRect.y - newFirstR.y;
2099                     if (block <= 0 && newFirstR.y > 0)
2100                       {
2101                         newFirst--;
2102                         newFirstR = getCellBounds(newFirst, newFirst);
2103                         if (newFirstR != null)
2104                           block = visibleRect.y - newFirstR.y;
2105                       }
2106                   }
2107               }
2108           }
2109       }
2110     else if (orientation == SwingConstants.HORIZONTAL
2111              && getLayoutOrientation() != VERTICAL)
2112       {
2113         // Default block increment. Special cases are handled below for
2114         // better usability.
2115         block = visibleRect.width;
2116         if (direction > 0)
2117           {
2118             // Scroll right.
2119             Point p = new Point(visibleRect.x + visibleRect.width + 1,
2120                                 visibleRect.y);
2121             int last = locationToIndex(p);
2122             if (last != -1)
2123               {
2124                 Rectangle lastR = getCellBounds(last, last);
2125                 if (lastR != null)
2126                   {
2127                     block = lastR.x  - visibleRect.x;
2128                     if (block < 0)
2129                       block += lastR.width;
2130                     else if (block == 0 && last < getModel().getSize() - 1)
2131                       block = lastR.width;
2132                   }
2133               }
2134           }
2135         else
2136           {
2137             // Scroll left.
2138             Point p = new Point(visibleRect.x - visibleRect.width,
2139                                 visibleRect.y);
2140             int first = locationToIndex(p);
2141             if (first != -1)
2142               {
2143                 Rectangle firstR = getCellBounds(first, first);
2144                 if (firstR != null)
2145                   {
2146                     if (firstR.x < visibleRect.x - visibleRect.width)
2147                       {
2148                         if (firstR.x + firstR.width > visibleRect.x)
2149                           block = visibleRect.x - firstR.x;
2150                         else
2151                           block = visibleRect.x - firstR.x - firstR.width;
2152                       }
2153                     else
2154                       block = visibleRect.x - firstR.x;
2155                   }
2156               }
2157           }
2158       }
2159
2160     return block;
2161   }
2162
2163   /**
2164    * Gets the value of the <code>scrollableTracksViewportWidth</code> property.
2165    *
2166    * @return <code>true</code> if the viewport is larger (horizontally)
2167    * than the list and the list should be expanded to fit the viewport;
2168    * <code>false</code> if the viewport is smaller than the list and the
2169    * list should scroll (horizontally) within the viewport
2170    */
2171   public boolean getScrollableTracksViewportWidth()
2172   {
2173     Component parent = getParent();
2174     boolean retVal = false;
2175     if (parent instanceof JViewport)
2176       {
2177         JViewport viewport = (JViewport) parent;
2178         Dimension pref = getPreferredSize();
2179         if (viewport.getSize().width > pref.width)
2180           retVal = true;
2181         if ((getLayoutOrientation() == HORIZONTAL_WRAP)
2182             && (getVisibleRowCount() <= 0))
2183           retVal = true;
2184       }
2185     return retVal;
2186   }
2187
2188   /**
2189    * Gets the value of the </code>scrollableTracksViewportWidth</code> property.
2190    *
2191    * @return <code>true</code> if the viewport is larger (vertically)
2192    * than the list and the list should be expanded to fit the viewport;
2193    * <code>false</code> if the viewport is smaller than the list and the
2194    * list should scroll (vertically) within the viewport
2195    */
2196   public boolean getScrollableTracksViewportHeight()
2197   {
2198     Component parent = getParent();
2199     boolean retVal = false;
2200     if (parent instanceof JViewport)
2201       {
2202         JViewport viewport = (JViewport) parent;
2203         Dimension pref = getPreferredSize();
2204         if (viewport.getSize().height > pref.height)
2205           retVal = true;
2206         if ((getLayoutOrientation() == VERTICAL_WRAP)
2207             && (getVisibleRowCount() <= 0))
2208           retVal = true;
2209       }
2210     return retVal;
2211   }
2212
2213   /**
2214    * Returns the index of the anchor item in the current selection, or
2215    * <code>-1</code> if there is no anchor item.
2216    * 
2217    * @return The item index.
2218    */
2219   public int getAnchorSelectionIndex()
2220   {
2221     return selectionModel.getAnchorSelectionIndex();
2222   }
2223
2224   /**
2225    * Returns the index of the lead item in the current selection, or
2226    * <code>-1</code> if there is no lead item.
2227    * 
2228    * @return The item index.
2229    */
2230   public int getLeadSelectionIndex()
2231   {
2232     return selectionModel.getLeadSelectionIndex();
2233   }
2234
2235   /**
2236    * Returns the lowest item index in the current selection, or <code>-1</code>
2237    * if there is no selection.
2238    * 
2239    * @return The index.
2240    * 
2241    * @see #getMaxSelectionIndex()
2242    */
2243   public int getMinSelectionIndex()
2244   {
2245     return selectionModel.getMinSelectionIndex();
2246   }
2247
2248   /**
2249    * Returns the highest item index in the current selection, or 
2250    * <code>-1</code> if there is no selection.
2251    * 
2252    * @return The index.
2253    * 
2254    * @see #getMinSelectionIndex()
2255    */
2256   public int getMaxSelectionIndex()
2257   {
2258     return selectionModel.getMaxSelectionIndex();
2259   }
2260
2261   /**
2262    * Clears the current selection.
2263    */
2264   public void clearSelection()
2265   {
2266     selectionModel.clearSelection();
2267   }
2268
2269   /**
2270    * Sets the current selection to the items in the specified range (inclusive).
2271    * Note that <code>anchor</code> can be less than, equal to, or greater than 
2272    * <code>lead</code>.
2273    * 
2274    * @param anchor  the index of the anchor item.
2275    * @param lead  the index of the anchor item.
2276    */
2277   public void setSelectionInterval(int anchor, int lead)
2278   {
2279     selectionModel.setSelectionInterval(anchor, lead);
2280   }
2281
2282   /**
2283    * Adds the specified interval to the current selection.  Note that 
2284    * <code>anchor</code> can be less than, equal to, or greater than 
2285    * <code>lead</code>.
2286    * 
2287    * @param anchor  the index of the anchor item.
2288    * @param lead  the index of the lead item.
2289    */
2290   public void addSelectionInterval(int anchor, int lead)
2291   {
2292     selectionModel.addSelectionInterval(anchor, lead);
2293   }
2294
2295   /**
2296    * Removes the specified interval from the current selection.  Note that 
2297    * <code>index0</code> can be less than, equal to, or greater than 
2298    * <code>index1</code>.
2299    * 
2300    * @param index0  an index for one end of the range.
2301    * @param index1  an index for the other end of the range.
2302    */
2303   public void removeSelectionInterval(int index0, int index1)
2304   {
2305     selectionModel.removeSelectionInterval(index0, index1);
2306   }
2307
2308   /**
2309    * Returns the <code>valueIsAdjusting</code> flag from the list's selection
2310    * model.
2311    *
2312    * @return the value
2313    */
2314   public boolean getValueIsAdjusting()
2315   {
2316     return selectionModel.getValueIsAdjusting();
2317   }
2318
2319   /**
2320    * Sets the <code>valueIsAdjusting</code> flag in the list's selection 
2321    * model.
2322    *
2323    * @param isAdjusting the new value
2324    */
2325   public void setValueIsAdjusting(boolean isAdjusting)
2326   {
2327     selectionModel.setValueIsAdjusting(isAdjusting);
2328   }
2329
2330   /**
2331    * Return the value of the <code>dragEnabled</code> property.
2332    *
2333    * @return the value
2334    * 
2335    * @since 1.4
2336    */
2337   public boolean getDragEnabled()
2338   {
2339     return dragEnabled;
2340   }
2341
2342   /**
2343    * Set the <code>dragEnabled</code> property.
2344    *
2345    * @param enabled new value
2346    * 
2347    * @since 1.4
2348    */
2349   public void setDragEnabled(boolean enabled)
2350   {
2351     dragEnabled = enabled;
2352   }
2353
2354   /**
2355    * Returns the layout orientation, which will be one of {@link #VERTICAL}, 
2356    * {@link #VERTICAL_WRAP} and {@link #HORIZONTAL_WRAP}.  The default value
2357    * is {@link #VERTICAL}.
2358    *
2359    * @return the orientation.
2360    *
2361    * @see #setLayoutOrientation(int)
2362    * @since 1.4
2363    */
2364   public int getLayoutOrientation()
2365   {
2366     return layoutOrientation;
2367   }
2368
2369   /**
2370    * Sets the layout orientation (this is a bound property with the name
2371    * 'layoutOrientation').  Valid orientations are {@link #VERTICAL}, 
2372    * {@link #VERTICAL_WRAP} and {@link #HORIZONTAL_WRAP}.
2373    *
2374    * @param orientation the orientation.
2375    *
2376    * @throws IllegalArgumentException if <code>orientation</code> is not one
2377    *     of the specified values.
2378    * @since 1.4
2379    * @see #getLayoutOrientation()
2380    */
2381   public void setLayoutOrientation(int orientation)
2382   {
2383     if (orientation < JList.VERTICAL || orientation > JList.HORIZONTAL_WRAP)
2384       throw new IllegalArgumentException();
2385     if (layoutOrientation == orientation)
2386       return;
2387
2388     int old = layoutOrientation;
2389     layoutOrientation = orientation;
2390     firePropertyChange("layoutOrientation", old, orientation);
2391   }
2392
2393   /**
2394    * Returns the bounds of the rectangle that encloses both list cells
2395    * with index0 and index1.
2396    *
2397    * @param index0 the index of the first cell
2398    * @param index1 the index of the second cell
2399    *
2400    * @return  the bounds of the rectangle that encloses both list cells
2401    *     with index0 and index1, <code>null</code> if one of the indices is
2402    *     not valid
2403    */
2404   public Rectangle getCellBounds(int index0, int index1)
2405   {
2406     ListUI ui = getUI();
2407     Rectangle bounds = null;
2408     if (ui != null)
2409       {
2410         bounds = ui.getCellBounds(this, index0, index1);
2411       }
2412     // When the UI is null, this method also returns null in the RI.
2413     return bounds;
2414   }
2415
2416   /**
2417    * Returns the index of the next list element (beginning at 
2418    * <code>startIndex</code> and moving in the specified direction through the
2419    * list, looping around if necessary) that starts with <code>prefix</code>
2420    * (ignoring case).
2421    *
2422    * @param prefix the prefix to search for in the cell values
2423    * @param startIndex the index where to start searching from
2424    * @param direction the search direction, either {@link Position.Bias#Forward}
2425    *     or {@link Position.Bias#Backward} (<code>null</code> is interpreted
2426    *     as {@link Position.Bias#Backward}.
2427    *
2428    * @return the index of the found element or -1 if no such element has
2429    *     been found
2430    *
2431    * @throws IllegalArgumentException if prefix is <code>null</code> or
2432    *     startIndex is not valid
2433    *
2434    * @since 1.4
2435    */
2436   public int getNextMatch(String prefix, int startIndex, 
2437                           Position.Bias direction)
2438   {
2439     if (prefix == null)
2440       throw new IllegalArgumentException("The argument 'prefix' must not be"
2441                                          + " null.");
2442     if (startIndex < 0)
2443       throw new IllegalArgumentException("The argument 'startIndex' must not"
2444                                          + " be less than zero.");
2445
2446     int size = model.getSize();
2447     if (startIndex >= model.getSize())
2448       throw new IllegalArgumentException("The argument 'startIndex' must not"
2449                                          + " be greater than the number of"
2450                                          + " elements in the ListModel.");
2451
2452     int result = -1;
2453     int current = startIndex;
2454     int delta = -1;
2455     int itemCount = model.getSize();
2456     boolean finished = false;
2457     prefix = prefix.toUpperCase();
2458     
2459     if (direction == Position.Bias.Forward)
2460       delta = 1;
2461     while (!finished)
2462       {
2463         String itemStr = model.getElementAt(current).toString().toUpperCase();
2464         if (itemStr.startsWith(prefix))
2465           return current;
2466         current = (current + delta);
2467         if (current == -1)
2468           current += itemCount;
2469         else
2470           current = current % itemCount; 
2471         finished = current == startIndex;
2472       }
2473     return result;
2474   }
2475   
2476   /**
2477    * Returns a string describing the attributes for the <code>JList</code>
2478    * component, for use in debugging.  The return value is guaranteed to be 
2479    * non-<code>null</code>, but the format of the string may vary between
2480    * implementations.
2481    *
2482    * @return A string describing the attributes of the <code>JList</code>.
2483    */
2484   protected String paramString()
2485   {
2486     CPStringBuilder sb = new CPStringBuilder(super.paramString());
2487     sb.append(",fixedCellHeight=").append(getFixedCellHeight());
2488     sb.append(",fixedCellWidth=").append(getFixedCellWidth());
2489     sb.append(",selectionBackground=");
2490     if (getSelectionBackground() != null)
2491       sb.append(getSelectionBackground());
2492     sb.append(",selectionForeground=");
2493     if (getSelectionForeground() != null)
2494       sb.append(getSelectionForeground());
2495     sb.append(",visibleRowCount=").append(getVisibleRowCount());
2496     sb.append(",layoutOrientation=").append(getLayoutOrientation());
2497     return sb.toString();
2498   }
2499 }