Imported GNU Classpath 0.90
[official-gcc.git] / libjava / classpath / javax / swing / JList.java
blob55978a4c695b0822a85f2ebe89213b9617f6bef9
1 /* JList.java --
2 Copyright (C) 2002, 2003, 2004, 2005, 2006, Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
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.
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.
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.
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.
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. */
39 package javax.swing;
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;
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;
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>
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>
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>
118 * @author Graydon Hoare (graydon@redhat.com)
121 public class JList extends JComponent implements Accessible, Scrollable
125 * Provides accessibility support for <code>JList</code>.
127 protected class AccessibleJList extends AccessibleJComponent
128 implements AccessibleSelection, PropertyChangeListener,
129 ListSelectionListener, ListDataListener
133 * Provides accessibility support for list elements in <code>JList</code>s.
135 protected class AccessibleJListChild extends AccessibleContext
136 implements Accessible, AccessibleComponent
140 * The parent list.
142 JList parent;
145 * The index in the list for that child.
147 int listIndex;
150 * The cursor for this list child.
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();
158 * Creates a new instance of <code>AccessibleJListChild</code>.
160 * @param list the list of which this is an accessible child
161 * @param index the list index for this child
163 public AccessibleJListChild(JList list, int index)
165 parent = list;
166 listIndex = index;
170 * Returns the accessible context of this object. Returns
171 * <code>this</code> since <code>AccessibleJListChild</code>s are their
172 * own accessible contexts.
174 * @return the accessible context of this object, <code>this</code>
176 public AccessibleContext getAccessibleContext()
178 return this;
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
186 * @return the background color for this list child
188 public Color getBackground()
190 return parent.getBackground();
194 * Calling this method has no effect, since the background color cannot be
195 * set on list children individually.
197 * @param color not used here.
199 public void setBackground(Color color)
201 // Calling this method has no effect, since the background color cannot
202 // be set on list children individually.
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.
210 * @return the background color for this list child
212 public Color getForeground()
214 return parent.getForeground();
218 * Calling this method has no effect, since the foreground color cannot be
219 * set on list children individually.
221 * @param color not used here.
223 public void setForeground(Color color)
225 // Calling this method has no effect, since the foreground color cannot
226 // be set on list children individually.
230 * Returns the cursor for this list child.
232 * @return the cursor for this list child
234 public Cursor getCursor()
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;
243 * Sets the cursor for this list child.
245 public void setCursor(Cursor cursor)
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.
254 * Returns the font of the <code>JList</code> since it is not possible to
255 * set fonts for list children individually.
257 * @return the font of the <code>JList</code>
259 public Font getFont()
261 return parent.getFont();
265 * Does nothing since it is not possible to set the font on list children
266 * individually.
268 * @param font not used here
270 public void setFont(Font font)
272 // Does nothing since it is not possible to set the font on list
273 // children individually.
277 * Returns the font metrics for the specified font. This method forwards
278 * to the parent <code>JList</code>.
280 * @param font the font for which the font metrics is queried
282 * @return the font metrics for the specified font
284 public FontMetrics getFontMetrics(Font font)
286 return parent.getFontMetrics(font);
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.
294 * @return <code>true</code> if the parent <code>JList</code> is enabled,
295 * <code>false</code> otherwise
297 public boolean isEnabled()
299 return parent.isEnabled();
303 * Does nothing since the enabled flag cannot be set for list children
304 * individually.
306 * @param b not used here
308 public void setEnabled(boolean b)
310 // Does nothing since the enabled flag cannot be set for list children
311 // individually.
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()}.
320 * @return <code>true</code> if this list child is visible,
321 * <code>false</code> otherwise
323 public boolean isVisible()
325 return listIndex >= parent.getFirstVisibleIndex()
326 && listIndex <= parent.getLastVisibleIndex();
330 * The value of the visible property cannot be modified, so this method
331 * does nothing.
333 * @param b not used here
335 public void setVisible(boolean b)
337 // The value of the visible property cannot be modified, so this method
338 // does nothing.
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.
346 * @return <code>true</code> if this list child is currently showing on
347 * screen and <code>false</code> otherwise
349 public boolean isShowing()
351 return isVisible() && parent.isShowing();
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.
359 * @return <code>true</code> if this list child covers the screen location
360 * <code>point</code> , <code>false</code> otherwise
362 public boolean contains(Point point)
364 return getBounds().contains(point);
368 * Returns the absolute screen location of this list child.
370 * @return the absolute screen location of this list child
372 public Point getLocationOnScreen()
374 Point loc = getLocation();
375 SwingUtilities.convertPointToScreen(loc, parent);
376 return loc;
380 * Returns the screen location of this list child relative to it's parent.
382 * @return the location of this list child relative to it's parent
384 * @see JList#indexToLocation(int)
386 public Point getLocation()
388 return parent.indexToLocation(listIndex);
392 * Does nothing since the screen location cannot be set on list children
393 * explictitly.
395 * @param point not used here
397 public void setLocation(Point point)
399 // Does nothing since the screen location cannot be set on list children
400 // explictitly.
404 * Returns the bounds of this list child.
406 * @return the bounds of this list child
408 * @see JList#getCellBounds(int, int)
410 public Rectangle getBounds()
412 return parent.getCellBounds(listIndex, listIndex);
416 * Does nothing since the bounds cannot be set on list children
417 * individually.
419 * @param rectangle not used here
421 public void setBounds(Rectangle rectangle)
423 // Does nothing since the bounds cannot be set on list children
424 // individually.
428 * Returns the size of this list child.
430 * @return the size of this list child
432 public Dimension getSize()
434 Rectangle b = getBounds();
435 return b.getSize();
439 * Does nothing since the size cannot be set on list children
440 * individually.
442 * @param dimension not used here
444 public void setSize(Dimension dimension)
446 // Does nothing since the size cannot be set on list children
447 // individually.
451 * Returns <code>null</code> because list children do not have children
452 * themselves
454 * @return <code>null</code>
456 public Accessible getAccessibleAt(Point point)
458 return null;
462 * Returns <code>true</code> since list children are focus traversable.
464 * @return true
466 public boolean isFocusTraversable()
468 // TODO: Is this 100% ok?
469 return true;
473 * Requests focus on the parent list. List children cannot request focus
474 * individually.
476 public void requestFocus()
478 // TODO: Is this 100% ok?
479 parent.requestFocus();
483 * Adds a focus listener to the parent list. List children do not have
484 * their own focus management.
486 * @param listener the focus listener to add
488 public void addFocusListener(FocusListener listener)
490 // TODO: Is this 100% ok?
491 parent.addFocusListener(listener);
495 * Removes a focus listener from the parent list. List children do not
496 * have their own focus management.
498 * @param listener the focus listener to remove
500 public void removeFocusListener(FocusListener listener)
502 // TODO: Is this 100%
503 parent.removeFocusListener(listener);
507 * Returns the accessible role of this list item, which is
508 * {@link AccessibleRole#LABEL}.
510 * @return {@link AccessibleRole#LABEL}
512 public AccessibleRole getAccessibleRole()
514 return AccessibleRole.LABEL;
518 * Returns the accessible state set of this list item.
520 * @return the accessible state set of this list item
522 public AccessibleStateSet getAccessibleStateSet()
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.
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);
541 if (parent.isSelectedIndex(listIndex))
542 states.add(AccessibleState.SELECTED);
544 // TODO: Handle more states here?
545 return states;
549 * Returns the index of this list child within it's parent list.
551 * @return the index of this list child within it's parent list
553 public int getAccessibleIndexInParent()
555 return listIndex;
559 * Returns <code>0</code> since list children don't have children
560 * themselves.
562 * @return <code>0</code>
564 public int getAccessibleChildrenCount()
566 return 0;
570 * Returns <code>null</code> since list children don't have children
571 * themselves.
573 * @return <code>null</code>
575 public Accessible getAccessibleChild(int i)
577 return null;
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.
584 * @return the locale of this component
586 public Locale getLocale()
588 return parent.getLocale();
592 * This method does
593 * nothing, list children are transient accessible objects which means
594 * that they don't fire property change events.
596 * @param l not used here
598 public void addPropertyChangeListener(PropertyChangeListener l)
600 // Do nothing here.
604 * This method does
605 * nothing, list children are transient accessible objects which means
606 * that they don't fire property change events.
608 * @param l not used here
610 public void removePropertyChangeListener(PropertyChangeListener l)
612 // Do nothing here.
615 // TODO: Implement the remaining methods of this class.
619 * Create a new AccessibleJList.
621 public AccessibleJList()
623 // Nothing to do here.
627 * Returns the number of selected accessible children.
629 * @return the number of selected accessible children
631 public int getAccessibleSelectionCount()
633 return getSelectedIndices().length;
637 * Returns the n-th selected accessible child.
639 * @param n the index of the selected child to return
641 * @return the n-th selected accessible child
643 public Accessible getAccessibleSelection(int n)
645 return new AccessibleJListChild(JList.this, getSelectedIndices()[n]);
649 * Returns <code>true</code> if the n-th child is selected,
650 * <code>false</code> otherwise.
652 * @param n the index of the child of which the selected state is queried
654 * @return <code>true</code> if the n-th child is selected,
655 * <code>false</code> otherwise
657 public boolean isAccessibleChildSelected(int n)
659 return isSelectedIndex(n);
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.
667 * @param i the index of the item to add to the selection
669 public void addAccessibleSelection(int i)
671 addSelectionInterval(i, i);
675 * Removes the accessible item with the specified index to the selection.
677 * @param i the index of the item to be removed from the selection
679 public void removeAccessibleSelection(int i)
681 removeSelectionInterval(i, i);
685 * Remove all selection items from the selection.
687 public void clearAccessibleSelection()
689 clearSelection();
693 * Selects all items if multiple selections are supported.
694 * Otherwise do nothing.
696 public void selectAllAccessibleSelection()
698 addSelectionInterval(0, getModel().getSize());
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}.
707 * @param event the list selection event
709 public void valueChanged(ListSelectionEvent event)
711 firePropertyChange(ACCESSIBLE_VISIBLE_DATA_PROPERTY, Boolean.FALSE,
712 Boolean.TRUE);
713 firePropertyChange(ACCESSIBLE_SELECTION_PROPERTY, Boolean.FALSE,
714 Boolean.TRUE);
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}.
722 * @param event the list data event
724 public void contentsChanged(ListDataEvent event)
726 firePropertyChange(ACCESSIBLE_VISIBLE_DATA_PROPERTY, Boolean.FALSE,
727 Boolean.TRUE);
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}.
735 * @param event the list data event
737 public void intervalAdded(ListDataEvent event)
739 firePropertyChange(ACCESSIBLE_VISIBLE_DATA_PROPERTY, Boolean.FALSE,
740 Boolean.TRUE);
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}.
748 * @param event the list data event
750 public void intervalRemoved(ListDataEvent event)
752 firePropertyChange(ACCESSIBLE_VISIBLE_DATA_PROPERTY, Boolean.FALSE,
753 Boolean.TRUE);
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.
763 * @param e the property change event
765 public void propertyChange(PropertyChangeEvent e)
767 String propertyName = e.getPropertyName();
768 if (propertyName.equals("model"))
770 ListModel oldModel = (ListModel) e.getOldValue();
771 oldModel.removeListDataListener(this);
772 ListModel newModel = (ListModel) e.getNewValue();
773 newModel.addListDataListener(this);
775 else if (propertyName.equals("selectionModel"))
777 ListSelectionModel oldModel = (ListSelectionModel) e.getOldValue();
778 oldModel.removeListSelectionListener(this);
779 ListSelectionModel newModel = (ListSelectionModel) e.getNewValue();
780 oldModel.addListSelectionListener(this);
785 * Return the state set of the <code>JList</code>.
787 * @return the state set of the <code>JList</code>
789 public AccessibleStateSet getAccessibleStateSet()
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;
800 * Returns the accessible role for <code>JList</code>,
801 * {@link AccessibleRole#LIST}.
803 * @return the accessible role for <code>JList</code>
805 public AccessibleRole getAccessibleRole()
807 return AccessibleRole.LIST;
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>.
815 * @param p the screen location for which to return the accessible child
817 * @return the accessible child at the specified location, or
818 * <code>null</code> if there is no child at that location
820 public Accessible getAccessibleAt(Point p)
822 int childIndex = locationToIndex(p);
823 return getAccessibleChild(childIndex);
827 * Returns the number of accessible children in the <code>JList</code>.
829 * @return the number of accessible children in the <code>JList</code>
831 public int getAccessibleChildrenCount()
833 return getModel().getSize();
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.
841 * @param n the index of the child to return
843 * @return the n-th accessible child of this <code>JList</code>
845 public Accessible getAccessibleChild(int n)
847 if (getModel().getSize() <= n)
848 return null;
849 return new AccessibleJListChild(JList.this, n);
853 private static final long serialVersionUID = 4406629526391098046L;
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.
859 public static final int VERTICAL = 0;
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.
866 public static final int VERTICAL_WRAP = 1;
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.
873 public static final int HORIZONTAL_WRAP = 2;
876 * This property indicates whether "drag and drop" functions are enabled
877 * on the list.
879 boolean dragEnabled;
881 /** This property provides a strategy for rendering cells in the list. */
882 ListCellRenderer cellRenderer;
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.
890 int fixedCellWidth;
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.
898 int fixedCellHeight;
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}.
905 int layoutOrientation;
907 /** This property holds the data elements displayed by the list. */
908 ListModel model;
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>
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>
922 Object prototypeCellValue;
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.
930 Color selectionBackground;
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.
938 Color selectionForeground;
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.
945 ListSelectionModel selectionModel;
949 * This property indicates that the list's selection is currently
950 * "adjusting" -- perhaps due to a user actively dragging the mouse over
951 * multiple list elements -- and is therefore likely to change again in
952 * the near future. A {@link ListSelectionListener} might choose to delay
953 * updating its view of the list's selection until this property is
954 * false, meaning that the adjustment has completed.
956 boolean valueIsAdjusting;
958 /**
959 * This property indicates a <em>preference</em> for the number of rows
960 * displayed in the list, and will scale the
961 * {@link #getPreferredScrollableViewportSize} property accordingly. The actual
962 * number of displayed rows, when the list is placed in a real {@link
963 * JViewport} or other component, may be greater or less than this number.
965 int visibleRowCount;
968 * Fire a {@link ListSelectionEvent} to all the registered
969 * ListSelectionListeners.
971 * @param firstIndex the lowest index covering the selection change.
972 * @param lastIndex the highest index covering the selection change.
973 * @param isAdjusting a flag indicating if this event is one in a series
974 * of events updating the selection.
976 protected void fireSelectionValueChanged(int firstIndex, int lastIndex,
977 boolean isAdjusting)
979 ListSelectionEvent evt = new ListSelectionEvent(this, firstIndex,
980 lastIndex, isAdjusting);
981 ListSelectionListener listeners[] = getListSelectionListeners();
982 for (int i = 0; i < listeners.length; ++i)
984 listeners[i].valueChanged(evt);
989 * This private listener propagates {@link ListSelectionEvent} events
990 * from the list's "selectionModel" property to the list's {@link
991 * ListSelectionListener} listeners. It also listens to {@link
992 * ListDataEvent} events from the list's {@link #model} property. If this
993 * class receives either type of event, it triggers repainting of the
994 * list.
996 private class ListListener
997 implements ListSelectionListener, ListDataListener
999 // ListDataListener events
1000 public void contentsChanged(ListDataEvent event)
1002 JList.this.revalidate();
1003 JList.this.repaint();
1005 public void intervalAdded(ListDataEvent event)
1007 JList.this.revalidate();
1008 JList.this.repaint();
1010 public void intervalRemoved(ListDataEvent event)
1012 JList.this.revalidate();
1013 JList.this.repaint();
1015 // ListSelectionListener events
1016 public void valueChanged(ListSelectionEvent event)
1018 JList.this.fireSelectionValueChanged(event.getFirstIndex(),
1019 event.getLastIndex(),
1020 event.getValueIsAdjusting());
1021 JList.this.repaint();
1025 /**
1026 * Shared ListListener instance, subscribed to both the current {@link
1027 * #model} and {@link #selectionModel} properties of the list.
1029 ListListener listListener;
1033 * Creates a new <code>JList</code> object.
1035 public JList()
1037 init(new DefaultListModel());
1041 * Creates a new <code>JList</code> object.
1043 * @param items the initial list items.
1045 public JList(Object[] items)
1047 init(createListModel(items));
1051 * Creates a new <code>JList</code> object.
1053 * @param items the initial list items.
1055 public JList(Vector items)
1057 init(createListModel(items));
1061 * Creates a new <code>JList</code> object.
1063 * @param model a model containing the list items (<code>null</code> not
1064 * permitted).
1066 * @throws IllegalArgumentException if <code>model</code> is
1067 * <code>null</code>.
1069 public JList(ListModel model)
1071 init(model);
1075 * Initializes the list.
1077 * @param m the list model (<code>null</code> not permitted).
1079 private void init(ListModel m)
1081 if (m == null)
1082 throw new IllegalArgumentException("Null model not permitted.");
1083 dragEnabled = false;
1084 fixedCellHeight = -1;
1085 fixedCellWidth = -1;
1086 layoutOrientation = VERTICAL;
1087 opaque = true;
1088 valueIsAdjusting = false;
1089 visibleRowCount = 7;
1091 cellRenderer = new DefaultListCellRenderer();
1092 listListener = new ListListener();
1094 model = m;
1095 if (model != null)
1096 model.addListDataListener(listListener);
1098 selectionModel = createSelectionModel();
1099 if (selectionModel != null)
1101 selectionModel.addListSelectionListener(listListener);
1102 selectionModel.setSelectionMode
1103 (ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
1105 setLayout(null);
1107 updateUI();
1111 * Creates the default <code>ListSelectionModel</code>.
1113 * @return the <code>ListSelectionModel</code>
1115 protected ListSelectionModel createSelectionModel()
1117 return new DefaultListSelectionModel();
1121 * Gets the value of the {@link #fixedCellHeight} property. This property
1122 * may be <code>-1</code> to indicate that no cell height has been
1123 * set. This property is also set implicitly when the
1124 * {@link #prototypeCellValue} property is set.
1126 * @return The current value of the property
1128 * @see #fixedCellHeight
1129 * @see #setFixedCellHeight
1130 * @see #setPrototypeCellValue
1132 public int getFixedCellHeight()
1134 return fixedCellHeight;
1138 * Sets the value of the {@link #fixedCellHeight} property. This property
1139 * may be <code>-1</code> to indicate that no cell height has been
1140 * set. This property is also set implicitly when the {@link
1141 * #prototypeCellValue} property is set, but setting it explicitly
1142 * overrides the height computed from {@link #prototypeCellValue}.
1144 * @param h the height.
1146 * @see #getFixedCellHeight
1147 * @see #getPrototypeCellValue
1149 public void setFixedCellHeight(int h)
1151 if (fixedCellHeight == h)
1152 return;
1154 int old = fixedCellHeight;
1155 fixedCellHeight = h;
1156 firePropertyChange("fixedCellHeight", old, h);
1161 * Gets the value of the {@link #fixedCellWidth} property. This property
1162 * may be <code>-1</code> to indicate that no cell width has been
1163 * set. This property is also set implicitly when the {@link
1164 * #prototypeCellValue} property is set.
1166 * @return The current value of the property
1168 * @see #setFixedCellWidth
1169 * @see #setPrototypeCellValue
1171 public int getFixedCellWidth()
1173 return fixedCellWidth;
1177 * Sets the value of the {@link #fixedCellWidth} property. This property
1178 * may be <code>-1</code> to indicate that no cell width has been
1179 * set. This property is also set implicitly when the {@link
1180 * #prototypeCellValue} property is set, but setting it explicitly
1181 * overrides the width computed from {@link #prototypeCellValue}.
1183 * @param w the width.
1185 * @see #getFixedCellHeight
1186 * @see #getPrototypeCellValue
1188 public void setFixedCellWidth(int w)
1190 if (fixedCellWidth == w)
1191 return;
1193 int old = fixedCellWidth;
1194 fixedCellWidth = w;
1195 firePropertyChange("fixedCellWidth", old, w);
1198 /**
1199 * Gets the value of the {@link #visibleRowCount} property.
1201 * @return the current value of the property.
1204 public int getVisibleRowCount()
1206 return visibleRowCount;
1210 * Sets the value of the {@link #visibleRowCount} property.
1212 * @param vc The new property value
1214 public void setVisibleRowCount(int vc)
1216 visibleRowCount = vc;
1217 revalidate();
1218 repaint();
1222 * Adds a {@link ListSelectionListener} to the listener list for this
1223 * list. The listener will be called back with a {@link
1224 * ListSelectionEvent} any time the list's {@link #selectionModel}
1225 * property changes. The source of such events will be the JList,
1226 * not the selection model.
1228 * @param listener The new listener to add
1230 public void addListSelectionListener(ListSelectionListener listener)
1232 listenerList.add (ListSelectionListener.class, listener);
1236 * Removes a {@link ListSelectionListener} from the listener list for
1237 * this list. The listener will no longer be called when the list's
1238 * {@link #selectionModel} changes.
1240 * @param listener The listener to remove
1242 public void removeListSelectionListener(ListSelectionListener listener)
1244 listenerList.remove(ListSelectionListener.class, listener);
1248 * Returns an array of all ListSelectionListeners subscribed to this
1249 * list.
1251 * @return The current subscribed listeners
1253 * @since 1.4
1255 public ListSelectionListener[] getListSelectionListeners()
1257 return (ListSelectionListener[]) getListeners(ListSelectionListener.class);
1261 * Returns the selection mode for the list (one of:
1262 * {@link ListSelectionModel#SINGLE_SELECTION},
1263 * {@link ListSelectionModel#SINGLE_INTERVAL_SELECTION} and
1264 * {@link ListSelectionModel#MULTIPLE_INTERVAL_SELECTION}).
1266 * @return The selection mode.
1268 * @see #setSelectionMode(int)
1270 public int getSelectionMode()
1272 return selectionModel.getSelectionMode();
1276 * Sets the list's "selectionMode" property, which simply mirrors the
1277 * same property on the list's {@link #selectionModel} property. This
1278 * property should be one of the integer constants
1279 * <code>SINGLE_SELECTION</code>, <code>SINGLE_INTERVAL_SELECTION</code>,
1280 * or <code>MULTIPLE_INTERVAL_SELECTION</code> from the {@link
1281 * ListSelectionModel} interface.
1283 * @param a The new selection mode
1285 public void setSelectionMode(int a)
1287 selectionModel.setSelectionMode(a);
1291 * Adds the interval <code>[a,a]</code> to the set of selections managed
1292 * by this list's {@link #selectionModel} property. Depending on the
1293 * selection mode, this may cause existing selections to become invalid,
1294 * or may simply expand the set of selections.
1296 * @param a A number in the half-open range <code>[0, x)</code> where
1297 * <code>x = getModel.getSize()</code>, indicating the index of an
1298 * element in the list to select. When &lt; 0 the selection is cleared.
1300 * @see #setSelectionMode
1301 * @see #selectionModel
1303 public void setSelectedIndex(int a)
1305 if (a < 0)
1306 selectionModel.clearSelection();
1307 else
1308 selectionModel.setSelectionInterval(a, a);
1312 * For each element <code>a[i]</code> of the provided array
1313 * <code>a</code>, calls {@link #setSelectedIndex} on <code>a[i]</code>.
1315 * @param a an array of selected indices (<code>null</code> not permitted).
1317 * @throws NullPointerException if <code>a</code> is <code>null</code>.
1318 * @see #setSelectionMode
1319 * @see #selectionModel
1321 public void setSelectedIndices(int [] a)
1323 for (int i = 0; i < a.length; ++i)
1324 setSelectedIndex(a[i]);
1328 * Returns the minimum index of an element in the list which is currently
1329 * selected.
1331 * @return A number in the half-open range <code>[0, x)</code> where
1332 * <code>x = getModel.getSize()</code>, indicating the minimum index of
1333 * an element in the list for which the element is selected, or
1334 * <code>-1</code> if no elements are selected
1336 public int getSelectedIndex()
1338 return selectionModel.getMinSelectionIndex();
1342 * Returns <code>true</code> if the model's selection is empty, otherwise
1343 * <code>false</code>.
1345 * @return The return value of {@link ListSelectionModel#isSelectionEmpty}
1347 public boolean isSelectionEmpty()
1349 return selectionModel.isSelectionEmpty();
1353 * Returns the list index of the upper left or upper right corner of the
1354 * visible rectangle of this list, depending on the {@link
1355 * Component#getComponentOrientation} property.
1357 * @return The index of the first visible list cell, or <code>-1</code>
1358 * if none is visible.
1360 public int getFirstVisibleIndex()
1362 ComponentOrientation or = getComponentOrientation();
1363 Rectangle r = getVisibleRect();
1364 if (or == ComponentOrientation.RIGHT_TO_LEFT)
1365 r.translate((int) r.getWidth() - 1, 0);
1366 return getUI().locationToIndex(this, r.getLocation());
1371 * Returns index of the cell to which specified location is closest to. If
1372 * the location is outside the bounds of the list, then the greatest index
1373 * in the list model is returned. If the list model is empty, then
1374 * <code>-1</code> is returned.
1376 * @param location for which to look for in the list
1378 * @return index of the cell to which specified location is closest to.
1380 public int locationToIndex(Point location)
1382 return getUI().locationToIndex(this, location);
1386 * Returns location of the cell located at the specified index in the list.
1387 * @param index of the cell for which location will be determined
1389 * @return location of the cell located at the specified index in the list.
1391 public Point indexToLocation(int index)
1393 return getUI().indexToLocation(this, index);
1397 * Returns the list index of the lower right or lower left corner of the
1398 * visible rectangle of this list, depending on the {@link
1399 * Component#getComponentOrientation} property.
1401 * @return The index of the last visible list cell, or <code>-1</code>
1402 * if none is visible.
1404 public int getLastVisibleIndex()
1406 ComponentOrientation or = getComponentOrientation();
1407 Rectangle r = getVisibleRect();
1408 r.translate(0, (int) r.getHeight() - 1);
1409 if (or == ComponentOrientation.LEFT_TO_RIGHT)
1410 r.translate((int) r.getWidth() - 1, 0);
1411 if (getUI().locationToIndex(this, r.getLocation()) == -1
1412 && indexToLocation(getModel().getSize() - 1).y < r.y)
1413 return getModel().getSize() - 1;
1414 return getUI().locationToIndex(this, r.getLocation());
1418 * Returns the indices of values in the {@link #model} property which are
1419 * selected.
1421 * @return An array of model indices, each of which is selected according
1422 * to the {@link #getSelectedValues} property
1424 public int[] getSelectedIndices()
1426 int lo, hi, n, i, j;
1427 if (selectionModel.isSelectionEmpty())
1428 return new int[0];
1429 lo = selectionModel.getMinSelectionIndex();
1430 hi = selectionModel.getMaxSelectionIndex();
1431 n = 0;
1432 for (i = lo; i <= hi; ++i)
1433 if (selectionModel.isSelectedIndex(i))
1434 n++;
1435 int [] v = new int[n];
1436 j = 0;
1437 for (i = lo; i <= hi; ++i)
1438 if (selectionModel.isSelectedIndex(i))
1439 v[j++] = i;
1440 return v;
1444 * Indicates whether the list element at a given index value is
1445 * currently selected.
1447 * @param a The index to check
1448 * @return <code>true</code> if <code>a</code> is the index of a selected
1449 * list element
1451 public boolean isSelectedIndex(int a)
1453 return selectionModel.isSelectedIndex(a);
1457 * Returns the first value in the list's {@link #model} property which is
1458 * selected, according to the list's {@link #selectionModel} property.
1459 * This is equivalent to calling
1460 * <code>getModel()getElementAt(getSelectedIndex())</code>, with a check
1461 * for the special index value of <code>-1</code> which returns null
1462 * <code>null</code>.
1464 * @return The first selected element, or <code>null</code> if no element
1465 * is selected.
1467 * @see #getSelectedValues
1469 public Object getSelectedValue()
1471 int index = getSelectedIndex();
1472 if (index == -1)
1473 return null;
1474 return getModel().getElementAt(index);
1478 * Returns all the values in the list's {@link #model} property which
1479 * are selected, according to the list's {@link #selectionModel} property.
1481 * @return An array containing all the selected values
1483 * @see #setSelectedValue
1485 public Object[] getSelectedValues()
1487 int [] idx = getSelectedIndices();
1488 Object [] v = new Object[idx.length];
1489 for (int i = 0; i < idx.length; ++i)
1490 v[i] = getModel().getElementAt(i);
1491 return v;
1495 * Gets the value of the {@link #selectionBackground} property.
1497 * @return The current value of the property
1499 public Color getSelectionBackground()
1501 return selectionBackground;
1505 * Sets the value of the {@link #selectionBackground} property.
1507 * @param c The new value of the property
1509 public void setSelectionBackground(Color c)
1511 if (selectionBackground == c)
1512 return;
1514 Color old = selectionBackground;
1515 selectionBackground = c;
1516 firePropertyChange("selectionBackground", old, c);
1517 repaint();
1521 * Gets the value of the {@link #selectionForeground} property.
1523 * @return The current value of the property
1525 public Color getSelectionForeground()
1527 return selectionForeground;
1531 * Sets the value of the {@link #selectionForeground} property.
1533 * @param c The new value of the property
1535 public void setSelectionForeground(Color c)
1537 if (selectionForeground == c)
1538 return;
1540 Color old = selectionForeground;
1541 selectionForeground = c;
1542 firePropertyChange("selectionForeground", old, c);
1546 * Sets the selection to cover only the specified value, if it
1547 * exists in the model.
1549 * @param obj The object to select
1550 * @param scroll Whether to scroll the list to make the newly selected
1551 * value visible
1553 * @see #ensureIndexIsVisible
1556 public void setSelectedValue(Object obj, boolean scroll)
1558 for (int i = 0; i < model.getSize(); ++i)
1560 if (model.getElementAt(i).equals(obj))
1562 setSelectedIndex(i);
1563 if (scroll)
1564 ensureIndexIsVisible(i);
1565 break;
1571 * Scrolls this list to make the specified cell visible. This
1572 * only works if the list is contained within a viewport.
1574 * @param i The list index to make visible
1576 * @see JComponent#scrollRectToVisible
1578 public void ensureIndexIsVisible(int i)
1580 Rectangle r = getUI().getCellBounds(this, i, i);
1581 if (r != null)
1582 scrollRectToVisible(r);
1586 * Sets the {@link #model} property of the list to a new anonymous
1587 * {@link AbstractListModel} subclass which accesses the provided Object
1588 * array directly.
1590 * @param listData The object array to build a new list model on
1591 * @see #setModel
1593 public void setListData(Object[] listData)
1595 setModel(createListModel(listData));
1599 * Returns a {@link ListModel} backed by the specified array.
1601 * @param items the list items (don't use <code>null</code>).
1603 * @return A list model containing the specified items.
1605 private ListModel createListModel(final Object[] items)
1607 return new AbstractListModel()
1609 public int getSize()
1611 return items.length;
1613 public Object getElementAt(int i)
1615 return items[i];
1621 * Returns a {@link ListModel} backed by the specified vector.
1623 * @param items the list items (don't use <code>null</code>).
1625 * @return A list model containing the specified items.
1627 private ListModel createListModel(final Vector items)
1629 return new AbstractListModel()
1631 public int getSize()
1633 return items.size();
1635 public Object getElementAt(int i)
1637 return items.get(i);
1643 * Sets the {@link #model} property of the list to a new anonymous {@link
1644 * AbstractListModel} subclass which accesses the provided vector
1645 * directly.
1647 * @param listData The object array to build a new list model on
1648 * @see #setModel
1650 public void setListData(Vector listData)
1652 setModel(createListModel(listData));
1656 * Gets the value of the {@link #cellRenderer} property.
1658 * @return The current value of the property
1660 public ListCellRenderer getCellRenderer()
1662 return cellRenderer;
1666 * Sets the value of the {@link #getCellRenderer} property.
1668 * @param renderer The new property value
1670 public void setCellRenderer(ListCellRenderer renderer)
1672 if (cellRenderer == renderer)
1673 return;
1675 ListCellRenderer old = cellRenderer;
1676 cellRenderer = renderer;
1677 firePropertyChange("cellRenderer", old, renderer);
1678 revalidate();
1679 repaint();
1683 * Gets the value of the {@link #model} property.
1685 * @return The current value of the property
1687 public ListModel getModel()
1689 return model;
1693 * Sets the value of the {@link #model} property. The list's {@link
1694 * #listListener} is unsubscribed from the existing model, if it exists,
1695 * and re-subscribed to the new model.
1697 * @param model the new model (<code>null</code> not permitted).
1699 * @throws IllegalArgumentException if <code>model</code> is
1700 * <code>null</code>.
1702 public void setModel(ListModel model)
1704 if (model == null)
1705 throw new IllegalArgumentException("Null 'model' argument.");
1706 if (this.model == model)
1707 return;
1709 if (this.model != null)
1710 this.model.removeListDataListener(listListener);
1712 ListModel old = this.model;
1713 this.model = model;
1715 if (this.model != null)
1716 this.model.addListDataListener(listListener);
1718 firePropertyChange("model", old, model);
1719 revalidate();
1720 repaint();
1724 * Returns the selection model for the {@link JList} component. Note that
1725 * this class contains a range of convenience methods for configuring the
1726 * selection model:<br>
1727 * <ul>
1728 * <li>{@link #clearSelection()};</li>
1729 * <li>{@link #setSelectionMode(int)};</li>
1730 * <li>{@link #addSelectionInterval(int, int)};</li>
1731 * <li>{@link #setSelectedIndex(int)};</li>
1732 * <li>{@link #setSelectedIndices(int[])};</li>
1733 * <li>{@link #setSelectionInterval(int, int)}.</li>
1734 * </ul>
1736 * @return The selection model.
1738 public ListSelectionModel getSelectionModel()
1740 return selectionModel;
1744 * Sets the value of the {@link #selectionModel} property. The list's
1745 * {@link #listListener} is unsubscribed from the existing selection
1746 * model, if it exists, and re-subscribed to the new selection model.
1748 * @param model The new property value
1750 public void setSelectionModel(ListSelectionModel model)
1752 if (selectionModel == model)
1753 return;
1755 if (selectionModel != null)
1756 selectionModel.removeListSelectionListener(listListener);
1758 ListSelectionModel old = selectionModel;
1759 selectionModel = model;
1761 if (selectionModel != null)
1762 selectionModel.addListSelectionListener(listListener);
1764 firePropertyChange("selectionModel", old, model);
1765 revalidate();
1766 repaint();
1770 * Gets the value of the UI property.
1772 * @return The current property value
1774 public ListUI getUI()
1776 return (ListUI) ui;
1780 * Sets the value of the UI property.
1782 * @param ui The new property value
1784 public void setUI(ListUI ui)
1786 super.setUI(ui);
1790 * Calls {@link #setUI} with the {@link ListUI} subclass
1791 * returned from calling {@link UIManager#getUI}.
1793 public void updateUI()
1795 setUI((ListUI) UIManager.getUI(this));
1799 * Return the class identifier for the list's UI property. This should
1800 * be the constant string <code>"ListUI"</code>, and map to an
1801 * appropriate UI class in the {@link UIManager}.
1803 * @return The class identifier
1805 public String getUIClassID()
1807 return "ListUI";
1812 * Returns the current value of the {@link #prototypeCellValue}
1813 * property. This property holds a reference to a "prototype" data value
1814 * -- typically a String -- which is used to calculate the {@link
1815 * #fixedCellWidth} and {@link #fixedCellHeight} properties, using the
1816 * {@link #cellRenderer} property to acquire a component to render the
1817 * prototype.
1819 * @return The current prototype cell value
1820 * @see #setPrototypeCellValue
1822 public Object getPrototypeCellValue()
1824 return prototypeCellValue;
1828 * <p>Set the {@link #prototypeCellValue} property. This property holds a
1829 * reference to a "prototype" data value -- typically a String -- which
1830 * is used to calculate the {@link #fixedCellWidth} and {@link
1831 * #fixedCellHeight} properties, using the {@link #cellRenderer} property
1832 * to acquire a component to render the prototype.</p>
1834 * <p>It is important that you <em>not</em> set this value to a
1835 * component. It has to be a <em>data value</em> such as the objects you
1836 * would find in the list's model. Setting it to a component will have
1837 * undefined (and undesirable) affects. </p>
1839 * @param obj The new prototype cell value
1840 * @see #getPrototypeCellValue
1842 public void setPrototypeCellValue(Object obj)
1844 if (prototypeCellValue == obj)
1845 return;
1847 Object old = prototypeCellValue;
1848 Component comp = getCellRenderer()
1849 .getListCellRendererComponent(this, obj, 0, false, false);
1850 Dimension d = comp.getPreferredSize();
1851 fixedCellWidth = d.width;
1852 fixedCellHeight = d.height;
1853 prototypeCellValue = obj;
1854 firePropertyChange("prototypeCellValue", old, obj);
1857 public AccessibleContext getAccessibleContext()
1859 return new AccessibleJList();
1863 * Returns a size indicating how much space this list would like to
1864 * consume, when contained in a scrollable viewport. This is part of the
1865 * {@link Scrollable} interface, which interacts with {@link
1866 * ScrollPaneLayout} and {@link JViewport} to define scrollable objects.
1868 * @return The preferred size
1870 public Dimension getPreferredScrollableViewportSize()
1872 //If the layout orientation is not VERTICAL, then this will
1873 //return the value from getPreferredSize. The current ListUI is
1874 //expected to override getPreferredSize to return an appropriate value.
1875 if (getLayoutOrientation() != VERTICAL)
1876 return getPreferredSize();
1878 int size = getModel().getSize();
1880 // Trivial case: if fixedCellWidth and fixedCellHeight were set
1881 // just use them
1882 if (fixedCellHeight != -1 && fixedCellWidth != -1)
1883 return new Dimension(fixedCellWidth, size * fixedCellHeight);
1885 // If the model is empty we use 16 * the number of visible rows
1886 // for the height and either fixedCellWidth (if set) or 256
1887 // for the width
1888 if (size == 0)
1890 if (fixedCellWidth == -1)
1891 return new Dimension(256, 16 * getVisibleRowCount());
1892 else
1893 return new Dimension(fixedCellWidth, 16 * getVisibleRowCount());
1896 // Calculate the width: if fixedCellWidth was set use that, otherwise
1897 // use the preferredWidth
1898 int prefWidth;
1899 if (fixedCellWidth != -1)
1900 prefWidth = fixedCellWidth;
1901 else
1902 prefWidth = getPreferredSize().width;
1904 // Calculate the height: if fixedCellHeight was set use that, otherwise
1905 // use the height of the first row multiplied by the number of visible
1906 // rows
1907 int prefHeight;
1908 if (fixedCellHeight != -1)
1909 prefHeight = fixedCellHeight;
1910 else
1911 prefHeight = getVisibleRowCount() * getCellBounds(0, 0).height;
1913 return new Dimension (prefWidth, prefHeight);
1917 * <p>Return the number of pixels the list must scroll in order to move a
1918 * "unit" of the list into the provided visible rectangle. When the
1919 * provided direction is positive, the call describes a "downwards"
1920 * scroll, which will be exposing a cell at a <em>greater</em> index in
1921 * the list than those elements currently showing. Then the provided
1922 * direction is negative, the call describes an "upwards" scroll, which
1923 * will be exposing a cell at a <em>lesser</em> index in the list than
1924 * those elements currently showing.</p>
1926 * <p>If the provided orientation is <code>HORIZONTAL</code>, the above
1927 * comments refer to "rightwards" for positive direction, and "leftwards"
1928 * for negative.</p>
1931 * @param visibleRect The rectangle to scroll an element into
1932 * @param orientation One of the numeric consants <code>VERTICAL</code>
1933 * or <code>HORIZONTAL</code>
1934 * @param direction An integer indicating the scroll direction: positive means
1935 * forwards (down, right), negative means backwards (up, left)
1937 * @return The scrollable unit increment, in pixels
1939 public int getScrollableUnitIncrement(Rectangle visibleRect,
1940 int orientation, int direction)
1942 ListUI lui = this.getUI();
1943 if (orientation == SwingConstants.VERTICAL)
1945 if (direction > 0)
1947 // Scrolling down
1948 Point bottomLeft = new Point(visibleRect.x,
1949 visibleRect.y + visibleRect.height);
1950 int curIdx = lui.locationToIndex(this, bottomLeft);
1951 Rectangle curBounds = lui.getCellBounds(this, curIdx, curIdx);
1952 if (curBounds.y + curBounds.height == bottomLeft.y)
1954 // we are at the exact bottom of the current cell, so we
1955 // are being asked to scroll to the end of the next one
1956 if (curIdx + 1 < model.getSize())
1958 // there *is* a next item in the list
1959 Rectangle nxtBounds = lui.getCellBounds(this, curIdx + 1, curIdx + 1);
1960 return nxtBounds.height;
1962 else
1964 // no next item, no advance possible
1965 return 0;
1968 else
1970 // we are part way through an existing cell, so we are being
1971 // asked to scroll to the bottom of it
1972 return (curBounds.y + curBounds.height) - bottomLeft.y;
1975 else
1977 // scrolling up
1978 Point topLeft = new Point(visibleRect.x, visibleRect.y);
1979 int curIdx = lui.locationToIndex(this, topLeft);
1980 Rectangle curBounds = lui.getCellBounds(this, curIdx, curIdx);
1981 if (curBounds.y == topLeft.y)
1983 // we are at the exact top of the current cell, so we
1984 // are being asked to scroll to the top of the previous one
1985 if (curIdx > 0)
1987 // there *is* a previous item in the list
1988 Rectangle nxtBounds = lui.getCellBounds(this, curIdx - 1, curIdx - 1);
1989 return -nxtBounds.height;
1991 else
1993 // no previous item, no advance possible
1994 return 0;
1997 else
1999 // we are part way through an existing cell, so we are being
2000 // asked to scroll to the top of it
2001 return curBounds.y - topLeft.y;
2006 // FIXME: handle horizontal scrolling (also wrapping?)
2007 return 1;
2011 * <p>Return the number of pixels the list must scroll in order to move a
2012 * "block" of the list into the provided visible rectangle. When the
2013 * provided direction is positive, the call describes a "downwards"
2014 * scroll, which will be exposing a cell at a <em>greater</em> index in
2015 * the list than those elements currently showing. Then the provided
2016 * direction is negative, the call describes an "upwards" scroll, which
2017 * will be exposing a cell at a <em>lesser</em> index in the list than
2018 * those elements currently showing.</p>
2020 * <p>If the provided orientation is <code>HORIZONTAL</code>, the above
2021 * comments refer to "rightwards" for positive direction, and "leftwards"
2022 * for negative.</p>
2025 * @param visibleRect The rectangle to scroll an element into
2026 * @param orientation One of the numeric consants <code>VERTICAL</code>
2027 * or <code>HORIZONTAL</code>
2028 * @param direction An integer indicating the scroll direction: positive means
2029 * forwards (down, right), negative means backwards (up, left)
2031 * @return The scrollable unit increment, in pixels
2033 public int getScrollableBlockIncrement(Rectangle visibleRect,
2034 int orientation, int direction)
2036 if (orientation == VERTICAL)
2037 return visibleRect.height * direction;
2038 else
2039 return visibleRect.width * direction;
2043 * Gets the value of the <code>scrollableTracksViewportWidth</code> property.
2045 * @return <code>true</code> if the viewport is larger (horizontally)
2046 * than the list and the list should be expanded to fit the viewport;
2047 * <code>false</code> if the viewport is smaller than the list and the
2048 * list should scroll (horizontally) within the viewport
2050 public boolean getScrollableTracksViewportWidth()
2052 Component parent = getParent();
2053 boolean retVal = false;
2054 if (parent instanceof JViewport)
2056 JViewport viewport = (JViewport) parent;
2057 Dimension pref = getPreferredSize();
2058 if (viewport.getSize().width > pref.width)
2059 retVal = true;
2060 if ((getLayoutOrientation() == HORIZONTAL_WRAP)
2061 && (getVisibleRowCount() <= 0))
2062 retVal = true;
2064 return retVal;
2068 * Gets the value of the </code>scrollableTracksViewportWidth</code> property.
2070 * @return <code>true</code> if the viewport is larger (vertically)
2071 * than the list and the list should be expanded to fit the viewport;
2072 * <code>false</code> if the viewport is smaller than the list and the
2073 * list should scroll (vertically) within the viewport
2075 public boolean getScrollableTracksViewportHeight()
2077 Component parent = getParent();
2078 boolean retVal = false;
2079 if (parent instanceof JViewport)
2081 JViewport viewport = (JViewport) parent;
2082 Dimension pref = getPreferredSize();
2083 if (viewport.getSize().height > pref.height)
2084 retVal = true;
2085 if ((getLayoutOrientation() == VERTICAL_WRAP)
2086 && (getVisibleRowCount() <= 0))
2087 retVal = true;
2089 return retVal;
2093 * Returns the index of the anchor item in the current selection, or
2094 * <code>-1</code> if there is no anchor item.
2096 * @return The item index.
2098 public int getAnchorSelectionIndex()
2100 return selectionModel.getAnchorSelectionIndex();
2104 * Returns the index of the lead item in the current selection, or
2105 * <code>-1</code> if there is no lead item.
2107 * @return The item index.
2109 public int getLeadSelectionIndex()
2111 return selectionModel.getLeadSelectionIndex();
2115 * Returns the lowest item index in the current selection, or <code>-1</code>
2116 * if there is no selection.
2118 * @return The index.
2120 * @see #getMaxSelectionIndex()
2122 public int getMinSelectionIndex()
2124 return selectionModel.getMinSelectionIndex();
2128 * Returns the highest item index in the current selection, or
2129 * <code>-1</code> if there is no selection.
2131 * @return The index.
2133 * @see #getMinSelectionIndex()
2135 public int getMaxSelectionIndex()
2137 return selectionModel.getMaxSelectionIndex();
2141 * Clears the current selection.
2143 public void clearSelection()
2145 selectionModel.clearSelection();
2149 * Sets the current selection to the items in the specified range (inclusive).
2150 * Note that <code>anchor</code> can be less than, equal to, or greater than
2151 * <code>lead</code>.
2153 * @param anchor the index of the anchor item.
2154 * @param lead the index of the anchor item.
2156 public void setSelectionInterval(int anchor, int lead)
2158 selectionModel.setSelectionInterval(anchor, lead);
2162 * Adds the specified interval to the current selection. Note that
2163 * <code>anchor</code> can be less than, equal to, or greater than
2164 * <code>lead</code>.
2166 * @param anchor the index of the anchor item.
2167 * @param lead the index of the lead item.
2169 public void addSelectionInterval(int anchor, int lead)
2171 selectionModel.addSelectionInterval(anchor, lead);
2175 * Removes the specified interval from the current selection. Note that
2176 * <code>index0</code> can be less than, equal to, or greater than
2177 * <code>index1</code>.
2179 * @param index0 an index for one end of the range.
2180 * @param index1 an index for the other end of the range.
2182 public void removeSelectionInterval(int index0, int index1)
2184 selectionModel.removeSelectionInterval(index0, index1);
2188 * Returns the value of the <code>valueIsAdjusting</code> property.
2190 * @return the value
2192 public boolean getValueIsAdjusting()
2194 return valueIsAdjusting;
2198 * Sets the <code>valueIsAdjusting</code> property.
2200 * @param isAdjusting the new value
2202 public void setValueIsAdjusting(boolean isAdjusting)
2204 valueIsAdjusting = isAdjusting;
2208 * Return the value of the <code>dragEnabled</code> property.
2210 * @return the value
2212 * @since 1.4
2214 public boolean getDragEnabled()
2216 return dragEnabled;
2220 * Set the <code>dragEnabled</code> property.
2222 * @param enabled new value
2224 * @since 1.4
2226 public void setDragEnabled(boolean enabled)
2228 dragEnabled = enabled;
2232 * Returns the layout orientation.
2234 * @return the orientation, one of <code>JList.VERTICAL</code>,
2235 * <code>JList.VERTICAL_WRAP</code> and <code>JList.HORIZONTAL_WRAP</code>
2237 * @since 1.4
2239 public int getLayoutOrientation()
2241 return layoutOrientation;
2245 * Sets the layout orientation.
2247 * @param orientation the orientation to set, one of <code>JList.VERTICAL</code>,
2248 * <code>JList.VERTICAL_WRAP</code> and <code>JList.HORIZONTAL_WRAP</code>
2250 * @since 1.4
2252 public void setLayoutOrientation(int orientation)
2254 if (layoutOrientation == orientation)
2255 return;
2257 int old = layoutOrientation;
2258 layoutOrientation = orientation;
2259 firePropertyChange("layoutOrientation", old, orientation);
2263 * Returns the bounds of the rectangle that encloses both list cells
2264 * with index0 and index1.
2266 * @param index0 the index of the first cell
2267 * @param index1 the index of the second cell
2269 * @return the bounds of the rectangle that encloses both list cells
2270 * with index0 and index1, <code>null</code> if one of the indices is
2271 * not valid
2273 public Rectangle getCellBounds(int index0, int index1)
2275 ListUI ui = getUI();
2276 Rectangle bounds = null;
2277 if (ui != null)
2279 bounds = ui.getCellBounds(this, index0, index1);
2281 // When the UI is null, this method also returns null in the RI.
2282 return bounds;
2286 * Returns the next list element (beginning from <code>startIndex</code>
2287 * that starts with <code>prefix</code>. Searching is done in the direction
2288 * specified by <code>bias</code>.
2290 * @param prefix the prefix to search for in the cell values
2291 * @param startIndex the index where to start searching from
2292 * @param bias the search direction, either {@link Position.Bias#Forward}
2293 * or {@link Position.Bias#Backward}
2295 * @return the index of the found element or -1 if no such element has
2296 * been found
2298 * @throws IllegalArgumentException if prefix is <code>null</code> or
2299 * startIndex is not valid
2301 * @since 1.4
2303 public int getNextMatch(String prefix, int startIndex, Position.Bias bias)
2305 if (prefix == null)
2306 throw new IllegalArgumentException("The argument 'prefix' must not be"
2307 + " null.");
2308 if (startIndex < 0)
2309 throw new IllegalArgumentException("The argument 'startIndex' must not"
2310 + " be less than zero.");
2312 int size = model.getSize();
2313 if (startIndex > model.getSize())
2314 throw new IllegalArgumentException("The argument 'startIndex' must not"
2315 + " be greater than the number of"
2316 + " elements in the ListModel.");
2318 int index = -1;
2319 if (bias == Position.Bias.Forward)
2321 for (int i = startIndex; i < size; i++)
2323 String item = model.getElementAt(i).toString();
2324 if (item.startsWith(prefix))
2326 index = i;
2327 break;
2331 else
2333 for (int i = startIndex; i >= 0; i--)
2335 String item = model.getElementAt(i).toString();
2336 if (item.startsWith(prefix))
2338 index = i;
2339 break;
2343 return index;
2347 * Returns a string describing the attributes for the <code>JList</code>
2348 * component, for use in debugging. The return value is guaranteed to be
2349 * non-<code>null</code>, but the format of the string may vary between
2350 * implementations.
2352 * @return A string describing the attributes of the <code>JList</code>.
2354 protected String paramString()
2356 StringBuffer sb = new StringBuffer(super.paramString());
2357 sb.append(",fixedCellHeight=").append(getFixedCellHeight());
2358 sb.append(",fixedCellWidth=").append(getFixedCellWidth());
2359 sb.append(",selectionBackground=");
2360 if (getSelectionBackground() != null)
2361 sb.append(getSelectionBackground());
2362 sb.append(",selectionForeground=");
2363 if (getSelectionForeground() != null)
2364 sb.append(getSelectionForeground());
2365 sb.append(",visibleRowCount=").append(getVisibleRowCount());
2366 sb.append(",layoutOrientation=").append(getLayoutOrientation());
2367 return sb.toString();