OSDN Git Service

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