85 * for(int i = 0; i < model.getSize(); i++) {
86 * System.out.println(model.getElementAt(i));
87 * }
88 * }
89 * </pre>
90 * <p>
91 * A {@code ListModel} can be supplied directly to a {@code JList} by way of a
92 * constructor or the {@code setModel} method. The contents need not be static -
93 * the number of items, and the values of items can change over time. A correct
94 * {@code ListModel} implementation notifies the set of
95 * {@code javax.swing.event.ListDataListener}s that have been added to it, each
96 * time a change occurs. These changes are characterized by a
97 * {@code javax.swing.event.ListDataEvent}, which identifies the range of list
98 * indices that have been modified, added, or removed. {@code JList}'s
99 * {@code ListUI} is responsible for keeping the visual representation up to
100 * date with changes, by listening to the model.
101 * <p>
102 * Simple, dynamic-content, {@code JList} applications can use the
103 * {@code DefaultListModel} class to maintain list elements. This class
104 * implements the {@code ListModel} interface and also provides a
105 * <code>java.util.Vector</code>-like API. Applications that need a more
106 * custom <code>ListModel</code> implementation may instead wish to subclass
107 * {@code AbstractListModel}, which provides basic support for managing and
108 * notifying listeners. For example, a read-only implementation of
109 * {@code AbstractListModel}:
110 * <pre>
111 * {@code
112 * // This list model has about 2^16 elements. Enjoy scrolling.
113 *
114 * ListModel<String> bigData = new AbstractListModel<String>() {
115 * public int getSize() { return Short.MAX_VALUE; }
116 * public String getElementAt(int index) { return "Index " + index; }
117 * };
118 * }
119 * </pre>
120 * <p>
121 * The selection state of a {@code JList} is managed by another separate
122 * model, an instance of {@code ListSelectionModel}. {@code JList} is
123 * initialized with a selection model on construction, and also contains
124 * methods to query or set this selection model. Additionally, {@code JList}
125 * provides convenient methods for easily managing the selection. These methods,
126 * such as {@code setSelectedIndex} and {@code getSelectedValue}, are cover
237 * if (e.getClickCount() == 2) {
238 * int index = list.locationToIndex(e.getPoint());
239 * System.out.println("Double clicked on Item " + index);
240 * }
241 * }
242 * };
243 * list.addMouseListener(mouseListener);
244 * </pre>
245 * <p>
246 * <strong>Warning:</strong> Swing is not thread safe. For more
247 * information see <a
248 * href="package-summary.html#threading">Swing's Threading
249 * Policy</a>.
250 * <p>
251 * <strong>Warning:</strong>
252 * Serialized objects of this class will not be compatible with
253 * future Swing releases. The current serialization support is
254 * appropriate for short term storage or RMI between applications running
255 * the same version of Swing. As of 1.4, support for long term storage
256 * of all JavaBeans™
257 * has been added to the <code>java.beans</code> package.
258 * Please see {@link java.beans.XMLEncoder}.
259 * <p>
260 * See <a href="http://docs.oracle.com/javase/tutorial/uiswing/components/list.html">How to Use Lists</a>
261 * in <a href="http://docs.oracle.com/javase/tutorial/"><em>The Java Tutorial</em></a>
262 * for further documentation.
263 *
264 * @see ListModel
265 * @see AbstractListModel
266 * @see DefaultListModel
267 * @see ListSelectionModel
268 * @see DefaultListSelectionModel
269 * @see ListCellRenderer
270 * @see DefaultListCellRenderer
271 *
272 * @param <E> the type of the elements of this list
273 *
274 * @beaninfo
275 * attribute: isContainer false
276 * description: A component which allows for the selection of one or more objects from a list.
277 *
309 * @see #setLayoutOrientation
310 * @since 1.4
311 */
312 public static final int HORIZONTAL_WRAP = 2;
313
314 private int fixedCellWidth = -1;
315 private int fixedCellHeight = -1;
316 private int horizontalScrollIncrement = -1;
317 private E prototypeCellValue;
318 private int visibleRowCount = 8;
319 private Color selectionForeground;
320 private Color selectionBackground;
321 private boolean dragEnabled;
322
323 private ListSelectionModel selectionModel;
324 private ListModel<E> dataModel;
325 private ListCellRenderer<? super E> cellRenderer;
326 private ListSelectionListener selectionListener;
327
328 /**
329 * How to lay out the cells; defaults to <code>VERTICAL</code>.
330 */
331 private int layoutOrientation;
332
333 /**
334 * The drop mode for this component.
335 */
336 private DropMode dropMode = DropMode.USE_SELECTION;
337
338 /**
339 * The drop location.
340 */
341 private transient DropLocation dropLocation;
342
343 /**
344 * A subclass of <code>TransferHandler.DropLocation</code> representing
345 * a drop location for a <code>JList</code>.
346 *
347 * @see #getDropLocation
348 * @since 1.6
349 */
350 public static final class DropLocation extends TransferHandler.DropLocation {
351 private final int index;
352 private final boolean isInsert;
353
354 private DropLocation(Point p, int index, boolean isInsert) {
355 super(p);
356 this.index = index;
357 this.isInsert = isInsert;
358 }
359
360 /**
361 * Returns the index where dropped data should be placed in the
362 * list. Interpretation of the value depends on the drop mode set on
363 * the associated component. If the drop mode is either
364 * <code>DropMode.USE_SELECTION</code> or <code>DropMode.ON</code>,
365 * the return value is an index of a row in the list. If the drop mode is
366 * <code>DropMode.INSERT</code>, the return value refers to the index
367 * where the data should be inserted. If the drop mode is
368 * <code>DropMode.ON_OR_INSERT</code>, the value of
369 * <code>isInsert()</code> indicates whether the index is an index
370 * of a row, or an insert index.
371 * <p>
372 * <code>-1</code> indicates that the drop occurred over empty space,
373 * and no index could be calculated.
374 *
375 * @return the drop index
376 */
377 public int getIndex() {
378 return index;
379 }
380
381 /**
382 * Returns whether or not this location represents an insert
383 * location.
384 *
385 * @return whether or not this is an insert location
386 */
387 public boolean isInsert() {
388 return isInsert;
389 }
390
391 /**
392 * Returns a string representation of this drop location.
420 if (dataModel == null) {
421 throw new IllegalArgumentException("dataModel must be non null");
422 }
423
424 // Register with the ToolTipManager so that tooltips from the
425 // renderer show through.
426 ToolTipManager toolTipManager = ToolTipManager.sharedInstance();
427 toolTipManager.registerComponent(this);
428
429 layoutOrientation = VERTICAL;
430
431 this.dataModel = dataModel;
432 selectionModel = createSelectionModel();
433 setAutoscrolls(true);
434 setOpaque(true);
435 updateUI();
436 }
437
438
439 /**
440 * Constructs a <code>JList</code> that displays the elements in
441 * the specified array. This constructor creates a read-only model
442 * for the given array, and then delegates to the constructor that
443 * takes a {@code ListModel}.
444 * <p>
445 * Attempts to pass a {@code null} value to this method results in
446 * undefined behavior and, most likely, exceptions. The created model
447 * references the given array directly. Attempts to modify the array
448 * after constructing the list results in undefined behavior.
449 *
450 * @param listData the array of Objects to be loaded into the data model,
451 * {@code non-null}
452 */
453 public JList(final E[] listData)
454 {
455 this (
456 new AbstractListModel<E>() {
457 public int getSize() { return listData.length; }
458 public E getElementAt(int i) { return listData[i]; }
459 }
460 );
461 }
462
463
464 /**
465 * Constructs a <code>JList</code> that displays the elements in
466 * the specified <code>Vector</code>. This constructor creates a read-only
467 * model for the given {@code Vector}, and then delegates to the constructor
468 * that takes a {@code ListModel}.
469 * <p>
470 * Attempts to pass a {@code null} value to this method results in
471 * undefined behavior and, most likely, exceptions. The created model
472 * references the given {@code Vector} directly. Attempts to modify the
473 * {@code Vector} after constructing the list results in undefined behavior.
474 *
475 * @param listData the <code>Vector</code> to be loaded into the
476 * data model, {@code non-null}
477 */
478 public JList(final Vector<? extends E> listData) {
479 this (
480 new AbstractListModel<E>() {
481 public int getSize() { return listData.size(); }
482 public E getElementAt(int i) { return listData.elementAt(i); }
483 }
484 );
485 }
486
487
488 /**
489 * Constructs a <code>JList</code> with an empty, read-only, model.
490 */
491 public JList() {
492 this (
493 new AbstractListModel<E>() {
494 public int getSize() { return 0; }
495 public E getElementAt(int i) { throw new IndexOutOfBoundsException("No Data Model"); }
496 }
497 );
498 }
499
500
501 /**
502 * Returns the {@code ListUI}, the look and feel object that
503 * renders this component.
504 *
505 * @return the <code>ListUI</code> object that renders this component
506 */
507 public ListUI getUI() {
508 return (ListUI)ui;
509 }
510
511
512 /**
513 * Sets the {@code ListUI}, the look and feel object that
514 * renders this component.
515 *
516 * @param ui the <code>ListUI</code> object
517 * @see UIDefaults#getUI
518 * @beaninfo
519 * bound: true
520 * hidden: true
521 * attribute: visualUpdate true
522 * description: The UI object that implements the Component's LookAndFeel.
523 */
524 public void setUI(ListUI ui) {
525 super.setUI(ui);
526 }
527
528
529 /**
530 * Resets the {@code ListUI} property by setting it to the value provided
531 * by the current look and feel. If the current cell renderer was installed
532 * by the developer (rather than the look and feel itself), this also causes
533 * the cell renderer and its children to be updated, by calling
534 * {@code SwingUtilities.updateComponentTreeUI} on it.
535 *
536 * @see UIManager#getUI
537 * @see SwingUtilities#updateComponentTreeUI
538 */
539 public void updateUI() {
540 setUI((ListUI)UIManager.getUI(this));
541
542 ListCellRenderer<? super E> renderer = getCellRenderer();
543 if (renderer instanceof Component) {
544 SwingUtilities.updateComponentTreeUI((Component)renderer);
545 }
546 }
547
548
549 /**
550 * Returns {@code "ListUI"}, the <code>UIDefaults</code> key used to look
551 * up the name of the {@code javax.swing.plaf.ListUI} class that defines
552 * the look and feel for this component.
553 *
554 * @return the string "ListUI"
555 * @see JComponent#getUIClassID
556 * @see UIDefaults#getUI
557 */
558 public String getUIClassID() {
559 return uiClassID;
560 }
561
562
563 /* -----private-----
564 * This method is called by setPrototypeCellValue and setCellRenderer
565 * to update the fixedCellWidth and fixedCellHeight properties from the
566 * current value of prototypeCellValue (if it's non null).
567 * <p>
568 * This method sets fixedCellWidth and fixedCellHeight but does <b>not</b>
569 * generate PropertyChangeEvents for them.
570 *
612 /**
613 * Sets the {@code prototypeCellValue} property, and then (if the new value
614 * is {@code non-null}), computes the {@code fixedCellWidth} and
615 * {@code fixedCellHeight} properties by requesting the cell renderer
616 * component for the given value (and index 0) from the cell renderer, and
617 * using that component's preferred size.
618 * <p>
619 * This method is useful when the list is too long to allow the
620 * {@code ListUI} to compute the width/height of each cell, and there is a
621 * single cell value that is known to occupy as much space as any of the
622 * others, a so-called prototype.
623 * <p>
624 * While all three of the {@code prototypeCellValue},
625 * {@code fixedCellHeight}, and {@code fixedCellWidth} properties may be
626 * modified by this method, {@code PropertyChangeEvent} notifications are
627 * only sent when the {@code prototypeCellValue} property changes.
628 * <p>
629 * To see an example which sets this property, see the
630 * <a href="#prototype_example">class description</a> above.
631 * <p>
632 * The default value of this property is <code>null</code>.
633 * <p>
634 * This is a JavaBeans bound property.
635 *
636 * @param prototypeCellValue the value on which to base
637 * <code>fixedCellWidth</code> and
638 * <code>fixedCellHeight</code>
639 * @see #getPrototypeCellValue
640 * @see #setFixedCellWidth
641 * @see #setFixedCellHeight
642 * @see JComponent#addPropertyChangeListener
643 * @beaninfo
644 * bound: true
645 * attribute: visualUpdate true
646 * description: The cell prototype value, used to compute cell width and height.
647 */
648 public void setPrototypeCellValue(E prototypeCellValue) {
649 E oldValue = this.prototypeCellValue;
650 this.prototypeCellValue = prototypeCellValue;
651
652 /* If the prototypeCellValue has changed and is non-null,
653 * then recompute fixedCellWidth and fixedCellHeight.
654 */
655
656 if ((prototypeCellValue != null) && !prototypeCellValue.equals(oldValue)) {
657 updateFixedCellSize();
658 }
659
660 firePropertyChange("prototypeCellValue", oldValue, prototypeCellValue);
661 }
662
663
664 /**
665 * Returns the value of the {@code fixedCellWidth} property.
666 *
667 * @return the fixed cell width
668 * @see #setFixedCellWidth
669 */
670 public int getFixedCellWidth() {
671 return fixedCellWidth;
672 }
673
674 /**
675 * Sets a fixed value to be used for the width of every cell in the list.
676 * If {@code width} is -1, cell widths are computed in the {@code ListUI}
677 * by applying <code>getPreferredSize</code> to the cell renderer component
678 * for each list element.
679 * <p>
680 * The default value of this property is {@code -1}.
681 * <p>
682 * This is a JavaBeans bound property.
683 *
684 * @param width the width to be used for all cells in the list
685 * @see #setPrototypeCellValue
686 * @see #setFixedCellWidth
687 * @see JComponent#addPropertyChangeListener
688 * @beaninfo
689 * bound: true
690 * attribute: visualUpdate true
691 * description: Defines a fixed cell width when greater than zero.
692 */
693 public void setFixedCellWidth(int width) {
694 int oldValue = fixedCellWidth;
695 fixedCellWidth = width;
696 firePropertyChange("fixedCellWidth", oldValue, fixedCellWidth);
697 }
698
699
700 /**
701 * Returns the value of the {@code fixedCellHeight} property.
702 *
703 * @return the fixed cell height
704 * @see #setFixedCellHeight
705 */
706 public int getFixedCellHeight() {
707 return fixedCellHeight;
708 }
709
710 /**
711 * Sets a fixed value to be used for the height of every cell in the list.
712 * If {@code height} is -1, cell heights are computed in the {@code ListUI}
713 * by applying <code>getPreferredSize</code> to the cell renderer component
714 * for each list element.
715 * <p>
716 * The default value of this property is {@code -1}.
717 * <p>
718 * This is a JavaBeans bound property.
719 *
720 * @param height the height to be used for all cells in the list
721 * @see #setPrototypeCellValue
722 * @see #setFixedCellWidth
723 * @see JComponent#addPropertyChangeListener
724 * @beaninfo
725 * bound: true
726 * attribute: visualUpdate true
727 * description: Defines a fixed cell height when greater than zero.
728 */
729 public void setFixedCellHeight(int height) {
730 int oldValue = fixedCellHeight;
731 fixedCellHeight = height;
732 firePropertyChange("fixedCellHeight", oldValue, fixedCellHeight);
733 }
735
736 /**
737 * Returns the object responsible for painting list items.
738 *
739 * @return the value of the {@code cellRenderer} property
740 * @see #setCellRenderer
741 */
742 @Transient
743 public ListCellRenderer<? super E> getCellRenderer() {
744 return cellRenderer;
745 }
746
747 /**
748 * Sets the delegate that is used to paint each cell in the list.
749 * The job of a cell renderer is discussed in detail in the
750 * <a href="#renderer">class level documentation</a>.
751 * <p>
752 * If the {@code prototypeCellValue} property is {@code non-null},
753 * setting the cell renderer also causes the {@code fixedCellWidth} and
754 * {@code fixedCellHeight} properties to be re-calculated. Only one
755 * <code>PropertyChangeEvent</code> is generated however -
756 * for the <code>cellRenderer</code> property.
757 * <p>
758 * The default value of this property is provided by the {@code ListUI}
759 * delegate, i.e. by the look and feel implementation.
760 * <p>
761 * This is a JavaBeans bound property.
762 *
763 * @param cellRenderer the <code>ListCellRenderer</code>
764 * that paints list cells
765 * @see #getCellRenderer
766 * @beaninfo
767 * bound: true
768 * attribute: visualUpdate true
769 * description: The component used to draw the cells.
770 */
771 public void setCellRenderer(ListCellRenderer<? super E> cellRenderer) {
772 ListCellRenderer<? super E> oldValue = this.cellRenderer;
773 this.cellRenderer = cellRenderer;
774
775 /* If the cellRenderer has changed and prototypeCellValue
776 * was set, then recompute fixedCellWidth and fixedCellHeight.
777 */
778 if ((cellRenderer != null) && !cellRenderer.equals(oldValue)) {
779 updateFixedCellSize();
780 }
781
782 firePropertyChange("cellRenderer", oldValue, cellRenderer);
783 }
956 * <pre>
957 * VERTICAL: 0
958 * 1
959 * 2
960 * 3
961 * 4
962 *
963 * HORIZONTAL_WRAP: 0 1 2
964 * 3 4
965 *
966 * VERTICAL_WRAP: 0 3
967 * 1 4
968 * 2
969 * </pre>
970 * <p>
971 * A description of these layouts follows:
972 *
973 * <table border="1"
974 * summary="Describes layouts VERTICAL, HORIZONTAL_WRAP, and VERTICAL_WRAP">
975 * <tr><th><p style="text-align:left">Value</p></th><th><p style="text-align:left">Description</p></th></tr>
976 * <tr><td><code>VERTICAL</code>
977 * <td>Cells are layed out vertically in a single column.
978 * <tr><td><code>HORIZONTAL_WRAP</code>
979 * <td>Cells are layed out horizontally, wrapping to a new row as
980 * necessary. If the {@code visibleRowCount} property is less than
981 * or equal to zero, wrapping is determined by the width of the
982 * list; otherwise wrapping is done in such a way as to ensure
983 * {@code visibleRowCount} rows in the list.
984 * <tr><td><code>VERTICAL_WRAP</code>
985 * <td>Cells are layed out vertically, wrapping to a new column as
986 * necessary. If the {@code visibleRowCount} property is less than
987 * or equal to zero, wrapping is determined by the height of the
988 * list; otherwise wrapping is done at {@code visibleRowCount} rows.
989 * </table>
990 * <p>
991 * The default value of this property is <code>VERTICAL</code>.
992 *
993 * @param layoutOrientation the new layout orientation, one of:
994 * {@code VERTICAL}, {@code HORIZONTAL_WRAP} or {@code VERTICAL_WRAP}
995 * @see #getLayoutOrientation
996 * @see #setVisibleRowCount
997 * @see #getScrollableTracksViewportHeight
998 * @see #getScrollableTracksViewportWidth
999 * @throws IllegalArgumentException if {@code layoutOrientation} isn't one of the
1000 * allowable values
1001 * @since 1.4
1002 * @beaninfo
1003 * bound: true
1004 * attribute: visualUpdate true
1005 * description: Defines the way list cells are layed out.
1006 * enum: VERTICAL JList.VERTICAL
1007 * HORIZONTAL_WRAP JList.HORIZONTAL_WRAP
1008 * VERTICAL_WRAP JList.VERTICAL_WRAP
1009 */
1010 public void setLayoutOrientation(int layoutOrientation) {
1011 int oldValue = this.layoutOrientation;
1119 }
1120 }
1121
1122 }
1123 else {
1124 last = visIndex;
1125 }
1126 }
1127 } while (visIndex != -1 && last != visIndex);
1128 }
1129 }
1130 }
1131 return location;
1132 }
1133
1134
1135 /**
1136 * Scrolls the list within an enclosing viewport to make the specified
1137 * cell completely visible. This calls {@code scrollRectToVisible} with
1138 * the bounds of the specified cell. For this method to work, the
1139 * {@code JList} must be within a <code>JViewport</code>.
1140 * <p>
1141 * If the given index is outside the list's range of cells, this method
1142 * results in nothing.
1143 *
1144 * @param index the index of the cell to make visible
1145 * @see JComponent#scrollRectToVisible
1146 * @see #getVisibleRect
1147 */
1148 public void ensureIndexIsVisible(int index) {
1149 Rectangle cellBounds = getCellBounds(index, index);
1150 if (cellBounds != null) {
1151 scrollRectToVisible(cellBounds);
1152 }
1153 }
1154
1155 /**
1156 * Turns on or off automatic drag handling. In order to enable automatic
1157 * drag handling, this property should be set to {@code true}, and the
1158 * list's {@code TransferHandler} needs to be {@code non-null}.
1159 * The default value of the {@code dragEnabled} property is {@code false}.
1160 * <p>
1161 * The job of honoring this property, and recognizing a user drag gesture,
1162 * lies with the look and feel implementation, and in particular, the list's
1163 * {@code ListUI}. When automatic drag handling is enabled, most look and
1164 * feels (including those that subclass {@code BasicLookAndFeel}) begin a
1165 * drag and drop operation whenever the user presses the mouse button over
1166 * an item and then moves the mouse a few pixels. Setting this property to
1167 * {@code true} can therefore have a subtle effect on how selections behave.
1168 * <p>
1169 * If a look and feel is used that ignores this property, you can still
1170 * begin a drag and drop operation by calling {@code exportAsDrag} on the
1171 * list's {@code TransferHandler}.
1172 *
1173 * @param b whether or not to enable automatic drag handling
1174 * @exception HeadlessException if
1175 * <code>b</code> is <code>true</code> and
1176 * <code>GraphicsEnvironment.isHeadless()</code>
1177 * returns <code>true</code>
1178 * @see java.awt.GraphicsEnvironment#isHeadless
1179 * @see #getDragEnabled
1180 * @see #setTransferHandler
1181 * @see TransferHandler
1182 * @since 1.4
1183 *
1184 * @beaninfo
1185 * description: determines whether automatic drag handling is enabled
1186 * bound: false
1187 */
1188 public void setDragEnabled(boolean b) {
1189 if (b && GraphicsEnvironment.isHeadless()) {
1190 throw new HeadlessException();
1191 }
1192 dragEnabled = b;
1193 }
1194
1195 /**
1196 * Returns whether or not automatic drag handling is enabled.
1197 *
1198 * @return the value of the {@code dragEnabled} property
1199 * @see #setDragEnabled
1200 * @since 1.4
1201 */
1202 public boolean getDragEnabled() {
1203 return dragEnabled;
1204 }
1205
1206 /**
1207 * Sets the drop mode for this component. For backward compatibility,
1208 * the default for this property is <code>DropMode.USE_SELECTION</code>.
1209 * Usage of one of the other modes is recommended, however, for an
1210 * improved user experience. <code>DropMode.ON</code>, for instance,
1211 * offers similar behavior of showing items as selected, but does so without
1212 * affecting the actual selection in the list.
1213 * <p>
1214 * <code>JList</code> supports the following drop modes:
1215 * <ul>
1216 * <li><code>DropMode.USE_SELECTION</code></li>
1217 * <li><code>DropMode.ON</code></li>
1218 * <li><code>DropMode.INSERT</code></li>
1219 * <li><code>DropMode.ON_OR_INSERT</code></li>
1220 * </ul>
1221 * The drop mode is only meaningful if this component has a
1222 * <code>TransferHandler</code> that accepts drops.
1223 *
1224 * @param dropMode the drop mode to use
1225 * @throws IllegalArgumentException if the drop mode is unsupported
1226 * or <code>null</code>
1227 * @see #getDropMode
1228 * @see #getDropLocation
1229 * @see #setTransferHandler
1230 * @see TransferHandler
1231 * @since 1.6
1232 */
1233 public final void setDropMode(DropMode dropMode) {
1234 if (dropMode != null) {
1235 switch (dropMode) {
1236 case USE_SELECTION:
1237 case ON:
1238 case INSERT:
1239 case ON_OR_INSERT:
1240 this.dropMode = dropMode;
1241 return;
1242 }
1243 }
1244
1245 throw new IllegalArgumentException(dropMode + ": Unsupported drop mode for list");
1246 }
1247
1248 /**
1249 * Returns the drop mode for this component.
1250 *
1251 * @return the drop mode for this component
1252 * @see #setDropMode
1253 * @since 1.6
1254 */
1255 public final DropMode getDropMode() {
1256 return dropMode;
1257 }
1258
1259 /**
1260 * Calculates a drop location in this component, representing where a
1261 * drop at the given point should insert data.
1262 *
1263 * @param p the point to calculate a drop location for
1264 * @return the drop location, or <code>null</code>
1265 */
1266 DropLocation dropLocationForPoint(Point p) {
1267 DropLocation location = null;
1268 Rectangle rect = null;
1269
1270 int index = locationToIndex(p);
1271 if (index != -1) {
1272 rect = getCellBounds(index, index);
1273 }
1274
1275 switch(dropMode) {
1276 case USE_SELECTION:
1277 case ON:
1278 location = new DropLocation(p,
1279 (rect != null && rect.contains(p)) ? index : -1,
1280 false);
1281
1282 break;
1283 case INSERT:
1284 if (index == -1) {
1347 }
1348
1349 /**
1350 * Called to set or clear the drop location during a DnD operation.
1351 * In some cases, the component may need to use it's internal selection
1352 * temporarily to indicate the drop location. To help facilitate this,
1353 * this method returns and accepts as a parameter a state object.
1354 * This state object can be used to store, and later restore, the selection
1355 * state. Whatever this method returns will be passed back to it in
1356 * future calls, as the state parameter. If it wants the DnD system to
1357 * continue storing the same state, it must pass it back every time.
1358 * Here's how this is used:
1359 * <p>
1360 * Let's say that on the first call to this method the component decides
1361 * to save some state (because it is about to use the selection to show
1362 * a drop index). It can return a state object to the caller encapsulating
1363 * any saved selection state. On a second call, let's say the drop location
1364 * is being changed to something else. The component doesn't need to
1365 * restore anything yet, so it simply passes back the same state object
1366 * to have the DnD system continue storing it. Finally, let's say this
1367 * method is messaged with <code>null</code>. This means DnD
1368 * is finished with this component for now, meaning it should restore
1369 * state. At this point, it can use the state parameter to restore
1370 * said state, and of course return <code>null</code> since there's
1371 * no longer anything to store.
1372 *
1373 * @param location the drop location (as calculated by
1374 * <code>dropLocationForPoint</code>) or <code>null</code>
1375 * if there's no longer a valid drop location
1376 * @param state the state object saved earlier for this component,
1377 * or <code>null</code>
1378 * @param forDrop whether or not the method is being called because an
1379 * actual drop occurred
1380 * @return any saved state for this component, or <code>null</code> if none
1381 */
1382 Object setDropLocation(TransferHandler.DropLocation location,
1383 Object state,
1384 boolean forDrop) {
1385
1386 Object retVal = null;
1387 DropLocation listLocation = (DropLocation)location;
1388
1389 if (dropMode == DropMode.USE_SELECTION) {
1390 if (listLocation == null) {
1391 if (!forDrop && state != null) {
1392 setSelectedIndices(((int[][])state)[0]);
1393
1394 int anchor = ((int[][])state)[1][0];
1395 int lead = ((int[][])state)[1][1];
1396
1397 SwingUtilities2.setLeadAnchorWithoutSelection(
1398 getSelectionModel(), lead, anchor);
1399 }
1400 } else {
1414 } else {
1415 setSelectionInterval(index, index);
1416 }
1417 }
1418 }
1419
1420 DropLocation old = dropLocation;
1421 dropLocation = listLocation;
1422 firePropertyChange("dropLocation", old, dropLocation);
1423
1424 return retVal;
1425 }
1426
1427 /**
1428 * Returns the location that this component should visually indicate
1429 * as the drop location during a DnD operation over the component,
1430 * or {@code null} if no location is to currently be shown.
1431 * <p>
1432 * This method is not meant for querying the drop location
1433 * from a {@code TransferHandler}, as the drop location is only
1434 * set after the {@code TransferHandler}'s <code>canImport</code>
1435 * has returned and has allowed for the location to be shown.
1436 * <p>
1437 * When this property changes, a property change event with
1438 * name "dropLocation" is fired by the component.
1439 * <p>
1440 * By default, responsibility for listening for changes to this property
1441 * and indicating the drop location visually lies with the list's
1442 * {@code ListUI}, which may paint it directly and/or install a cell
1443 * renderer to do so. Developers wishing to implement custom drop location
1444 * painting and/or replace the default cell renderer, may need to honor
1445 * this property.
1446 *
1447 * @return the drop location
1448 * @see #setDropMode
1449 * @see TransferHandler#canImport(TransferHandler.TransferSupport)
1450 * @since 1.6
1451 */
1452 public final DropLocation getDropLocation() {
1453 return dropLocation;
1454 }
1497 }
1498 }
1499
1500 if (string != null && string.startsWith(prefix)) {
1501 return index;
1502 }
1503 }
1504 index = (index + increment + max) % max;
1505 } while (index != startIndex);
1506 return -1;
1507 }
1508
1509 /**
1510 * Returns the tooltip text to be used for the given event. This overrides
1511 * {@code JComponent}'s {@code getToolTipText} to first check the cell
1512 * renderer component for the cell over which the event occurred, returning
1513 * its tooltip text, if any. This implementation allows you to specify
1514 * tooltip text on the cell level, by using {@code setToolTipText} on your
1515 * cell renderer component.
1516 * <p>
1517 * <strong>Note:</strong> For <code>JList</code> to properly display the
1518 * tooltips of its renderers in this manner, <code>JList</code> must be a
1519 * registered component with the <code>ToolTipManager</code>. This registration
1520 * is done automatically in the constructor. However, if at a later point
1521 * <code>JList</code> is unregistered, by way of a call to
1522 * {@code setToolTipText(null)}, tips from the renderers will no longer display.
1523 *
1524 * @param event the {@code MouseEvent} to fetch the tooltip text for
1525 * @see JComponent#setToolTipText
1526 * @see JComponent#getToolTipText
1527 */
1528 public String getToolTipText(MouseEvent event) {
1529 if(event != null) {
1530 Point p = event.getPoint();
1531 int index = locationToIndex(p);
1532 ListCellRenderer<? super E> r = getCellRenderer();
1533 Rectangle cellBounds;
1534
1535 if (index != -1 && r != null && (cellBounds =
1536 getCellBounds(index, index)) != null &&
1537 cellBounds.contains(p.x, p.y)) {
1538 ListSelectionModel lsm = getSelectionModel();
1539 Component rComponent = r.getListCellRendererComponent(
1540 this, getModel().getElementAt(index), index,
1541 lsm.isSelectedIndex(index),
1624 * in the list's {@code ListUI}. It returns {@code null} if the list has
1625 * no {@code ListUI}.
1626 *
1627 * @param index0 the first index in the range
1628 * @param index1 the second index in the range
1629 * @return the bounding rectangle for the range of cells, or {@code null}
1630 */
1631 public Rectangle getCellBounds(int index0, int index1) {
1632 ListUI ui = getUI();
1633 return (ui != null) ? ui.getCellBounds(this, index0, index1) : null;
1634 }
1635
1636
1637 /**
1638 * --- ListModel Support ---
1639 */
1640
1641
1642 /**
1643 * Returns the data model that holds the list of items displayed
1644 * by the <code>JList</code> component.
1645 *
1646 * @return the <code>ListModel</code> that provides the displayed
1647 * list of items
1648 * @see #setModel
1649 */
1650 public ListModel<E> getModel() {
1651 return dataModel;
1652 }
1653
1654 /**
1655 * Sets the model that represents the contents or "value" of the
1656 * list, notifies property change listeners, and then clears the
1657 * list's selection.
1658 * <p>
1659 * This is a JavaBeans bound property.
1660 *
1661 * @param model the <code>ListModel</code> that provides the
1662 * list of items for display
1663 * @exception IllegalArgumentException if <code>model</code> is
1664 * <code>null</code>
1665 * @see #getModel
1666 * @see #clearSelection
1667 * @beaninfo
1668 * bound: true
1669 * attribute: visualUpdate true
1670 * description: The object that contains the data to be drawn by this JList.
1671 */
1672 public void setModel(ListModel<E> model) {
1673 if (model == null) {
1674 throw new IllegalArgumentException("model must be non null");
1675 }
1676 ListModel<E> oldValue = dataModel;
1677 dataModel = model;
1678 firePropertyChange("model", oldValue, dataModel);
1679 clearSelection();
1680 }
1681
1682
1683 /**
1684 * Constructs a read-only <code>ListModel</code> from an array of items,
1685 * and calls {@code setModel} with this model.
1686 * <p>
1687 * Attempts to pass a {@code null} value to this method results in
1688 * undefined behavior and, most likely, exceptions. The created model
1689 * references the given array directly. Attempts to modify the array
1690 * after invoking this method results in undefined behavior.
1691 *
1692 * @param listData an array of {@code E} containing the items to
1693 * display in the list
1694 * @see #setModel
1695 */
1696 public void setListData(final E[] listData) {
1697 setModel (
1698 new AbstractListModel<E>() {
1699 public int getSize() { return listData.length; }
1700 public E getElementAt(int i) { return listData[i]; }
1701 }
1702 );
1703 }
1704
1705
1706 /**
1707 * Constructs a read-only <code>ListModel</code> from a <code>Vector</code>
1708 * and calls {@code setModel} with this model.
1709 * <p>
1710 * Attempts to pass a {@code null} value to this method results in
1711 * undefined behavior and, most likely, exceptions. The created model
1712 * references the given {@code Vector} directly. Attempts to modify the
1713 * {@code Vector} after invoking this method results in undefined behavior.
1714 *
1715 * @param listData a <code>Vector</code> containing the items to
1716 * display in the list
1717 * @see #setModel
1718 */
1719 public void setListData(final Vector<? extends E> listData) {
1720 setModel (
1721 new AbstractListModel<E>() {
1722 public int getSize() { return listData.size(); }
1723 public E getElementAt(int i) { return listData.elementAt(i); }
1724 }
1725 );
1726 }
1727
1728
1729 /**
1730 * --- ListSelectionModel delegations and extensions ---
1731 */
1732
1733
1734 /**
1735 * Returns an instance of {@code DefaultListSelectionModel}; called
1736 * during construction to initialize the list's selection model
1737 * property.
1738 *
1739 * @return a {@code DefaultListSelecitonModel}, used to initialize
1740 * the list's selection model property during construction
1741 * @see #setSelectionModel
1742 * @see DefaultListSelectionModel
1743 */
1744 protected ListSelectionModel createSelectionModel() {
1745 return new DefaultListSelectionModel();
1746 }
1747
1748
1749 /**
1750 * Returns the current selection model. The selection model maintains the
1751 * selection state of the list. See the class level documentation for more
1752 * details.
1753 *
1754 * @return the <code>ListSelectionModel</code> that maintains the
1755 * list's selections
1756 *
1757 * @see #setSelectionModel
1758 * @see ListSelectionModel
1759 */
1760 public ListSelectionModel getSelectionModel() {
1761 return selectionModel;
1762 }
1763
1764
1765 /**
1766 * Notifies {@code ListSelectionListener}s added directly to the list
1767 * of selection changes made to the selection model. {@code JList}
1768 * listens for changes made to the selection in the selection model,
1769 * and forwards notification to listeners added to the list directly,
1770 * by calling this method.
1771 * <p>
1772 * This method constructs a {@code ListSelectionEvent} with this list
1773 * as the source, and the specified arguments, and sends it to the
1774 * registered {@code ListSelectionListeners}.
1849 public void removeListSelectionListener(ListSelectionListener listener) {
1850 listenerList.remove(ListSelectionListener.class, listener);
1851 }
1852
1853
1854 /**
1855 * Returns an array of all the {@code ListSelectionListener}s added
1856 * to this {@code JList} by way of {@code addListSelectionListener}.
1857 *
1858 * @return all of the {@code ListSelectionListener}s on this list, or
1859 * an empty array if no listeners have been added
1860 * @see #addListSelectionListener
1861 * @since 1.4
1862 */
1863 public ListSelectionListener[] getListSelectionListeners() {
1864 return listenerList.getListeners(ListSelectionListener.class);
1865 }
1866
1867
1868 /**
1869 * Sets the <code>selectionModel</code> for the list to a
1870 * non-<code>null</code> <code>ListSelectionModel</code>
1871 * implementation. The selection model handles the task of making single
1872 * selections, selections of contiguous ranges, and non-contiguous
1873 * selections.
1874 * <p>
1875 * This is a JavaBeans bound property.
1876 *
1877 * @param selectionModel the <code>ListSelectionModel</code> that
1878 * implements the selections
1879 * @exception IllegalArgumentException if <code>selectionModel</code>
1880 * is <code>null</code>
1881 * @see #getSelectionModel
1882 * @beaninfo
1883 * bound: true
1884 * description: The selection model, recording which cells are selected.
1885 */
1886 public void setSelectionModel(ListSelectionModel selectionModel) {
1887 if (selectionModel == null) {
1888 throw new IllegalArgumentException("selectionModel must be non null");
1889 }
1890
1891 /* Remove the forwarding ListSelectionListener from the old
1892 * selectionModel, and add it to the new one, if necessary.
1893 */
1894 if (selectionListener != null) {
1895 this.selectionModel.removeListSelectionListener(selectionListener);
1896 selectionModel.addListSelectionListener(selectionListener);
1897 }
1898
1899 ListSelectionModel oldValue = this.selectionModel;
1900 this.selectionModel = selectionModel;
2863 */
2864 public AccessibleContext getAccessibleContext() {
2865 if (accessibleContext == null) {
2866 accessibleContext = new AccessibleJList();
2867 }
2868 return accessibleContext;
2869 }
2870
2871 /**
2872 * This class implements accessibility support for the
2873 * {@code JList} class. It provides an implementation of the
2874 * Java Accessibility API appropriate to list user-interface
2875 * elements.
2876 * <p>
2877 * <strong>Warning:</strong>
2878 * Serialized objects of this class will not be compatible with
2879 * future Swing releases. The current serialization support is
2880 * appropriate for short term storage or RMI between applications running
2881 * the same version of Swing. As of 1.4, support for long term storage
2882 * of all JavaBeans™
2883 * has been added to the <code>java.beans</code> package.
2884 * Please see {@link java.beans.XMLEncoder}.
2885 */
2886 @SuppressWarnings("serial") // Same-version serialization only
2887 protected class AccessibleJList extends AccessibleJComponent
2888 implements AccessibleSelection, PropertyChangeListener,
2889 ListSelectionListener, ListDataListener {
2890
2891 int leadSelectionIndex;
2892
2893 /**
2894 * Constructs an {@code AccessibleJList}.
2895 */
2896 public AccessibleJList() {
2897 super();
2898 JList.this.addPropertyChangeListener(this);
2899 JList.this.getSelectionModel().addListSelectionListener(this);
2900 JList.this.getModel().addListDataListener(this);
2901 leadSelectionIndex = JList.this.getLeadSelectionIndex();
2902 }
2903
3031 AccessibleStateSet states = super.getAccessibleStateSet();
3032 if (selectionModel.getSelectionMode() !=
3033 ListSelectionModel.SINGLE_SELECTION) {
3034 states.add(AccessibleState.MULTISELECTABLE);
3035 }
3036 return states;
3037 }
3038
3039 /**
3040 * Get the role of this object.
3041 *
3042 * @return an instance of AccessibleRole describing the role of the
3043 * object
3044 * @see AccessibleRole
3045 */
3046 public AccessibleRole getAccessibleRole() {
3047 return AccessibleRole.LIST;
3048 }
3049
3050 /**
3051 * Returns the <code>Accessible</code> child contained at
3052 * the local coordinate <code>Point</code>, if one exists.
3053 * Otherwise returns <code>null</code>.
3054 *
3055 * @return the <code>Accessible</code> at the specified
3056 * location, if it exists
3057 */
3058 public Accessible getAccessibleAt(Point p) {
3059 int i = locationToIndex(p);
3060 if (i >= 0) {
3061 return new AccessibleJListChild(JList.this, i);
3062 } else {
3063 return null;
3064 }
3065 }
3066
3067 /**
3068 * Returns the number of accessible children in the object. If all
3069 * of the children of this object implement Accessible, than this
3070 * method should return the number of children of this object.
3071 *
3072 * @return the number of accessible children in the object.
3073 */
3074 public int getAccessibleChildrenCount() {
3075 return getModel().getSize();
3101 return this;
3102 }
3103
3104
3105 // AccessibleSelection methods
3106
3107 /**
3108 * Returns the number of items currently selected.
3109 * If no items are selected, the return value will be 0.
3110 *
3111 * @return the number of items currently selected.
3112 */
3113 public int getAccessibleSelectionCount() {
3114 return JList.this.getSelectedIndices().length;
3115 }
3116
3117 /**
3118 * Returns an Accessible representing the specified selected item
3119 * in the object. If there isn't a selection, or there are
3120 * fewer items selected than the integer passed in, the return
3121 * value will be <code>null</code>.
3122 *
3123 * @param i the zero-based index of selected items
3124 * @return an Accessible containing the selected item
3125 */
3126 public Accessible getAccessibleSelection(int i) {
3127 int len = getAccessibleSelectionCount();
3128 if (i < 0 || i >= len) {
3129 return null;
3130 } else {
3131 return getAccessibleChild(JList.this.getSelectedIndices()[i]);
3132 }
3133 }
3134
3135 /**
3136 * Returns true if the current child of this object is selected.
3137 *
3138 * @param i the zero-based index of the child in this Accessible
3139 * object.
3140 * @see AccessibleContext#getAccessibleChild
3141 */
3708 c.addFocusListener(l);
3709 }
3710 }
3711 }
3712
3713 public void removeFocusListener(FocusListener l) {
3714 AccessibleContext ac = getCurrentAccessibleContext();
3715 if (ac instanceof AccessibleComponent) {
3716 ((AccessibleComponent) ac).removeFocusListener(l);
3717 } else {
3718 Component c = getCurrentComponent();
3719 if (c != null) {
3720 c.removeFocusListener(l);
3721 }
3722 }
3723 }
3724
3725 // TIGER - 4733624
3726 /**
3727 * Returns the icon for the element renderer, as the only item
3728 * of an array of <code>AccessibleIcon</code>s or a <code>null</code> array
3729 * if the renderer component contains no icons.
3730 *
3731 * @return an array containing the accessible icon
3732 * or a <code>null</code> array if none
3733 * @since 1.3
3734 */
3735 public AccessibleIcon [] getAccessibleIcon() {
3736 AccessibleContext ac = getCurrentAccessibleContext();
3737 if (ac != null) {
3738 return ac.getAccessibleIcon();
3739 } else {
3740 return null;
3741 }
3742 }
3743 } // inner class AccessibleJListChild
3744 } // inner class AccessibleJList
3745 }
|
85 * for(int i = 0; i < model.getSize(); i++) {
86 * System.out.println(model.getElementAt(i));
87 * }
88 * }
89 * </pre>
90 * <p>
91 * A {@code ListModel} can be supplied directly to a {@code JList} by way of a
92 * constructor or the {@code setModel} method. The contents need not be static -
93 * the number of items, and the values of items can change over time. A correct
94 * {@code ListModel} implementation notifies the set of
95 * {@code javax.swing.event.ListDataListener}s that have been added to it, each
96 * time a change occurs. These changes are characterized by a
97 * {@code javax.swing.event.ListDataEvent}, which identifies the range of list
98 * indices that have been modified, added, or removed. {@code JList}'s
99 * {@code ListUI} is responsible for keeping the visual representation up to
100 * date with changes, by listening to the model.
101 * <p>
102 * Simple, dynamic-content, {@code JList} applications can use the
103 * {@code DefaultListModel} class to maintain list elements. This class
104 * implements the {@code ListModel} interface and also provides a
105 * {@code java.util.Vector}-like API. Applications that need a more
106 * custom {@code ListModel} implementation may instead wish to subclass
107 * {@code AbstractListModel}, which provides basic support for managing and
108 * notifying listeners. For example, a read-only implementation of
109 * {@code AbstractListModel}:
110 * <pre>
111 * {@code
112 * // This list model has about 2^16 elements. Enjoy scrolling.
113 *
114 * ListModel<String> bigData = new AbstractListModel<String>() {
115 * public int getSize() { return Short.MAX_VALUE; }
116 * public String getElementAt(int index) { return "Index " + index; }
117 * };
118 * }
119 * </pre>
120 * <p>
121 * The selection state of a {@code JList} is managed by another separate
122 * model, an instance of {@code ListSelectionModel}. {@code JList} is
123 * initialized with a selection model on construction, and also contains
124 * methods to query or set this selection model. Additionally, {@code JList}
125 * provides convenient methods for easily managing the selection. These methods,
126 * such as {@code setSelectedIndex} and {@code getSelectedValue}, are cover
237 * if (e.getClickCount() == 2) {
238 * int index = list.locationToIndex(e.getPoint());
239 * System.out.println("Double clicked on Item " + index);
240 * }
241 * }
242 * };
243 * list.addMouseListener(mouseListener);
244 * </pre>
245 * <p>
246 * <strong>Warning:</strong> Swing is not thread safe. For more
247 * information see <a
248 * href="package-summary.html#threading">Swing's Threading
249 * Policy</a>.
250 * <p>
251 * <strong>Warning:</strong>
252 * Serialized objects of this class will not be compatible with
253 * future Swing releases. The current serialization support is
254 * appropriate for short term storage or RMI between applications running
255 * the same version of Swing. As of 1.4, support for long term storage
256 * of all JavaBeans™
257 * has been added to the {@code java.beans} package.
258 * Please see {@link java.beans.XMLEncoder}.
259 * <p>
260 * See <a href="http://docs.oracle.com/javase/tutorial/uiswing/components/list.html">How to Use Lists</a>
261 * in <a href="http://docs.oracle.com/javase/tutorial/"><em>The Java Tutorial</em></a>
262 * for further documentation.
263 *
264 * @see ListModel
265 * @see AbstractListModel
266 * @see DefaultListModel
267 * @see ListSelectionModel
268 * @see DefaultListSelectionModel
269 * @see ListCellRenderer
270 * @see DefaultListCellRenderer
271 *
272 * @param <E> the type of the elements of this list
273 *
274 * @beaninfo
275 * attribute: isContainer false
276 * description: A component which allows for the selection of one or more objects from a list.
277 *
309 * @see #setLayoutOrientation
310 * @since 1.4
311 */
312 public static final int HORIZONTAL_WRAP = 2;
313
314 private int fixedCellWidth = -1;
315 private int fixedCellHeight = -1;
316 private int horizontalScrollIncrement = -1;
317 private E prototypeCellValue;
318 private int visibleRowCount = 8;
319 private Color selectionForeground;
320 private Color selectionBackground;
321 private boolean dragEnabled;
322
323 private ListSelectionModel selectionModel;
324 private ListModel<E> dataModel;
325 private ListCellRenderer<? super E> cellRenderer;
326 private ListSelectionListener selectionListener;
327
328 /**
329 * How to lay out the cells; defaults to {@code VERTICAL}.
330 */
331 private int layoutOrientation;
332
333 /**
334 * The drop mode for this component.
335 */
336 private DropMode dropMode = DropMode.USE_SELECTION;
337
338 /**
339 * The drop location.
340 */
341 private transient DropLocation dropLocation;
342
343 /**
344 * A subclass of {@code TransferHandler.DropLocation} representing
345 * a drop location for a {@code JList}.
346 *
347 * @see #getDropLocation
348 * @since 1.6
349 */
350 public static final class DropLocation extends TransferHandler.DropLocation {
351 private final int index;
352 private final boolean isInsert;
353
354 private DropLocation(Point p, int index, boolean isInsert) {
355 super(p);
356 this.index = index;
357 this.isInsert = isInsert;
358 }
359
360 /**
361 * Returns the index where dropped data should be placed in the
362 * list. Interpretation of the value depends on the drop mode set on
363 * the associated component. If the drop mode is either
364 * {@code DropMode.USE_SELECTION} or {@code DropMode.ON},
365 * the return value is an index of a row in the list. If the drop mode is
366 * {@code DropMode.INSERT}, the return value refers to the index
367 * where the data should be inserted. If the drop mode is
368 * {@code DropMode.ON_OR_INSERT}, the value of
369 * {@code isInsert()} indicates whether the index is an index
370 * of a row, or an insert index.
371 * <p>
372 * {@code -1} indicates that the drop occurred over empty space,
373 * and no index could be calculated.
374 *
375 * @return the drop index
376 */
377 public int getIndex() {
378 return index;
379 }
380
381 /**
382 * Returns whether or not this location represents an insert
383 * location.
384 *
385 * @return whether or not this is an insert location
386 */
387 public boolean isInsert() {
388 return isInsert;
389 }
390
391 /**
392 * Returns a string representation of this drop location.
420 if (dataModel == null) {
421 throw new IllegalArgumentException("dataModel must be non null");
422 }
423
424 // Register with the ToolTipManager so that tooltips from the
425 // renderer show through.
426 ToolTipManager toolTipManager = ToolTipManager.sharedInstance();
427 toolTipManager.registerComponent(this);
428
429 layoutOrientation = VERTICAL;
430
431 this.dataModel = dataModel;
432 selectionModel = createSelectionModel();
433 setAutoscrolls(true);
434 setOpaque(true);
435 updateUI();
436 }
437
438
439 /**
440 * Constructs a {@code JList} that displays the elements in
441 * the specified array. This constructor creates a read-only model
442 * for the given array, and then delegates to the constructor that
443 * takes a {@code ListModel}.
444 * <p>
445 * Attempts to pass a {@code null} value to this method results in
446 * undefined behavior and, most likely, exceptions. The created model
447 * references the given array directly. Attempts to modify the array
448 * after constructing the list results in undefined behavior.
449 *
450 * @param listData the array of Objects to be loaded into the data model,
451 * {@code non-null}
452 */
453 public JList(final E[] listData)
454 {
455 this (
456 new AbstractListModel<E>() {
457 public int getSize() { return listData.length; }
458 public E getElementAt(int i) { return listData[i]; }
459 }
460 );
461 }
462
463
464 /**
465 * Constructs a {@code JList} that displays the elements in
466 * the specified {@code Vector}. This constructor creates a read-only
467 * model for the given {@code Vector}, and then delegates to the constructor
468 * that takes a {@code ListModel}.
469 * <p>
470 * Attempts to pass a {@code null} value to this method results in
471 * undefined behavior and, most likely, exceptions. The created model
472 * references the given {@code Vector} directly. Attempts to modify the
473 * {@code Vector} after constructing the list results in undefined behavior.
474 *
475 * @param listData the {@code Vector} to be loaded into the
476 * data model, {@code non-null}
477 */
478 public JList(final Vector<? extends E> listData) {
479 this (
480 new AbstractListModel<E>() {
481 public int getSize() { return listData.size(); }
482 public E getElementAt(int i) { return listData.elementAt(i); }
483 }
484 );
485 }
486
487
488 /**
489 * Constructs a {@code JList} with an empty, read-only, model.
490 */
491 public JList() {
492 this (
493 new AbstractListModel<E>() {
494 public int getSize() { return 0; }
495 public E getElementAt(int i) { throw new IndexOutOfBoundsException("No Data Model"); }
496 }
497 );
498 }
499
500
501 /**
502 * Returns the {@code ListUI}, the look and feel object that
503 * renders this component.
504 *
505 * @return the {@code ListUI} object that renders this component
506 */
507 public ListUI getUI() {
508 return (ListUI)ui;
509 }
510
511
512 /**
513 * Sets the {@code ListUI}, the look and feel object that
514 * renders this component.
515 *
516 * @param ui the {@code ListUI} object
517 * @see UIDefaults#getUI
518 * @beaninfo
519 * bound: true
520 * hidden: true
521 * attribute: visualUpdate true
522 * description: The UI object that implements the Component's LookAndFeel.
523 */
524 public void setUI(ListUI ui) {
525 super.setUI(ui);
526 }
527
528
529 /**
530 * Resets the {@code ListUI} property by setting it to the value provided
531 * by the current look and feel. If the current cell renderer was installed
532 * by the developer (rather than the look and feel itself), this also causes
533 * the cell renderer and its children to be updated, by calling
534 * {@code SwingUtilities.updateComponentTreeUI} on it.
535 *
536 * @see UIManager#getUI
537 * @see SwingUtilities#updateComponentTreeUI
538 */
539 public void updateUI() {
540 setUI((ListUI)UIManager.getUI(this));
541
542 ListCellRenderer<? super E> renderer = getCellRenderer();
543 if (renderer instanceof Component) {
544 SwingUtilities.updateComponentTreeUI((Component)renderer);
545 }
546 }
547
548
549 /**
550 * Returns {@code "ListUI"}, the {@code UIDefaults} key used to look
551 * up the name of the {@code javax.swing.plaf.ListUI} class that defines
552 * the look and feel for this component.
553 *
554 * @return the string "ListUI"
555 * @see JComponent#getUIClassID
556 * @see UIDefaults#getUI
557 */
558 public String getUIClassID() {
559 return uiClassID;
560 }
561
562
563 /* -----private-----
564 * This method is called by setPrototypeCellValue and setCellRenderer
565 * to update the fixedCellWidth and fixedCellHeight properties from the
566 * current value of prototypeCellValue (if it's non null).
567 * <p>
568 * This method sets fixedCellWidth and fixedCellHeight but does <b>not</b>
569 * generate PropertyChangeEvents for them.
570 *
612 /**
613 * Sets the {@code prototypeCellValue} property, and then (if the new value
614 * is {@code non-null}), computes the {@code fixedCellWidth} and
615 * {@code fixedCellHeight} properties by requesting the cell renderer
616 * component for the given value (and index 0) from the cell renderer, and
617 * using that component's preferred size.
618 * <p>
619 * This method is useful when the list is too long to allow the
620 * {@code ListUI} to compute the width/height of each cell, and there is a
621 * single cell value that is known to occupy as much space as any of the
622 * others, a so-called prototype.
623 * <p>
624 * While all three of the {@code prototypeCellValue},
625 * {@code fixedCellHeight}, and {@code fixedCellWidth} properties may be
626 * modified by this method, {@code PropertyChangeEvent} notifications are
627 * only sent when the {@code prototypeCellValue} property changes.
628 * <p>
629 * To see an example which sets this property, see the
630 * <a href="#prototype_example">class description</a> above.
631 * <p>
632 * The default value of this property is {@code null}.
633 * <p>
634 * This is a JavaBeans bound property.
635 *
636 * @param prototypeCellValue the value on which to base
637 * {@code fixedCellWidth} and
638 * {@code fixedCellHeight}
639 * @see #getPrototypeCellValue
640 * @see #setFixedCellWidth
641 * @see #setFixedCellHeight
642 * @see JComponent#addPropertyChangeListener
643 * @beaninfo
644 * bound: true
645 * attribute: visualUpdate true
646 * description: The cell prototype value, used to compute cell width and height.
647 */
648 public void setPrototypeCellValue(E prototypeCellValue) {
649 E oldValue = this.prototypeCellValue;
650 this.prototypeCellValue = prototypeCellValue;
651
652 /* If the prototypeCellValue has changed and is non-null,
653 * then recompute fixedCellWidth and fixedCellHeight.
654 */
655
656 if ((prototypeCellValue != null) && !prototypeCellValue.equals(oldValue)) {
657 updateFixedCellSize();
658 }
659
660 firePropertyChange("prototypeCellValue", oldValue, prototypeCellValue);
661 }
662
663
664 /**
665 * Returns the value of the {@code fixedCellWidth} property.
666 *
667 * @return the fixed cell width
668 * @see #setFixedCellWidth
669 */
670 public int getFixedCellWidth() {
671 return fixedCellWidth;
672 }
673
674 /**
675 * Sets a fixed value to be used for the width of every cell in the list.
676 * If {@code width} is -1, cell widths are computed in the {@code ListUI}
677 * by applying {@code getPreferredSize} to the cell renderer component
678 * for each list element.
679 * <p>
680 * The default value of this property is {@code -1}.
681 * <p>
682 * This is a JavaBeans bound property.
683 *
684 * @param width the width to be used for all cells in the list
685 * @see #setPrototypeCellValue
686 * @see #setFixedCellWidth
687 * @see JComponent#addPropertyChangeListener
688 * @beaninfo
689 * bound: true
690 * attribute: visualUpdate true
691 * description: Defines a fixed cell width when greater than zero.
692 */
693 public void setFixedCellWidth(int width) {
694 int oldValue = fixedCellWidth;
695 fixedCellWidth = width;
696 firePropertyChange("fixedCellWidth", oldValue, fixedCellWidth);
697 }
698
699
700 /**
701 * Returns the value of the {@code fixedCellHeight} property.
702 *
703 * @return the fixed cell height
704 * @see #setFixedCellHeight
705 */
706 public int getFixedCellHeight() {
707 return fixedCellHeight;
708 }
709
710 /**
711 * Sets a fixed value to be used for the height of every cell in the list.
712 * If {@code height} is -1, cell heights are computed in the {@code ListUI}
713 * by applying {@code getPreferredSize} to the cell renderer component
714 * for each list element.
715 * <p>
716 * The default value of this property is {@code -1}.
717 * <p>
718 * This is a JavaBeans bound property.
719 *
720 * @param height the height to be used for all cells in the list
721 * @see #setPrototypeCellValue
722 * @see #setFixedCellWidth
723 * @see JComponent#addPropertyChangeListener
724 * @beaninfo
725 * bound: true
726 * attribute: visualUpdate true
727 * description: Defines a fixed cell height when greater than zero.
728 */
729 public void setFixedCellHeight(int height) {
730 int oldValue = fixedCellHeight;
731 fixedCellHeight = height;
732 firePropertyChange("fixedCellHeight", oldValue, fixedCellHeight);
733 }
735
736 /**
737 * Returns the object responsible for painting list items.
738 *
739 * @return the value of the {@code cellRenderer} property
740 * @see #setCellRenderer
741 */
742 @Transient
743 public ListCellRenderer<? super E> getCellRenderer() {
744 return cellRenderer;
745 }
746
747 /**
748 * Sets the delegate that is used to paint each cell in the list.
749 * The job of a cell renderer is discussed in detail in the
750 * <a href="#renderer">class level documentation</a>.
751 * <p>
752 * If the {@code prototypeCellValue} property is {@code non-null},
753 * setting the cell renderer also causes the {@code fixedCellWidth} and
754 * {@code fixedCellHeight} properties to be re-calculated. Only one
755 * {@code PropertyChangeEvent} is generated however -
756 * for the {@code cellRenderer} property.
757 * <p>
758 * The default value of this property is provided by the {@code ListUI}
759 * delegate, i.e. by the look and feel implementation.
760 * <p>
761 * This is a JavaBeans bound property.
762 *
763 * @param cellRenderer the {@code ListCellRenderer}
764 * that paints list cells
765 * @see #getCellRenderer
766 * @beaninfo
767 * bound: true
768 * attribute: visualUpdate true
769 * description: The component used to draw the cells.
770 */
771 public void setCellRenderer(ListCellRenderer<? super E> cellRenderer) {
772 ListCellRenderer<? super E> oldValue = this.cellRenderer;
773 this.cellRenderer = cellRenderer;
774
775 /* If the cellRenderer has changed and prototypeCellValue
776 * was set, then recompute fixedCellWidth and fixedCellHeight.
777 */
778 if ((cellRenderer != null) && !cellRenderer.equals(oldValue)) {
779 updateFixedCellSize();
780 }
781
782 firePropertyChange("cellRenderer", oldValue, cellRenderer);
783 }
956 * <pre>
957 * VERTICAL: 0
958 * 1
959 * 2
960 * 3
961 * 4
962 *
963 * HORIZONTAL_WRAP: 0 1 2
964 * 3 4
965 *
966 * VERTICAL_WRAP: 0 3
967 * 1 4
968 * 2
969 * </pre>
970 * <p>
971 * A description of these layouts follows:
972 *
973 * <table border="1"
974 * summary="Describes layouts VERTICAL, HORIZONTAL_WRAP, and VERTICAL_WRAP">
975 * <tr><th><p style="text-align:left">Value</p></th><th><p style="text-align:left">Description</p></th></tr>
976 * <tr><td>{@code VERTICAL}
977 * <td>Cells are layed out vertically in a single column.
978 * <tr><td>{@code HORIZONTAL_WRAP}
979 * <td>Cells are layed out horizontally, wrapping to a new row as
980 * necessary. If the {@code visibleRowCount} property is less than
981 * or equal to zero, wrapping is determined by the width of the
982 * list; otherwise wrapping is done in such a way as to ensure
983 * {@code visibleRowCount} rows in the list.
984 * <tr><td>{@code VERTICAL_WRAP}
985 * <td>Cells are layed out vertically, wrapping to a new column as
986 * necessary. If the {@code visibleRowCount} property is less than
987 * or equal to zero, wrapping is determined by the height of the
988 * list; otherwise wrapping is done at {@code visibleRowCount} rows.
989 * </table>
990 * <p>
991 * The default value of this property is {@code VERTICAL}.
992 *
993 * @param layoutOrientation the new layout orientation, one of:
994 * {@code VERTICAL}, {@code HORIZONTAL_WRAP} or {@code VERTICAL_WRAP}
995 * @see #getLayoutOrientation
996 * @see #setVisibleRowCount
997 * @see #getScrollableTracksViewportHeight
998 * @see #getScrollableTracksViewportWidth
999 * @throws IllegalArgumentException if {@code layoutOrientation} isn't one of the
1000 * allowable values
1001 * @since 1.4
1002 * @beaninfo
1003 * bound: true
1004 * attribute: visualUpdate true
1005 * description: Defines the way list cells are layed out.
1006 * enum: VERTICAL JList.VERTICAL
1007 * HORIZONTAL_WRAP JList.HORIZONTAL_WRAP
1008 * VERTICAL_WRAP JList.VERTICAL_WRAP
1009 */
1010 public void setLayoutOrientation(int layoutOrientation) {
1011 int oldValue = this.layoutOrientation;
1119 }
1120 }
1121
1122 }
1123 else {
1124 last = visIndex;
1125 }
1126 }
1127 } while (visIndex != -1 && last != visIndex);
1128 }
1129 }
1130 }
1131 return location;
1132 }
1133
1134
1135 /**
1136 * Scrolls the list within an enclosing viewport to make the specified
1137 * cell completely visible. This calls {@code scrollRectToVisible} with
1138 * the bounds of the specified cell. For this method to work, the
1139 * {@code JList} must be within a {@code JViewport}.
1140 * <p>
1141 * If the given index is outside the list's range of cells, this method
1142 * results in nothing.
1143 *
1144 * @param index the index of the cell to make visible
1145 * @see JComponent#scrollRectToVisible
1146 * @see #getVisibleRect
1147 */
1148 public void ensureIndexIsVisible(int index) {
1149 Rectangle cellBounds = getCellBounds(index, index);
1150 if (cellBounds != null) {
1151 scrollRectToVisible(cellBounds);
1152 }
1153 }
1154
1155 /**
1156 * Turns on or off automatic drag handling. In order to enable automatic
1157 * drag handling, this property should be set to {@code true}, and the
1158 * list's {@code TransferHandler} needs to be {@code non-null}.
1159 * The default value of the {@code dragEnabled} property is {@code false}.
1160 * <p>
1161 * The job of honoring this property, and recognizing a user drag gesture,
1162 * lies with the look and feel implementation, and in particular, the list's
1163 * {@code ListUI}. When automatic drag handling is enabled, most look and
1164 * feels (including those that subclass {@code BasicLookAndFeel}) begin a
1165 * drag and drop operation whenever the user presses the mouse button over
1166 * an item and then moves the mouse a few pixels. Setting this property to
1167 * {@code true} can therefore have a subtle effect on how selections behave.
1168 * <p>
1169 * If a look and feel is used that ignores this property, you can still
1170 * begin a drag and drop operation by calling {@code exportAsDrag} on the
1171 * list's {@code TransferHandler}.
1172 *
1173 * @param b whether or not to enable automatic drag handling
1174 * @exception HeadlessException if
1175 * {@code b} is {@code true} and
1176 * {@code GraphicsEnvironment.isHeadless()}
1177 * returns {@code true}
1178 * @see java.awt.GraphicsEnvironment#isHeadless
1179 * @see #getDragEnabled
1180 * @see #setTransferHandler
1181 * @see TransferHandler
1182 * @since 1.4
1183 *
1184 * @beaninfo
1185 * description: determines whether automatic drag handling is enabled
1186 * bound: false
1187 */
1188 public void setDragEnabled(boolean b) {
1189 if (b && GraphicsEnvironment.isHeadless()) {
1190 throw new HeadlessException();
1191 }
1192 dragEnabled = b;
1193 }
1194
1195 /**
1196 * Returns whether or not automatic drag handling is enabled.
1197 *
1198 * @return the value of the {@code dragEnabled} property
1199 * @see #setDragEnabled
1200 * @since 1.4
1201 */
1202 public boolean getDragEnabled() {
1203 return dragEnabled;
1204 }
1205
1206 /**
1207 * Sets the drop mode for this component. For backward compatibility,
1208 * the default for this property is {@code DropMode.USE_SELECTION}.
1209 * Usage of one of the other modes is recommended, however, for an
1210 * improved user experience. {@code DropMode.ON}, for instance,
1211 * offers similar behavior of showing items as selected, but does so without
1212 * affecting the actual selection in the list.
1213 * <p>
1214 * {@code JList} supports the following drop modes:
1215 * <ul>
1216 * <li>{@code DropMode.USE_SELECTION}</li>
1217 * <li>{@code DropMode.ON}</li>
1218 * <li>{@code DropMode.INSERT}</li>
1219 * <li>{@code DropMode.ON_OR_INSERT}</li>
1220 * </ul>
1221 * The drop mode is only meaningful if this component has a
1222 * {@code TransferHandler} that accepts drops.
1223 *
1224 * @param dropMode the drop mode to use
1225 * @throws IllegalArgumentException if the drop mode is unsupported
1226 * or {@code null}
1227 * @see #getDropMode
1228 * @see #getDropLocation
1229 * @see #setTransferHandler
1230 * @see TransferHandler
1231 * @since 1.6
1232 */
1233 public final void setDropMode(DropMode dropMode) {
1234 if (dropMode != null) {
1235 switch (dropMode) {
1236 case USE_SELECTION:
1237 case ON:
1238 case INSERT:
1239 case ON_OR_INSERT:
1240 this.dropMode = dropMode;
1241 return;
1242 }
1243 }
1244
1245 throw new IllegalArgumentException(dropMode + ": Unsupported drop mode for list");
1246 }
1247
1248 /**
1249 * Returns the drop mode for this component.
1250 *
1251 * @return the drop mode for this component
1252 * @see #setDropMode
1253 * @since 1.6
1254 */
1255 public final DropMode getDropMode() {
1256 return dropMode;
1257 }
1258
1259 /**
1260 * Calculates a drop location in this component, representing where a
1261 * drop at the given point should insert data.
1262 *
1263 * @param p the point to calculate a drop location for
1264 * @return the drop location, or {@code null}
1265 */
1266 DropLocation dropLocationForPoint(Point p) {
1267 DropLocation location = null;
1268 Rectangle rect = null;
1269
1270 int index = locationToIndex(p);
1271 if (index != -1) {
1272 rect = getCellBounds(index, index);
1273 }
1274
1275 switch(dropMode) {
1276 case USE_SELECTION:
1277 case ON:
1278 location = new DropLocation(p,
1279 (rect != null && rect.contains(p)) ? index : -1,
1280 false);
1281
1282 break;
1283 case INSERT:
1284 if (index == -1) {
1347 }
1348
1349 /**
1350 * Called to set or clear the drop location during a DnD operation.
1351 * In some cases, the component may need to use it's internal selection
1352 * temporarily to indicate the drop location. To help facilitate this,
1353 * this method returns and accepts as a parameter a state object.
1354 * This state object can be used to store, and later restore, the selection
1355 * state. Whatever this method returns will be passed back to it in
1356 * future calls, as the state parameter. If it wants the DnD system to
1357 * continue storing the same state, it must pass it back every time.
1358 * Here's how this is used:
1359 * <p>
1360 * Let's say that on the first call to this method the component decides
1361 * to save some state (because it is about to use the selection to show
1362 * a drop index). It can return a state object to the caller encapsulating
1363 * any saved selection state. On a second call, let's say the drop location
1364 * is being changed to something else. The component doesn't need to
1365 * restore anything yet, so it simply passes back the same state object
1366 * to have the DnD system continue storing it. Finally, let's say this
1367 * method is messaged with {@code null}. This means DnD
1368 * is finished with this component for now, meaning it should restore
1369 * state. At this point, it can use the state parameter to restore
1370 * said state, and of course return {@code null} since there's
1371 * no longer anything to store.
1372 *
1373 * @param location the drop location (as calculated by
1374 * {@code dropLocationForPoint}) or {@code null}
1375 * if there's no longer a valid drop location
1376 * @param state the state object saved earlier for this component,
1377 * or {@code null}
1378 * @param forDrop whether or not the method is being called because an
1379 * actual drop occurred
1380 * @return any saved state for this component, or {@code null} if none
1381 */
1382 Object setDropLocation(TransferHandler.DropLocation location,
1383 Object state,
1384 boolean forDrop) {
1385
1386 Object retVal = null;
1387 DropLocation listLocation = (DropLocation)location;
1388
1389 if (dropMode == DropMode.USE_SELECTION) {
1390 if (listLocation == null) {
1391 if (!forDrop && state != null) {
1392 setSelectedIndices(((int[][])state)[0]);
1393
1394 int anchor = ((int[][])state)[1][0];
1395 int lead = ((int[][])state)[1][1];
1396
1397 SwingUtilities2.setLeadAnchorWithoutSelection(
1398 getSelectionModel(), lead, anchor);
1399 }
1400 } else {
1414 } else {
1415 setSelectionInterval(index, index);
1416 }
1417 }
1418 }
1419
1420 DropLocation old = dropLocation;
1421 dropLocation = listLocation;
1422 firePropertyChange("dropLocation", old, dropLocation);
1423
1424 return retVal;
1425 }
1426
1427 /**
1428 * Returns the location that this component should visually indicate
1429 * as the drop location during a DnD operation over the component,
1430 * or {@code null} if no location is to currently be shown.
1431 * <p>
1432 * This method is not meant for querying the drop location
1433 * from a {@code TransferHandler}, as the drop location is only
1434 * set after the {@code TransferHandler}'s {@code canImport}
1435 * has returned and has allowed for the location to be shown.
1436 * <p>
1437 * When this property changes, a property change event with
1438 * name "dropLocation" is fired by the component.
1439 * <p>
1440 * By default, responsibility for listening for changes to this property
1441 * and indicating the drop location visually lies with the list's
1442 * {@code ListUI}, which may paint it directly and/or install a cell
1443 * renderer to do so. Developers wishing to implement custom drop location
1444 * painting and/or replace the default cell renderer, may need to honor
1445 * this property.
1446 *
1447 * @return the drop location
1448 * @see #setDropMode
1449 * @see TransferHandler#canImport(TransferHandler.TransferSupport)
1450 * @since 1.6
1451 */
1452 public final DropLocation getDropLocation() {
1453 return dropLocation;
1454 }
1497 }
1498 }
1499
1500 if (string != null && string.startsWith(prefix)) {
1501 return index;
1502 }
1503 }
1504 index = (index + increment + max) % max;
1505 } while (index != startIndex);
1506 return -1;
1507 }
1508
1509 /**
1510 * Returns the tooltip text to be used for the given event. This overrides
1511 * {@code JComponent}'s {@code getToolTipText} to first check the cell
1512 * renderer component for the cell over which the event occurred, returning
1513 * its tooltip text, if any. This implementation allows you to specify
1514 * tooltip text on the cell level, by using {@code setToolTipText} on your
1515 * cell renderer component.
1516 * <p>
1517 * <strong>Note:</strong> For {@code JList} to properly display the
1518 * tooltips of its renderers in this manner, {@code JList} must be a
1519 * registered component with the {@code ToolTipManager}. This registration
1520 * is done automatically in the constructor. However, if at a later point
1521 * {@code JList} is unregistered, by way of a call to
1522 * {@code setToolTipText(null)}, tips from the renderers will no longer display.
1523 *
1524 * @param event the {@code MouseEvent} to fetch the tooltip text for
1525 * @see JComponent#setToolTipText
1526 * @see JComponent#getToolTipText
1527 */
1528 public String getToolTipText(MouseEvent event) {
1529 if(event != null) {
1530 Point p = event.getPoint();
1531 int index = locationToIndex(p);
1532 ListCellRenderer<? super E> r = getCellRenderer();
1533 Rectangle cellBounds;
1534
1535 if (index != -1 && r != null && (cellBounds =
1536 getCellBounds(index, index)) != null &&
1537 cellBounds.contains(p.x, p.y)) {
1538 ListSelectionModel lsm = getSelectionModel();
1539 Component rComponent = r.getListCellRendererComponent(
1540 this, getModel().getElementAt(index), index,
1541 lsm.isSelectedIndex(index),
1624 * in the list's {@code ListUI}. It returns {@code null} if the list has
1625 * no {@code ListUI}.
1626 *
1627 * @param index0 the first index in the range
1628 * @param index1 the second index in the range
1629 * @return the bounding rectangle for the range of cells, or {@code null}
1630 */
1631 public Rectangle getCellBounds(int index0, int index1) {
1632 ListUI ui = getUI();
1633 return (ui != null) ? ui.getCellBounds(this, index0, index1) : null;
1634 }
1635
1636
1637 /**
1638 * --- ListModel Support ---
1639 */
1640
1641
1642 /**
1643 * Returns the data model that holds the list of items displayed
1644 * by the {@code JList} component.
1645 *
1646 * @return the {@code ListModel} that provides the displayed
1647 * list of items
1648 * @see #setModel
1649 */
1650 public ListModel<E> getModel() {
1651 return dataModel;
1652 }
1653
1654 /**
1655 * Sets the model that represents the contents or "value" of the
1656 * list, notifies property change listeners, and then clears the
1657 * list's selection.
1658 * <p>
1659 * This is a JavaBeans bound property.
1660 *
1661 * @param model the {@code ListModel} that provides the
1662 * list of items for display
1663 * @exception IllegalArgumentException if {@code model} is
1664 * {@code null}
1665 * @see #getModel
1666 * @see #clearSelection
1667 * @beaninfo
1668 * bound: true
1669 * attribute: visualUpdate true
1670 * description: The object that contains the data to be drawn by this JList.
1671 */
1672 public void setModel(ListModel<E> model) {
1673 if (model == null) {
1674 throw new IllegalArgumentException("model must be non null");
1675 }
1676 ListModel<E> oldValue = dataModel;
1677 dataModel = model;
1678 firePropertyChange("model", oldValue, dataModel);
1679 clearSelection();
1680 }
1681
1682
1683 /**
1684 * Constructs a read-only {@code ListModel} from an array of items,
1685 * and calls {@code setModel} with this model.
1686 * <p>
1687 * Attempts to pass a {@code null} value to this method results in
1688 * undefined behavior and, most likely, exceptions. The created model
1689 * references the given array directly. Attempts to modify the array
1690 * after invoking this method results in undefined behavior.
1691 *
1692 * @param listData an array of {@code E} containing the items to
1693 * display in the list
1694 * @see #setModel
1695 */
1696 public void setListData(final E[] listData) {
1697 setModel (
1698 new AbstractListModel<E>() {
1699 public int getSize() { return listData.length; }
1700 public E getElementAt(int i) { return listData[i]; }
1701 }
1702 );
1703 }
1704
1705
1706 /**
1707 * Constructs a read-only {@code ListModel} from a {@code Vector}
1708 * and calls {@code setModel} with this model.
1709 * <p>
1710 * Attempts to pass a {@code null} value to this method results in
1711 * undefined behavior and, most likely, exceptions. The created model
1712 * references the given {@code Vector} directly. Attempts to modify the
1713 * {@code Vector} after invoking this method results in undefined behavior.
1714 *
1715 * @param listData a {@code Vector} containing the items to
1716 * display in the list
1717 * @see #setModel
1718 */
1719 public void setListData(final Vector<? extends E> listData) {
1720 setModel (
1721 new AbstractListModel<E>() {
1722 public int getSize() { return listData.size(); }
1723 public E getElementAt(int i) { return listData.elementAt(i); }
1724 }
1725 );
1726 }
1727
1728
1729 /**
1730 * --- ListSelectionModel delegations and extensions ---
1731 */
1732
1733
1734 /**
1735 * Returns an instance of {@code DefaultListSelectionModel}; called
1736 * during construction to initialize the list's selection model
1737 * property.
1738 *
1739 * @return a {@code DefaultListSelecitonModel}, used to initialize
1740 * the list's selection model property during construction
1741 * @see #setSelectionModel
1742 * @see DefaultListSelectionModel
1743 */
1744 protected ListSelectionModel createSelectionModel() {
1745 return new DefaultListSelectionModel();
1746 }
1747
1748
1749 /**
1750 * Returns the current selection model. The selection model maintains the
1751 * selection state of the list. See the class level documentation for more
1752 * details.
1753 *
1754 * @return the {@code ListSelectionModel} that maintains the
1755 * list's selections
1756 *
1757 * @see #setSelectionModel
1758 * @see ListSelectionModel
1759 */
1760 public ListSelectionModel getSelectionModel() {
1761 return selectionModel;
1762 }
1763
1764
1765 /**
1766 * Notifies {@code ListSelectionListener}s added directly to the list
1767 * of selection changes made to the selection model. {@code JList}
1768 * listens for changes made to the selection in the selection model,
1769 * and forwards notification to listeners added to the list directly,
1770 * by calling this method.
1771 * <p>
1772 * This method constructs a {@code ListSelectionEvent} with this list
1773 * as the source, and the specified arguments, and sends it to the
1774 * registered {@code ListSelectionListeners}.
1849 public void removeListSelectionListener(ListSelectionListener listener) {
1850 listenerList.remove(ListSelectionListener.class, listener);
1851 }
1852
1853
1854 /**
1855 * Returns an array of all the {@code ListSelectionListener}s added
1856 * to this {@code JList} by way of {@code addListSelectionListener}.
1857 *
1858 * @return all of the {@code ListSelectionListener}s on this list, or
1859 * an empty array if no listeners have been added
1860 * @see #addListSelectionListener
1861 * @since 1.4
1862 */
1863 public ListSelectionListener[] getListSelectionListeners() {
1864 return listenerList.getListeners(ListSelectionListener.class);
1865 }
1866
1867
1868 /**
1869 * Sets the {@code selectionModel} for the list to a
1870 * non-{@code null ListSelectionModel}
1871 * implementation. The selection model handles the task of making single
1872 * selections, selections of contiguous ranges, and non-contiguous
1873 * selections.
1874 * <p>
1875 * This is a JavaBeans bound property.
1876 *
1877 * @param selectionModel the {@code ListSelectionModel} that
1878 * implements the selections
1879 * @exception IllegalArgumentException if {@code selectionModel}
1880 * is {@code null}
1881 * @see #getSelectionModel
1882 * @beaninfo
1883 * bound: true
1884 * description: The selection model, recording which cells are selected.
1885 */
1886 public void setSelectionModel(ListSelectionModel selectionModel) {
1887 if (selectionModel == null) {
1888 throw new IllegalArgumentException("selectionModel must be non null");
1889 }
1890
1891 /* Remove the forwarding ListSelectionListener from the old
1892 * selectionModel, and add it to the new one, if necessary.
1893 */
1894 if (selectionListener != null) {
1895 this.selectionModel.removeListSelectionListener(selectionListener);
1896 selectionModel.addListSelectionListener(selectionListener);
1897 }
1898
1899 ListSelectionModel oldValue = this.selectionModel;
1900 this.selectionModel = selectionModel;
2863 */
2864 public AccessibleContext getAccessibleContext() {
2865 if (accessibleContext == null) {
2866 accessibleContext = new AccessibleJList();
2867 }
2868 return accessibleContext;
2869 }
2870
2871 /**
2872 * This class implements accessibility support for the
2873 * {@code JList} class. It provides an implementation of the
2874 * Java Accessibility API appropriate to list user-interface
2875 * elements.
2876 * <p>
2877 * <strong>Warning:</strong>
2878 * Serialized objects of this class will not be compatible with
2879 * future Swing releases. The current serialization support is
2880 * appropriate for short term storage or RMI between applications running
2881 * the same version of Swing. As of 1.4, support for long term storage
2882 * of all JavaBeans™
2883 * has been added to the {@code java.beans} package.
2884 * Please see {@link java.beans.XMLEncoder}.
2885 */
2886 @SuppressWarnings("serial") // Same-version serialization only
2887 protected class AccessibleJList extends AccessibleJComponent
2888 implements AccessibleSelection, PropertyChangeListener,
2889 ListSelectionListener, ListDataListener {
2890
2891 int leadSelectionIndex;
2892
2893 /**
2894 * Constructs an {@code AccessibleJList}.
2895 */
2896 public AccessibleJList() {
2897 super();
2898 JList.this.addPropertyChangeListener(this);
2899 JList.this.getSelectionModel().addListSelectionListener(this);
2900 JList.this.getModel().addListDataListener(this);
2901 leadSelectionIndex = JList.this.getLeadSelectionIndex();
2902 }
2903
3031 AccessibleStateSet states = super.getAccessibleStateSet();
3032 if (selectionModel.getSelectionMode() !=
3033 ListSelectionModel.SINGLE_SELECTION) {
3034 states.add(AccessibleState.MULTISELECTABLE);
3035 }
3036 return states;
3037 }
3038
3039 /**
3040 * Get the role of this object.
3041 *
3042 * @return an instance of AccessibleRole describing the role of the
3043 * object
3044 * @see AccessibleRole
3045 */
3046 public AccessibleRole getAccessibleRole() {
3047 return AccessibleRole.LIST;
3048 }
3049
3050 /**
3051 * Returns the {@code Accessible} child contained at
3052 * the local coordinate {@code Point}, if one exists.
3053 * Otherwise returns {@code null}.
3054 *
3055 * @return the {@code Accessible} at the specified
3056 * location, if it exists
3057 */
3058 public Accessible getAccessibleAt(Point p) {
3059 int i = locationToIndex(p);
3060 if (i >= 0) {
3061 return new AccessibleJListChild(JList.this, i);
3062 } else {
3063 return null;
3064 }
3065 }
3066
3067 /**
3068 * Returns the number of accessible children in the object. If all
3069 * of the children of this object implement Accessible, than this
3070 * method should return the number of children of this object.
3071 *
3072 * @return the number of accessible children in the object.
3073 */
3074 public int getAccessibleChildrenCount() {
3075 return getModel().getSize();
3101 return this;
3102 }
3103
3104
3105 // AccessibleSelection methods
3106
3107 /**
3108 * Returns the number of items currently selected.
3109 * If no items are selected, the return value will be 0.
3110 *
3111 * @return the number of items currently selected.
3112 */
3113 public int getAccessibleSelectionCount() {
3114 return JList.this.getSelectedIndices().length;
3115 }
3116
3117 /**
3118 * Returns an Accessible representing the specified selected item
3119 * in the object. If there isn't a selection, or there are
3120 * fewer items selected than the integer passed in, the return
3121 * value will be {@code null}.
3122 *
3123 * @param i the zero-based index of selected items
3124 * @return an Accessible containing the selected item
3125 */
3126 public Accessible getAccessibleSelection(int i) {
3127 int len = getAccessibleSelectionCount();
3128 if (i < 0 || i >= len) {
3129 return null;
3130 } else {
3131 return getAccessibleChild(JList.this.getSelectedIndices()[i]);
3132 }
3133 }
3134
3135 /**
3136 * Returns true if the current child of this object is selected.
3137 *
3138 * @param i the zero-based index of the child in this Accessible
3139 * object.
3140 * @see AccessibleContext#getAccessibleChild
3141 */
3708 c.addFocusListener(l);
3709 }
3710 }
3711 }
3712
3713 public void removeFocusListener(FocusListener l) {
3714 AccessibleContext ac = getCurrentAccessibleContext();
3715 if (ac instanceof AccessibleComponent) {
3716 ((AccessibleComponent) ac).removeFocusListener(l);
3717 } else {
3718 Component c = getCurrentComponent();
3719 if (c != null) {
3720 c.removeFocusListener(l);
3721 }
3722 }
3723 }
3724
3725 // TIGER - 4733624
3726 /**
3727 * Returns the icon for the element renderer, as the only item
3728 * of an array of {@code AccessibleIcon}s or a {@code null} array
3729 * if the renderer component contains no icons.
3730 *
3731 * @return an array containing the accessible icon
3732 * or a {@code null} array if none
3733 * @since 1.3
3734 */
3735 public AccessibleIcon [] getAccessibleIcon() {
3736 AccessibleContext ac = getCurrentAccessibleContext();
3737 if (ac != null) {
3738 return ac.getAccessibleIcon();
3739 } else {
3740 return null;
3741 }
3742 }
3743 } // inner class AccessibleJListChild
3744 } // inner class AccessibleJList
3745 }
|