Print this page
Split |
Close |
Expand all |
Collapse all |
--- old/src/share/classes/javax/swing/JList.java
+++ new/src/share/classes/javax/swing/JList.java
1 1 /*
2 2 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
3 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 4 *
5 5 * This code is free software; you can redistribute it and/or modify it
6 6 * under the terms of the GNU General Public License version 2 only, as
7 7 * published by the Free Software Foundation. Oracle designates this
8 8 * particular file as subject to the "Classpath" exception as provided
9 9 * by Oracle in the LICENSE file that accompanied this code.
10 10 *
11 11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 14 * version 2 for more details (a copy is included in the LICENSE file that
15 15 * accompanied this code).
16 16 *
17 17 * You should have received a copy of the GNU General Public License version
18 18 * 2 along with this work; if not, write to the Free Software Foundation,
19 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 20 *
21 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 22 * or visit www.oracle.com if you need additional information or have any
23 23 * questions.
24 24 */
25 25
26 26 package javax.swing;
27 27
28 28 import java.awt.*;
29 29 import java.awt.event.*;
30 30
31 31 import java.util.Vector;
32 32 import java.util.Locale;
33 33 import java.util.ArrayList;
34 34 import java.util.Collections;
35 35 import java.util.List;
36 36
37 37 import java.beans.PropertyChangeEvent;
38 38 import java.beans.PropertyChangeListener;
39 39 import java.beans.Transient;
40 40
41 41 import javax.swing.event.*;
42 42 import javax.accessibility.*;
43 43 import javax.swing.plaf.*;
44 44 import javax.swing.text.Position;
45 45
46 46 import java.io.ObjectOutputStream;
47 47 import java.io.ObjectInputStream;
48 48 import java.io.IOException;
49 49 import java.io.Serializable;
50 50
51 51 import sun.swing.SwingUtilities2;
52 52 import sun.swing.SwingUtilities2.Section;
53 53 import static sun.swing.SwingUtilities2.Section.*;
54 54
55 55
56 56 /**
57 57 * A component that displays a list of objects and allows the user to select
58 58 * one or more items. A separate model, {@code ListModel}, maintains the
59 59 * contents of the list.
60 60 * <p>
61 61 * It's easy to display an array or Vector of objects, using the {@code JList}
62 62 * constructor that automatically builds a read-only {@code ListModel} instance
63 63 * for you:
64 64 * <pre>
65 65 * {@code
66 66 * // Create a JList that displays strings from an array
67 67 *
68 68 * String[] data = {"one", "two", "three", "four"};
69 69 * JList<String> myList = new JList<String>(data);
70 70 *
71 71 * // Create a JList that displays the superclasses of JList.class, by
72 72 * // creating it with a Vector populated with this data
73 73 *
74 74 * Vector<Class<?>> superClasses = new Vector<Class<?>>();
75 75 * Class<JList> rootClass = javax.swing.JList.class;
76 76 * for(Class<?> cls = rootClass; cls != null; cls = cls.getSuperclass()) {
77 77 * superClasses.addElement(cls);
78 78 * }
79 79 * JList<Class<?>> myList = new JList<Class<?>>(superClasses);
80 80 *
81 81 * // The automatically created model is stored in JList's "model"
82 82 * // property, which you can retrieve
83 83 *
84 84 * ListModel<Class<?>> model = myList.getModel();
85 85 * for(int i = 0; i < model.getSize(); i++) {
86 86 * System.out.println(model.getElementAt(i));
87 87 * }
88 88 * }
89 89 * </pre>
90 90 * <p>
91 91 * A {@code ListModel} can be supplied directly to a {@code JList} by way of a
92 92 * constructor or the {@code setModel} method. The contents need not be static -
93 93 * the number of items, and the values of items can change over time. A correct
94 94 * {@code ListModel} implementation notifies the set of
95 95 * {@code javax.swing.event.ListDataListener}s that have been added to it, each
96 96 * time a change occurs. These changes are characterized by a
97 97 * {@code javax.swing.event.ListDataEvent}, which identifies the range of list
98 98 * indices that have been modified, added, or removed. {@code JList}'s
99 99 * {@code ListUI} is responsible for keeping the visual representation up to
100 100 * date with changes, by listening to the model.
101 101 * <p>
102 102 * Simple, dynamic-content, {@code JList} applications can use the
103 103 * {@code DefaultListModel} class to maintain list elements. This class
104 104 * implements the {@code ListModel} interface and also provides a
105 105 * <code>java.util.Vector</code>-like API. Applications that need a more
106 106 * custom <code>ListModel</code> implementation may instead wish to subclass
107 107 * {@code AbstractListModel}, which provides basic support for managing and
108 108 * notifying listeners. For example, a read-only implementation of
109 109 * {@code AbstractListModel}:
110 110 * <pre>
111 111 * {@code
112 112 * // This list model has about 2^16 elements. Enjoy scrolling.
113 113 *
114 114 * ListModel<String> bigData = new AbstractListModel<String>() {
115 115 * public int getSize() { return Short.MAX_VALUE; }
116 116 * public String getElementAt(int index) { return "Index " + index; }
117 117 * };
118 118 * }
119 119 * </pre>
120 120 * <p>
121 121 * The selection state of a {@code JList} is managed by another separate
122 122 * model, an instance of {@code ListSelectionModel}. {@code JList} is
123 123 * initialized with a selection model on construction, and also contains
124 124 * methods to query or set this selection model. Additionally, {@code JList}
125 125 * provides convenient methods for easily managing the selection. These methods,
126 126 * such as {@code setSelectedIndex} and {@code getSelectedValue}, are cover
127 127 * methods that take care of the details of interacting with the selection
128 128 * model. By default, {@code JList}'s selection model is configured to allow any
129 129 * combination of items to be selected at a time; selection mode
130 130 * {@code MULTIPLE_INTERVAL_SELECTION}. The selection mode can be changed
131 131 * on the selection model directly, or via {@code JList}'s cover method.
132 132 * Responsibility for updating the selection model in response to user gestures
133 133 * lies with the list's {@code ListUI}.
134 134 * <p>
135 135 * A correct {@code ListSelectionModel} implementation notifies the set of
136 136 * {@code javax.swing.event.ListSelectionListener}s that have been added to it
137 137 * each time a change to the selection occurs. These changes are characterized
138 138 * by a {@code javax.swing.event.ListSelectionEvent}, which identifies the range
139 139 * of the selection change.
140 140 * <p>
141 141 * The preferred way to listen for changes in list selection is to add
142 142 * {@code ListSelectionListener}s directly to the {@code JList}. {@code JList}
143 143 * then takes care of listening to the the selection model and notifying your
144 144 * listeners of change.
145 145 * <p>
146 146 * Responsibility for listening to selection changes in order to keep the list's
147 147 * visual representation up to date lies with the list's {@code ListUI}.
148 148 * <p>
149 149 * <a name="renderer"></a>
150 150 * Painting of cells in a {@code JList} is handled by a delegate called a
151 151 * cell renderer, installed on the list as the {@code cellRenderer} property.
152 152 * The renderer provides a {@code java.awt.Component} that is used
153 153 * like a "rubber stamp" to paint the cells. Each time a cell needs to be
154 154 * painted, the list's {@code ListUI} asks the cell renderer for the component,
155 155 * moves it into place, and has it paint the contents of the cell by way of its
156 156 * {@code paint} method. A default cell renderer, which uses a {@code JLabel}
157 157 * component to render, is installed by the lists's {@code ListUI}. You can
158 158 * substitute your own renderer using code like this:
159 159 * <pre>
160 160 * {@code
161 161 * // Display an icon and a string for each object in the list.
162 162 *
163 163 * class MyCellRenderer extends JLabel implements ListCellRenderer<Object> {
164 164 * final static ImageIcon longIcon = new ImageIcon("long.gif");
165 165 * final static ImageIcon shortIcon = new ImageIcon("short.gif");
166 166 *
167 167 * // This is the only method defined by ListCellRenderer.
168 168 * // We just reconfigure the JLabel each time we're called.
169 169 *
170 170 * public Component getListCellRendererComponent(
171 171 * JList<?> list, // the list
172 172 * Object value, // value to display
173 173 * int index, // cell index
174 174 * boolean isSelected, // is the cell selected
175 175 * boolean cellHasFocus) // does the cell have focus
176 176 * {
177 177 * String s = value.toString();
178 178 * setText(s);
179 179 * setIcon((s.length() > 10) ? longIcon : shortIcon);
180 180 * if (isSelected) {
181 181 * setBackground(list.getSelectionBackground());
182 182 * setForeground(list.getSelectionForeground());
183 183 * } else {
184 184 * setBackground(list.getBackground());
185 185 * setForeground(list.getForeground());
186 186 * }
187 187 * setEnabled(list.isEnabled());
188 188 * setFont(list.getFont());
189 189 * setOpaque(true);
190 190 * return this;
191 191 * }
192 192 * }
193 193 *
194 194 * myList.setCellRenderer(new MyCellRenderer());
195 195 * }
196 196 * </pre>
197 197 * <p>
198 198 * Another job for the cell renderer is in helping to determine sizing
199 199 * information for the list. By default, the list's {@code ListUI} determines
200 200 * the size of cells by asking the cell renderer for its preferred
201 201 * size for each list item. This can be expensive for large lists of items.
202 202 * To avoid these calculations, you can set a {@code fixedCellWidth} and
203 203 * {@code fixedCellHeight} on the list, or have these values calculated
204 204 * automatically based on a single prototype value:
205 205 * <a name="prototype_example"></a>
206 206 * <pre>
207 207 * {@code
208 208 * JList<String> bigDataList = new JList<String>(bigData);
209 209 *
210 210 * // We don't want the JList implementation to compute the width
211 211 * // or height of all of the list cells, so we give it a string
212 212 * // that's as big as we'll need for any cell. It uses this to
213 213 * // compute values for the fixedCellWidth and fixedCellHeight
214 214 * // properties.
215 215 *
216 216 * bigDataList.setPrototypeCellValue("Index 1234567890");
217 217 * }
218 218 * </pre>
219 219 * <p>
220 220 * {@code JList} doesn't implement scrolling directly. To create a list that
221 221 * scrolls, make it the viewport view of a {@code JScrollPane}. For example:
222 222 * <pre>
223 223 * JScrollPane scrollPane = new JScrollPane(myList);
224 224 *
225 225 * // Or in two steps:
226 226 * JScrollPane scrollPane = new JScrollPane();
227 227 * scrollPane.getViewport().setView(myList);
228 228 * </pre>
229 229 * <p>
230 230 * {@code JList} doesn't provide any special handling of double or triple
231 231 * (or N) mouse clicks, but it's easy to add a {@code MouseListener} if you
232 232 * wish to take action on these events. Use the {@code locationToIndex}
233 233 * method to determine what cell was clicked. For example:
234 234 * <pre>
235 235 * MouseListener mouseListener = new MouseAdapter() {
236 236 * public void mouseClicked(MouseEvent e) {
237 237 * if (e.getClickCount() == 2) {
238 238 * int index = list.locationToIndex(e.getPoint());
239 239 * System.out.println("Double clicked on Item " + index);
240 240 * }
241 241 * }
242 242 * };
243 243 * list.addMouseListener(mouseListener);
244 244 * </pre>
245 245 * <p>
246 246 * <strong>Warning:</strong> Swing is not thread safe. For more
247 247 * information see <a
248 248 * href="package-summary.html#threading">Swing's Threading
249 249 * Policy</a>.
↓ open down ↓ |
249 lines elided |
↑ open up ↑ |
250 250 * <p>
251 251 * <strong>Warning:</strong>
252 252 * Serialized objects of this class will not be compatible with
253 253 * future Swing releases. The current serialization support is
254 254 * appropriate for short term storage or RMI between applications running
255 255 * the same version of Swing. As of 1.4, support for long term storage
256 256 * of all JavaBeans™
257 257 * has been added to the <code>java.beans</code> package.
258 258 * Please see {@link java.beans.XMLEncoder}.
259 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>
260 + * See <a href="https://docs.oracle.com/javase/tutorial/uiswing/components/list.html">How to Use Lists</a>
261 + * in <a href="https://docs.oracle.com/javase/tutorial/"><em>The Java Tutorial</em></a>
262 262 * for further documentation.
263 263 * <p>
264 264 * @see ListModel
265 265 * @see AbstractListModel
266 266 * @see DefaultListModel
267 267 * @see ListSelectionModel
268 268 * @see DefaultListSelectionModel
269 269 * @see ListCellRenderer
270 270 * @see DefaultListCellRenderer
271 271 *
272 272 * @param <E> the type of the elements of this list
273 273 *
274 274 * @beaninfo
275 275 * attribute: isContainer false
276 276 * description: A component which allows for the selection of one or more objects from a list.
277 277 *
278 278 * @author Hans Muller
279 279 */
280 280 public class JList<E> extends JComponent implements Scrollable, Accessible
281 281 {
282 282 /**
283 283 * @see #getUIClassID
284 284 * @see #readObject
285 285 */
286 286 private static final String uiClassID = "ListUI";
287 287
288 288 /**
289 289 * Indicates a vertical layout of cells, in a single column;
290 290 * the default layout.
291 291 * @see #setLayoutOrientation
292 292 * @since 1.4
293 293 */
294 294 public static final int VERTICAL = 0;
295 295
296 296 /**
297 297 * Indicates a "newspaper style" layout with cells flowing vertically
298 298 * then horizontally.
299 299 * @see #setLayoutOrientation
300 300 * @since 1.4
301 301 */
302 302 public static final int VERTICAL_WRAP = 1;
303 303
304 304 /**
305 305 * Indicates a "newspaper style" layout with cells flowing horizontally
306 306 * then vertically.
307 307 * @see #setLayoutOrientation
308 308 * @since 1.4
309 309 */
310 310 public static final int HORIZONTAL_WRAP = 2;
311 311
312 312 private int fixedCellWidth = -1;
313 313 private int fixedCellHeight = -1;
314 314 private int horizontalScrollIncrement = -1;
315 315 private E prototypeCellValue;
316 316 private int visibleRowCount = 8;
317 317 private Color selectionForeground;
318 318 private Color selectionBackground;
319 319 private boolean dragEnabled;
320 320
321 321 private ListSelectionModel selectionModel;
322 322 private ListModel<E> dataModel;
323 323 private ListCellRenderer<? super E> cellRenderer;
324 324 private ListSelectionListener selectionListener;
325 325
326 326 /**
327 327 * How to lay out the cells; defaults to <code>VERTICAL</code>.
328 328 */
329 329 private int layoutOrientation;
330 330
331 331 /**
332 332 * The drop mode for this component.
333 333 */
334 334 private DropMode dropMode = DropMode.USE_SELECTION;
335 335
336 336 /**
337 337 * The drop location.
338 338 */
339 339 private transient DropLocation dropLocation;
340 340
341 341 /**
342 342 * A subclass of <code>TransferHandler.DropLocation</code> representing
343 343 * a drop location for a <code>JList</code>.
344 344 *
345 345 * @see #getDropLocation
346 346 * @since 1.6
347 347 */
348 348 public static final class DropLocation extends TransferHandler.DropLocation {
349 349 private final int index;
350 350 private final boolean isInsert;
351 351
352 352 private DropLocation(Point p, int index, boolean isInsert) {
353 353 super(p);
354 354 this.index = index;
355 355 this.isInsert = isInsert;
356 356 }
357 357
358 358 /**
359 359 * Returns the index where dropped data should be placed in the
360 360 * list. Interpretation of the value depends on the drop mode set on
361 361 * the associated component. If the drop mode is either
362 362 * <code>DropMode.USE_SELECTION</code> or <code>DropMode.ON</code>,
363 363 * the return value is an index of a row in the list. If the drop mode is
364 364 * <code>DropMode.INSERT</code>, the return value refers to the index
365 365 * where the data should be inserted. If the drop mode is
366 366 * <code>DropMode.ON_OR_INSERT</code>, the value of
367 367 * <code>isInsert()</code> indicates whether the index is an index
368 368 * of a row, or an insert index.
369 369 * <p>
370 370 * <code>-1</code> indicates that the drop occurred over empty space,
371 371 * and no index could be calculated.
372 372 *
373 373 * @return the drop index
374 374 */
375 375 public int getIndex() {
376 376 return index;
377 377 }
378 378
379 379 /**
380 380 * Returns whether or not this location represents an insert
381 381 * location.
382 382 *
383 383 * @return whether or not this is an insert location
384 384 */
385 385 public boolean isInsert() {
386 386 return isInsert;
387 387 }
388 388
389 389 /**
390 390 * Returns a string representation of this drop location.
391 391 * This method is intended to be used for debugging purposes,
392 392 * and the content and format of the returned string may vary
393 393 * between implementations.
394 394 *
395 395 * @return a string representation of this drop location
396 396 */
397 397 public String toString() {
398 398 return getClass().getName()
399 399 + "[dropPoint=" + getDropPoint() + ","
400 400 + "index=" + index + ","
401 401 + "insert=" + isInsert + "]";
402 402 }
403 403 }
404 404
405 405 /**
406 406 * Constructs a {@code JList} that displays elements from the specified,
407 407 * {@code non-null}, model. All {@code JList} constructors delegate to
408 408 * this one.
409 409 * <p>
410 410 * This constructor registers the list with the {@code ToolTipManager},
411 411 * allowing for tooltips to be provided by the cell renderers.
412 412 *
413 413 * @param dataModel the model for the list
414 414 * @exception IllegalArgumentException if the model is {@code null}
415 415 */
416 416 public JList(ListModel<E> dataModel)
417 417 {
418 418 if (dataModel == null) {
419 419 throw new IllegalArgumentException("dataModel must be non null");
420 420 }
421 421
422 422 // Register with the ToolTipManager so that tooltips from the
423 423 // renderer show through.
424 424 ToolTipManager toolTipManager = ToolTipManager.sharedInstance();
425 425 toolTipManager.registerComponent(this);
426 426
427 427 layoutOrientation = VERTICAL;
428 428
429 429 this.dataModel = dataModel;
430 430 selectionModel = createSelectionModel();
431 431 setAutoscrolls(true);
432 432 setOpaque(true);
433 433 updateUI();
434 434 }
435 435
436 436
437 437 /**
438 438 * Constructs a <code>JList</code> that displays the elements in
439 439 * the specified array. This constructor creates a read-only model
440 440 * for the given array, and then delegates to the constructor that
441 441 * takes a {@code ListModel}.
442 442 * <p>
443 443 * Attempts to pass a {@code null} value to this method results in
444 444 * undefined behavior and, most likely, exceptions. The created model
445 445 * references the given array directly. Attempts to modify the array
446 446 * after constructing the list results in undefined behavior.
447 447 *
448 448 * @param listData the array of Objects to be loaded into the data model,
449 449 * {@code non-null}
450 450 */
451 451 public JList(final E[] listData)
452 452 {
453 453 this (
454 454 new AbstractListModel<E>() {
455 455 public int getSize() { return listData.length; }
456 456 public E getElementAt(int i) { return listData[i]; }
457 457 }
458 458 );
459 459 }
460 460
461 461
462 462 /**
463 463 * Constructs a <code>JList</code> that displays the elements in
464 464 * the specified <code>Vector</code>. This constructor creates a read-only
465 465 * model for the given {@code Vector}, and then delegates to the constructor
466 466 * that takes a {@code ListModel}.
467 467 * <p>
468 468 * Attempts to pass a {@code null} value to this method results in
469 469 * undefined behavior and, most likely, exceptions. The created model
470 470 * references the given {@code Vector} directly. Attempts to modify the
471 471 * {@code Vector} after constructing the list results in undefined behavior.
472 472 *
473 473 * @param listData the <code>Vector</code> to be loaded into the
474 474 * data model, {@code non-null}
475 475 */
476 476 public JList(final Vector<? extends E> listData) {
477 477 this (
478 478 new AbstractListModel<E>() {
479 479 public int getSize() { return listData.size(); }
480 480 public E getElementAt(int i) { return listData.elementAt(i); }
481 481 }
482 482 );
483 483 }
484 484
485 485
486 486 /**
487 487 * Constructs a <code>JList</code> with an empty, read-only, model.
488 488 */
489 489 public JList() {
490 490 this (
491 491 new AbstractListModel<E>() {
492 492 public int getSize() { return 0; }
493 493 public E getElementAt(int i) { throw new IndexOutOfBoundsException("No Data Model"); }
494 494 }
495 495 );
496 496 }
497 497
498 498
499 499 /**
500 500 * Returns the {@code ListUI}, the look and feel object that
501 501 * renders this component.
502 502 *
503 503 * @return the <code>ListUI</code> object that renders this component
504 504 */
505 505 public ListUI getUI() {
506 506 return (ListUI)ui;
507 507 }
508 508
509 509
510 510 /**
511 511 * Sets the {@code ListUI}, the look and feel object that
512 512 * renders this component.
513 513 *
514 514 * @param ui the <code>ListUI</code> object
515 515 * @see UIDefaults#getUI
516 516 * @beaninfo
517 517 * bound: true
518 518 * hidden: true
519 519 * attribute: visualUpdate true
520 520 * description: The UI object that implements the Component's LookAndFeel.
521 521 */
522 522 public void setUI(ListUI ui) {
523 523 super.setUI(ui);
524 524 }
525 525
526 526
527 527 /**
528 528 * Resets the {@code ListUI} property by setting it to the value provided
529 529 * by the current look and feel. If the current cell renderer was installed
530 530 * by the developer (rather than the look and feel itself), this also causes
531 531 * the cell renderer and its children to be updated, by calling
532 532 * {@code SwingUtilities.updateComponentTreeUI} on it.
533 533 *
534 534 * @see UIManager#getUI
535 535 * @see SwingUtilities#updateComponentTreeUI
536 536 */
537 537 public void updateUI() {
538 538 setUI((ListUI)UIManager.getUI(this));
539 539
540 540 ListCellRenderer<? super E> renderer = getCellRenderer();
541 541 if (renderer instanceof Component) {
542 542 SwingUtilities.updateComponentTreeUI((Component)renderer);
543 543 }
544 544 }
545 545
546 546
547 547 /**
548 548 * Returns {@code "ListUI"}, the <code>UIDefaults</code> key used to look
549 549 * up the name of the {@code javax.swing.plaf.ListUI} class that defines
550 550 * the look and feel for this component.
551 551 *
552 552 * @return the string "ListUI"
553 553 * @see JComponent#getUIClassID
554 554 * @see UIDefaults#getUI
555 555 */
556 556 public String getUIClassID() {
557 557 return uiClassID;
558 558 }
559 559
560 560
561 561 /* -----private-----
562 562 * This method is called by setPrototypeCellValue and setCellRenderer
563 563 * to update the fixedCellWidth and fixedCellHeight properties from the
564 564 * current value of prototypeCellValue (if it's non null).
565 565 * <p>
566 566 * This method sets fixedCellWidth and fixedCellHeight but does <b>not</b>
567 567 * generate PropertyChangeEvents for them.
568 568 *
569 569 * @see #setPrototypeCellValue
570 570 * @see #setCellRenderer
571 571 */
572 572 private void updateFixedCellSize()
573 573 {
574 574 ListCellRenderer<? super E> cr = getCellRenderer();
575 575 E value = getPrototypeCellValue();
576 576
577 577 if ((cr != null) && (value != null)) {
578 578 Component c = cr.getListCellRendererComponent(this, value, 0, false, false);
579 579
580 580 /* The ListUI implementation will add Component c to its private
581 581 * CellRendererPane however we can't assume that's already
582 582 * been done here. So we temporarily set the one "inherited"
583 583 * property that may affect the renderer components preferred size:
584 584 * its font.
585 585 */
586 586 Font f = c.getFont();
587 587 c.setFont(getFont());
588 588
589 589 Dimension d = c.getPreferredSize();
590 590 fixedCellWidth = d.width;
591 591 fixedCellHeight = d.height;
592 592
593 593 c.setFont(f);
594 594 }
595 595 }
596 596
597 597
598 598 /**
599 599 * Returns the "prototypical" cell value -- a value used to calculate a
600 600 * fixed width and height for cells. This can be {@code null} if there
601 601 * is no such value.
602 602 *
603 603 * @return the value of the {@code prototypeCellValue} property
604 604 * @see #setPrototypeCellValue
605 605 */
606 606 public E getPrototypeCellValue() {
607 607 return prototypeCellValue;
608 608 }
609 609
610 610 /**
611 611 * Sets the {@code prototypeCellValue} property, and then (if the new value
612 612 * is {@code non-null}), computes the {@code fixedCellWidth} and
613 613 * {@code fixedCellHeight} properties by requesting the cell renderer
614 614 * component for the given value (and index 0) from the cell renderer, and
615 615 * using that component's preferred size.
616 616 * <p>
617 617 * This method is useful when the list is too long to allow the
618 618 * {@code ListUI} to compute the width/height of each cell, and there is a
619 619 * single cell value that is known to occupy as much space as any of the
620 620 * others, a so-called prototype.
621 621 * <p>
622 622 * While all three of the {@code prototypeCellValue},
623 623 * {@code fixedCellHeight}, and {@code fixedCellWidth} properties may be
624 624 * modified by this method, {@code PropertyChangeEvent} notifications are
625 625 * only sent when the {@code prototypeCellValue} property changes.
626 626 * <p>
627 627 * To see an example which sets this property, see the
628 628 * <a href="#prototype_example">class description</a> above.
629 629 * <p>
630 630 * The default value of this property is <code>null</code>.
631 631 * <p>
632 632 * This is a JavaBeans bound property.
633 633 *
634 634 * @param prototypeCellValue the value on which to base
635 635 * <code>fixedCellWidth</code> and
636 636 * <code>fixedCellHeight</code>
637 637 * @see #getPrototypeCellValue
638 638 * @see #setFixedCellWidth
639 639 * @see #setFixedCellHeight
640 640 * @see JComponent#addPropertyChangeListener
641 641 * @beaninfo
642 642 * bound: true
643 643 * attribute: visualUpdate true
644 644 * description: The cell prototype value, used to compute cell width and height.
645 645 */
646 646 public void setPrototypeCellValue(E prototypeCellValue) {
647 647 E oldValue = this.prototypeCellValue;
648 648 this.prototypeCellValue = prototypeCellValue;
649 649
650 650 /* If the prototypeCellValue has changed and is non-null,
651 651 * then recompute fixedCellWidth and fixedCellHeight.
652 652 */
653 653
654 654 if ((prototypeCellValue != null) && !prototypeCellValue.equals(oldValue)) {
655 655 updateFixedCellSize();
656 656 }
657 657
658 658 firePropertyChange("prototypeCellValue", oldValue, prototypeCellValue);
659 659 }
660 660
661 661
662 662 /**
663 663 * Returns the value of the {@code fixedCellWidth} property.
664 664 *
665 665 * @return the fixed cell width
666 666 * @see #setFixedCellWidth
667 667 */
668 668 public int getFixedCellWidth() {
669 669 return fixedCellWidth;
670 670 }
671 671
672 672 /**
673 673 * Sets a fixed value to be used for the width of every cell in the list.
674 674 * If {@code width} is -1, cell widths are computed in the {@code ListUI}
675 675 * by applying <code>getPreferredSize</code> to the cell renderer component
676 676 * for each list element.
677 677 * <p>
678 678 * The default value of this property is {@code -1}.
679 679 * <p>
680 680 * This is a JavaBeans bound property.
681 681 *
682 682 * @param width the width to be used for all cells in the list
683 683 * @see #setPrototypeCellValue
684 684 * @see #setFixedCellWidth
685 685 * @see JComponent#addPropertyChangeListener
686 686 * @beaninfo
687 687 * bound: true
688 688 * attribute: visualUpdate true
689 689 * description: Defines a fixed cell width when greater than zero.
690 690 */
691 691 public void setFixedCellWidth(int width) {
692 692 int oldValue = fixedCellWidth;
693 693 fixedCellWidth = width;
694 694 firePropertyChange("fixedCellWidth", oldValue, fixedCellWidth);
695 695 }
696 696
697 697
698 698 /**
699 699 * Returns the value of the {@code fixedCellHeight} property.
700 700 *
701 701 * @return the fixed cell height
702 702 * @see #setFixedCellHeight
703 703 */
704 704 public int getFixedCellHeight() {
705 705 return fixedCellHeight;
706 706 }
707 707
708 708 /**
709 709 * Sets a fixed value to be used for the height of every cell in the list.
710 710 * If {@code height} is -1, cell heights are computed in the {@code ListUI}
711 711 * by applying <code>getPreferredSize</code> to the cell renderer component
712 712 * for each list element.
713 713 * <p>
714 714 * The default value of this property is {@code -1}.
715 715 * <p>
716 716 * This is a JavaBeans bound property.
717 717 *
718 718 * @param height the height to be used for for all cells in the list
719 719 * @see #setPrototypeCellValue
720 720 * @see #setFixedCellWidth
721 721 * @see JComponent#addPropertyChangeListener
722 722 * @beaninfo
723 723 * bound: true
724 724 * attribute: visualUpdate true
725 725 * description: Defines a fixed cell height when greater than zero.
726 726 */
727 727 public void setFixedCellHeight(int height) {
728 728 int oldValue = fixedCellHeight;
729 729 fixedCellHeight = height;
730 730 firePropertyChange("fixedCellHeight", oldValue, fixedCellHeight);
731 731 }
732 732
733 733
734 734 /**
735 735 * Returns the object responsible for painting list items.
736 736 *
737 737 * @return the value of the {@code cellRenderer} property
738 738 * @see #setCellRenderer
739 739 */
740 740 @Transient
741 741 public ListCellRenderer<? super E> getCellRenderer() {
742 742 return cellRenderer;
743 743 }
744 744
745 745 /**
746 746 * Sets the delegate that is used to paint each cell in the list.
747 747 * The job of a cell renderer is discussed in detail in the
748 748 * <a href="#renderer">class level documentation</a>.
749 749 * <p>
750 750 * If the {@code prototypeCellValue} property is {@code non-null},
751 751 * setting the cell renderer also causes the {@code fixedCellWidth} and
752 752 * {@code fixedCellHeight} properties to be re-calculated. Only one
753 753 * <code>PropertyChangeEvent</code> is generated however -
754 754 * for the <code>cellRenderer</code> property.
755 755 * <p>
756 756 * The default value of this property is provided by the {@code ListUI}
757 757 * delegate, i.e. by the look and feel implementation.
758 758 * <p>
759 759 * This is a JavaBeans bound property.
760 760 *
761 761 * @param cellRenderer the <code>ListCellRenderer</code>
762 762 * that paints list cells
763 763 * @see #getCellRenderer
764 764 * @beaninfo
765 765 * bound: true
766 766 * attribute: visualUpdate true
767 767 * description: The component used to draw the cells.
768 768 */
769 769 public void setCellRenderer(ListCellRenderer<? super E> cellRenderer) {
770 770 ListCellRenderer<? super E> oldValue = this.cellRenderer;
771 771 this.cellRenderer = cellRenderer;
772 772
773 773 /* If the cellRenderer has changed and prototypeCellValue
774 774 * was set, then recompute fixedCellWidth and fixedCellHeight.
775 775 */
776 776 if ((cellRenderer != null) && !cellRenderer.equals(oldValue)) {
777 777 updateFixedCellSize();
778 778 }
779 779
780 780 firePropertyChange("cellRenderer", oldValue, cellRenderer);
781 781 }
782 782
783 783
784 784 /**
785 785 * Returns the color used to draw the foreground of selected items.
786 786 * {@code DefaultListCellRenderer} uses this color to draw the foreground
787 787 * of items in the selected state, as do the renderers installed by most
788 788 * {@code ListUI} implementations.
789 789 *
790 790 * @return the color to draw the foreground of selected items
791 791 * @see #setSelectionForeground
792 792 * @see DefaultListCellRenderer
793 793 */
794 794 public Color getSelectionForeground() {
795 795 return selectionForeground;
796 796 }
797 797
798 798
799 799 /**
800 800 * Sets the color used to draw the foreground of selected items, which
801 801 * cell renderers can use to render text and graphics.
802 802 * {@code DefaultListCellRenderer} uses this color to draw the foreground
803 803 * of items in the selected state, as do the renderers installed by most
804 804 * {@code ListUI} implementations.
805 805 * <p>
806 806 * The default value of this property is defined by the look and feel
807 807 * implementation.
808 808 * <p>
809 809 * This is a JavaBeans bound property.
810 810 *
811 811 * @param selectionForeground the {@code Color} to use in the foreground
812 812 * for selected list items
813 813 * @see #getSelectionForeground
814 814 * @see #setSelectionBackground
815 815 * @see #setForeground
816 816 * @see #setBackground
817 817 * @see #setFont
818 818 * @see DefaultListCellRenderer
819 819 * @beaninfo
820 820 * bound: true
821 821 * attribute: visualUpdate true
822 822 * description: The foreground color of selected cells.
823 823 */
824 824 public void setSelectionForeground(Color selectionForeground) {
825 825 Color oldValue = this.selectionForeground;
826 826 this.selectionForeground = selectionForeground;
827 827 firePropertyChange("selectionForeground", oldValue, selectionForeground);
828 828 }
829 829
830 830
831 831 /**
832 832 * Returns the color used to draw the background of selected items.
833 833 * {@code DefaultListCellRenderer} uses this color to draw the background
834 834 * of items in the selected state, as do the renderers installed by most
835 835 * {@code ListUI} implementations.
836 836 *
837 837 * @return the color to draw the background of selected items
838 838 * @see #setSelectionBackground
839 839 * @see DefaultListCellRenderer
840 840 */
841 841 public Color getSelectionBackground() {
842 842 return selectionBackground;
843 843 }
844 844
845 845
846 846 /**
847 847 * Sets the color used to draw the background of selected items, which
848 848 * cell renderers can use fill selected cells.
849 849 * {@code DefaultListCellRenderer} uses this color to fill the background
850 850 * of items in the selected state, as do the renderers installed by most
851 851 * {@code ListUI} implementations.
852 852 * <p>
853 853 * The default value of this property is defined by the look
854 854 * and feel implementation.
855 855 * <p>
856 856 * This is a JavaBeans bound property.
857 857 *
858 858 * @param selectionBackground the {@code Color} to use for the
859 859 * background of selected cells
860 860 * @see #getSelectionBackground
861 861 * @see #setSelectionForeground
862 862 * @see #setForeground
863 863 * @see #setBackground
864 864 * @see #setFont
865 865 * @see DefaultListCellRenderer
866 866 * @beaninfo
867 867 * bound: true
868 868 * attribute: visualUpdate true
869 869 * description: The background color of selected cells.
870 870 */
871 871 public void setSelectionBackground(Color selectionBackground) {
872 872 Color oldValue = this.selectionBackground;
873 873 this.selectionBackground = selectionBackground;
874 874 firePropertyChange("selectionBackground", oldValue, selectionBackground);
875 875 }
876 876
877 877
878 878 /**
879 879 * Returns the value of the {@code visibleRowCount} property. See the
880 880 * documentation for {@link #setVisibleRowCount} for details on how to
881 881 * interpret this value.
882 882 *
883 883 * @return the value of the {@code visibleRowCount} property.
884 884 * @see #setVisibleRowCount
885 885 */
886 886 public int getVisibleRowCount() {
887 887 return visibleRowCount;
888 888 }
889 889
890 890 /**
891 891 * Sets the {@code visibleRowCount} property, which has different meanings
892 892 * depending on the layout orientation: For a {@code VERTICAL} layout
893 893 * orientation, this sets the preferred number of rows to display without
894 894 * requiring scrolling; for other orientations, it affects the wrapping of
895 895 * cells.
896 896 * <p>
897 897 * In {@code VERTICAL} orientation:<br>
898 898 * Setting this property affects the return value of the
899 899 * {@link #getPreferredScrollableViewportSize} method, which is used to
900 900 * calculate the preferred size of an enclosing viewport. See that method's
901 901 * documentation for more details.
902 902 * <p>
903 903 * In {@code HORIZONTAL_WRAP} and {@code VERTICAL_WRAP} orientations:<br>
904 904 * This affects how cells are wrapped. See the documentation of
905 905 * {@link #setLayoutOrientation} for more details.
906 906 * <p>
907 907 * The default value of this property is {@code 8}.
908 908 * <p>
909 909 * Calling this method with a negative value results in the property
910 910 * being set to {@code 0}.
911 911 * <p>
912 912 * This is a JavaBeans bound property.
913 913 *
914 914 * @param visibleRowCount an integer specifying the preferred number of
915 915 * rows to display without requiring scrolling
916 916 * @see #getVisibleRowCount
917 917 * @see #getPreferredScrollableViewportSize
918 918 * @see #setLayoutOrientation
919 919 * @see JComponent#getVisibleRect
920 920 * @see JViewport
921 921 * @beaninfo
922 922 * bound: true
923 923 * attribute: visualUpdate true
924 924 * description: The preferred number of rows to display without
925 925 * requiring scrolling
926 926 */
927 927 public void setVisibleRowCount(int visibleRowCount) {
928 928 int oldValue = this.visibleRowCount;
929 929 this.visibleRowCount = Math.max(0, visibleRowCount);
930 930 firePropertyChange("visibleRowCount", oldValue, visibleRowCount);
931 931 }
932 932
933 933
934 934 /**
935 935 * Returns the layout orientation property for the list: {@code VERTICAL}
936 936 * if the layout is a single column of cells, {@code VERTICAL_WRAP} if the
937 937 * layout is "newspaper style" with the content flowing vertically then
938 938 * horizontally, or {@code HORIZONTAL_WRAP} if the layout is "newspaper
939 939 * style" with the content flowing horizontally then vertically.
940 940 *
941 941 * @return the value of the {@code layoutOrientation} property
942 942 * @see #setLayoutOrientation
943 943 * @since 1.4
944 944 */
945 945 public int getLayoutOrientation() {
946 946 return layoutOrientation;
947 947 }
948 948
949 949
950 950 /**
951 951 * Defines the way list cells are layed out. Consider a {@code JList}
952 952 * with five cells. Cells can be layed out in one of the following ways:
953 953 *
954 954 * <pre>
955 955 * VERTICAL: 0
956 956 * 1
957 957 * 2
958 958 * 3
959 959 * 4
960 960 *
961 961 * HORIZONTAL_WRAP: 0 1 2
962 962 * 3 4
963 963 *
964 964 * VERTICAL_WRAP: 0 3
965 965 * 1 4
966 966 * 2
967 967 * </pre>
968 968 * <p>
969 969 * A description of these layouts follows:
970 970 *
971 971 * <table border="1"
972 972 * summary="Describes layouts VERTICAL, HORIZONTAL_WRAP, and VERTICAL_WRAP">
973 973 * <tr><th><p style="text-align:left">Value</p></th><th><p style="text-align:left">Description</p></th></tr>
974 974 * <tr><td><code>VERTICAL</code>
975 975 * <td>Cells are layed out vertically in a single column.
976 976 * <tr><td><code>HORIZONTAL_WRAP</code>
977 977 * <td>Cells are layed out horizontally, wrapping to a new row as
978 978 * necessary. If the {@code visibleRowCount} property is less than
979 979 * or equal to zero, wrapping is determined by the width of the
980 980 * list; otherwise wrapping is done in such a way as to ensure
981 981 * {@code visibleRowCount} rows in the list.
982 982 * <tr><td><code>VERTICAL_WRAP</code>
983 983 * <td>Cells are layed out vertically, wrapping to a new column as
984 984 * necessary. If the {@code visibleRowCount} property is less than
985 985 * or equal to zero, wrapping is determined by the height of the
986 986 * list; otherwise wrapping is done at {@code visibleRowCount} rows.
987 987 * </table>
988 988 * <p>
989 989 * The default value of this property is <code>VERTICAL</code>.
990 990 *
991 991 * @param layoutOrientation the new layout orientation, one of:
992 992 * {@code VERTICAL}, {@code HORIZONTAL_WRAP} or {@code VERTICAL_WRAP}
993 993 * @see #getLayoutOrientation
994 994 * @see #setVisibleRowCount
995 995 * @see #getScrollableTracksViewportHeight
996 996 * @see #getScrollableTracksViewportWidth
997 997 * @throws IllegalArgumentException if {@code layoutOrientation} isn't one of the
998 998 * allowable values
999 999 * @since 1.4
1000 1000 * @beaninfo
1001 1001 * bound: true
1002 1002 * attribute: visualUpdate true
1003 1003 * description: Defines the way list cells are layed out.
1004 1004 * enum: VERTICAL JList.VERTICAL
1005 1005 * HORIZONTAL_WRAP JList.HORIZONTAL_WRAP
1006 1006 * VERTICAL_WRAP JList.VERTICAL_WRAP
1007 1007 */
1008 1008 public void setLayoutOrientation(int layoutOrientation) {
1009 1009 int oldValue = this.layoutOrientation;
1010 1010 switch (layoutOrientation) {
1011 1011 case VERTICAL:
1012 1012 case VERTICAL_WRAP:
1013 1013 case HORIZONTAL_WRAP:
1014 1014 this.layoutOrientation = layoutOrientation;
1015 1015 firePropertyChange("layoutOrientation", oldValue, layoutOrientation);
1016 1016 break;
1017 1017 default:
1018 1018 throw new IllegalArgumentException("layoutOrientation must be one of: VERTICAL, HORIZONTAL_WRAP or VERTICAL_WRAP");
1019 1019 }
1020 1020 }
1021 1021
1022 1022
1023 1023 /**
1024 1024 * Returns the smallest list index that is currently visible.
1025 1025 * In a left-to-right {@code componentOrientation}, the first visible
1026 1026 * cell is found closest to the list's upper-left corner. In right-to-left
1027 1027 * orientation, it is found closest to the upper-right corner.
1028 1028 * If nothing is visible or the list is empty, {@code -1} is returned.
1029 1029 * Note that the returned cell may only be partially visible.
1030 1030 *
1031 1031 * @return the index of the first visible cell
1032 1032 * @see #getLastVisibleIndex
1033 1033 * @see JComponent#getVisibleRect
1034 1034 */
1035 1035 public int getFirstVisibleIndex() {
1036 1036 Rectangle r = getVisibleRect();
1037 1037 int first;
1038 1038 if (this.getComponentOrientation().isLeftToRight()) {
1039 1039 first = locationToIndex(r.getLocation());
1040 1040 } else {
1041 1041 first = locationToIndex(new Point((r.x + r.width) - 1, r.y));
1042 1042 }
1043 1043 if (first != -1) {
1044 1044 Rectangle bounds = getCellBounds(first, first);
1045 1045 if (bounds != null) {
1046 1046 SwingUtilities.computeIntersection(r.x, r.y, r.width, r.height, bounds);
1047 1047 if (bounds.width == 0 || bounds.height == 0) {
1048 1048 first = -1;
1049 1049 }
1050 1050 }
1051 1051 }
1052 1052 return first;
1053 1053 }
1054 1054
1055 1055
1056 1056 /**
1057 1057 * Returns the largest list index that is currently visible.
1058 1058 * If nothing is visible or the list is empty, {@code -1} is returned.
1059 1059 * Note that the returned cell may only be partially visible.
1060 1060 *
1061 1061 * @return the index of the last visible cell
1062 1062 * @see #getFirstVisibleIndex
1063 1063 * @see JComponent#getVisibleRect
1064 1064 */
1065 1065 public int getLastVisibleIndex() {
1066 1066 boolean leftToRight = this.getComponentOrientation().isLeftToRight();
1067 1067 Rectangle r = getVisibleRect();
1068 1068 Point lastPoint;
1069 1069 if (leftToRight) {
1070 1070 lastPoint = new Point((r.x + r.width) - 1, (r.y + r.height) - 1);
1071 1071 } else {
1072 1072 lastPoint = new Point(r.x, (r.y + r.height) - 1);
1073 1073 }
1074 1074 int location = locationToIndex(lastPoint);
1075 1075
1076 1076 if (location != -1) {
1077 1077 Rectangle bounds = getCellBounds(location, location);
1078 1078
1079 1079 if (bounds != null) {
1080 1080 SwingUtilities.computeIntersection(r.x, r.y, r.width, r.height, bounds);
1081 1081 if (bounds.width == 0 || bounds.height == 0) {
1082 1082 // Try the top left(LTR) or top right(RTL) corner, and
1083 1083 // then go across checking each cell for HORIZONTAL_WRAP.
1084 1084 // Try the lower left corner, and then go across checking
1085 1085 // each cell for other list layout orientation.
1086 1086 boolean isHorizontalWrap =
1087 1087 (getLayoutOrientation() == HORIZONTAL_WRAP);
1088 1088 Point visibleLocation = isHorizontalWrap ?
1089 1089 new Point(lastPoint.x, r.y) :
1090 1090 new Point(r.x, lastPoint.y);
1091 1091 int last;
1092 1092 int visIndex = -1;
1093 1093 int lIndex = location;
1094 1094 location = -1;
1095 1095
1096 1096 do {
1097 1097 last = visIndex;
1098 1098 visIndex = locationToIndex(visibleLocation);
1099 1099
1100 1100 if (visIndex != -1) {
1101 1101 bounds = getCellBounds(visIndex, visIndex);
1102 1102 if (visIndex != lIndex && bounds != null &&
1103 1103 bounds.contains(visibleLocation)) {
1104 1104 location = visIndex;
1105 1105 if (isHorizontalWrap) {
1106 1106 visibleLocation.y = bounds.y + bounds.height;
1107 1107 if (visibleLocation.y >= lastPoint.y) {
1108 1108 // Past visible region, bail.
1109 1109 last = visIndex;
1110 1110 }
1111 1111 }
1112 1112 else {
1113 1113 visibleLocation.x = bounds.x + bounds.width;
1114 1114 if (visibleLocation.x >= lastPoint.x) {
1115 1115 // Past visible region, bail.
1116 1116 last = visIndex;
1117 1117 }
1118 1118 }
1119 1119
1120 1120 }
1121 1121 else {
1122 1122 last = visIndex;
1123 1123 }
1124 1124 }
1125 1125 } while (visIndex != -1 && last != visIndex);
1126 1126 }
1127 1127 }
1128 1128 }
1129 1129 return location;
1130 1130 }
1131 1131
1132 1132
1133 1133 /**
1134 1134 * Scrolls the list within an enclosing viewport to make the specified
1135 1135 * cell completely visible. This calls {@code scrollRectToVisible} with
1136 1136 * the bounds of the specified cell. For this method to work, the
1137 1137 * {@code JList} must be within a <code>JViewport</code>.
1138 1138 * <p>
1139 1139 * If the given index is outside the list's range of cells, this method
1140 1140 * results in nothing.
1141 1141 *
1142 1142 * @param index the index of the cell to make visible
1143 1143 * @see JComponent#scrollRectToVisible
1144 1144 * @see #getVisibleRect
1145 1145 */
1146 1146 public void ensureIndexIsVisible(int index) {
1147 1147 Rectangle cellBounds = getCellBounds(index, index);
1148 1148 if (cellBounds != null) {
1149 1149 scrollRectToVisible(cellBounds);
1150 1150 }
1151 1151 }
1152 1152
1153 1153 /**
1154 1154 * Turns on or off automatic drag handling. In order to enable automatic
1155 1155 * drag handling, this property should be set to {@code true}, and the
1156 1156 * list's {@code TransferHandler} needs to be {@code non-null}.
1157 1157 * The default value of the {@code dragEnabled} property is {@code false}.
1158 1158 * <p>
1159 1159 * The job of honoring this property, and recognizing a user drag gesture,
1160 1160 * lies with the look and feel implementation, and in particular, the list's
1161 1161 * {@code ListUI}. When automatic drag handling is enabled, most look and
1162 1162 * feels (including those that subclass {@code BasicLookAndFeel}) begin a
1163 1163 * drag and drop operation whenever the user presses the mouse button over
1164 1164 * an item and then moves the mouse a few pixels. Setting this property to
1165 1165 * {@code true} can therefore have a subtle effect on how selections behave.
1166 1166 * <p>
1167 1167 * If a look and feel is used that ignores this property, you can still
1168 1168 * begin a drag and drop operation by calling {@code exportAsDrag} on the
1169 1169 * list's {@code TransferHandler}.
1170 1170 *
1171 1171 * @param b whether or not to enable automatic drag handling
1172 1172 * @exception HeadlessException if
1173 1173 * <code>b</code> is <code>true</code> and
1174 1174 * <code>GraphicsEnvironment.isHeadless()</code>
1175 1175 * returns <code>true</code>
1176 1176 * @see java.awt.GraphicsEnvironment#isHeadless
1177 1177 * @see #getDragEnabled
1178 1178 * @see #setTransferHandler
1179 1179 * @see TransferHandler
1180 1180 * @since 1.4
1181 1181 *
1182 1182 * @beaninfo
1183 1183 * description: determines whether automatic drag handling is enabled
1184 1184 * bound: false
1185 1185 */
1186 1186 public void setDragEnabled(boolean b) {
1187 1187 if (b && GraphicsEnvironment.isHeadless()) {
1188 1188 throw new HeadlessException();
1189 1189 }
1190 1190 dragEnabled = b;
1191 1191 }
1192 1192
1193 1193 /**
1194 1194 * Returns whether or not automatic drag handling is enabled.
1195 1195 *
1196 1196 * @return the value of the {@code dragEnabled} property
1197 1197 * @see #setDragEnabled
1198 1198 * @since 1.4
1199 1199 */
1200 1200 public boolean getDragEnabled() {
1201 1201 return dragEnabled;
1202 1202 }
1203 1203
1204 1204 /**
1205 1205 * Sets the drop mode for this component. For backward compatibility,
1206 1206 * the default for this property is <code>DropMode.USE_SELECTION</code>.
1207 1207 * Usage of one of the other modes is recommended, however, for an
1208 1208 * improved user experience. <code>DropMode.ON</code>, for instance,
1209 1209 * offers similar behavior of showing items as selected, but does so without
1210 1210 * affecting the actual selection in the list.
1211 1211 * <p>
1212 1212 * <code>JList</code> supports the following drop modes:
1213 1213 * <ul>
1214 1214 * <li><code>DropMode.USE_SELECTION</code></li>
1215 1215 * <li><code>DropMode.ON</code></li>
1216 1216 * <li><code>DropMode.INSERT</code></li>
1217 1217 * <li><code>DropMode.ON_OR_INSERT</code></li>
1218 1218 * </ul>
1219 1219 * The drop mode is only meaningful if this component has a
1220 1220 * <code>TransferHandler</code> that accepts drops.
1221 1221 *
1222 1222 * @param dropMode the drop mode to use
1223 1223 * @throws IllegalArgumentException if the drop mode is unsupported
1224 1224 * or <code>null</code>
1225 1225 * @see #getDropMode
1226 1226 * @see #getDropLocation
1227 1227 * @see #setTransferHandler
1228 1228 * @see TransferHandler
1229 1229 * @since 1.6
1230 1230 */
1231 1231 public final void setDropMode(DropMode dropMode) {
1232 1232 if (dropMode != null) {
1233 1233 switch (dropMode) {
1234 1234 case USE_SELECTION:
1235 1235 case ON:
1236 1236 case INSERT:
1237 1237 case ON_OR_INSERT:
1238 1238 this.dropMode = dropMode;
1239 1239 return;
1240 1240 }
1241 1241 }
1242 1242
1243 1243 throw new IllegalArgumentException(dropMode + ": Unsupported drop mode for list");
1244 1244 }
1245 1245
1246 1246 /**
1247 1247 * Returns the drop mode for this component.
1248 1248 *
1249 1249 * @return the drop mode for this component
1250 1250 * @see #setDropMode
1251 1251 * @since 1.6
1252 1252 */
1253 1253 public final DropMode getDropMode() {
1254 1254 return dropMode;
1255 1255 }
1256 1256
1257 1257 /**
1258 1258 * Calculates a drop location in this component, representing where a
1259 1259 * drop at the given point should insert data.
1260 1260 *
1261 1261 * @param p the point to calculate a drop location for
1262 1262 * @return the drop location, or <code>null</code>
1263 1263 */
1264 1264 DropLocation dropLocationForPoint(Point p) {
1265 1265 DropLocation location = null;
1266 1266 Rectangle rect = null;
1267 1267
1268 1268 int index = locationToIndex(p);
1269 1269 if (index != -1) {
1270 1270 rect = getCellBounds(index, index);
1271 1271 }
1272 1272
1273 1273 switch(dropMode) {
1274 1274 case USE_SELECTION:
1275 1275 case ON:
1276 1276 location = new DropLocation(p,
1277 1277 (rect != null && rect.contains(p)) ? index : -1,
1278 1278 false);
1279 1279
1280 1280 break;
1281 1281 case INSERT:
1282 1282 if (index == -1) {
1283 1283 location = new DropLocation(p, getModel().getSize(), true);
1284 1284 break;
1285 1285 }
1286 1286
1287 1287 if (layoutOrientation == HORIZONTAL_WRAP) {
1288 1288 boolean ltr = getComponentOrientation().isLeftToRight();
1289 1289
1290 1290 if (SwingUtilities2.liesInHorizontal(rect, p, ltr, false) == TRAILING) {
1291 1291 index++;
1292 1292 // special case for below all cells
1293 1293 } else if (index == getModel().getSize() - 1 && p.y >= rect.y + rect.height) {
1294 1294 index++;
1295 1295 }
1296 1296 } else {
1297 1297 if (SwingUtilities2.liesInVertical(rect, p, false) == TRAILING) {
1298 1298 index++;
1299 1299 }
1300 1300 }
1301 1301
1302 1302 location = new DropLocation(p, index, true);
1303 1303
1304 1304 break;
1305 1305 case ON_OR_INSERT:
1306 1306 if (index == -1) {
1307 1307 location = new DropLocation(p, getModel().getSize(), true);
1308 1308 break;
1309 1309 }
1310 1310
1311 1311 boolean between = false;
1312 1312
1313 1313 if (layoutOrientation == HORIZONTAL_WRAP) {
1314 1314 boolean ltr = getComponentOrientation().isLeftToRight();
1315 1315
1316 1316 Section section = SwingUtilities2.liesInHorizontal(rect, p, ltr, true);
1317 1317 if (section == TRAILING) {
1318 1318 index++;
1319 1319 between = true;
1320 1320 // special case for below all cells
1321 1321 } else if (index == getModel().getSize() - 1 && p.y >= rect.y + rect.height) {
1322 1322 index++;
1323 1323 between = true;
1324 1324 } else if (section == LEADING) {
1325 1325 between = true;
1326 1326 }
1327 1327 } else {
1328 1328 Section section = SwingUtilities2.liesInVertical(rect, p, true);
1329 1329 if (section == LEADING) {
1330 1330 between = true;
1331 1331 } else if (section == TRAILING) {
1332 1332 index++;
1333 1333 between = true;
1334 1334 }
1335 1335 }
1336 1336
1337 1337 location = new DropLocation(p, index, between);
1338 1338
1339 1339 break;
1340 1340 default:
1341 1341 assert false : "Unexpected drop mode";
1342 1342 }
1343 1343
1344 1344 return location;
1345 1345 }
1346 1346
1347 1347 /**
1348 1348 * Called to set or clear the drop location during a DnD operation.
1349 1349 * In some cases, the component may need to use it's internal selection
1350 1350 * temporarily to indicate the drop location. To help facilitate this,
1351 1351 * this method returns and accepts as a parameter a state object.
1352 1352 * This state object can be used to store, and later restore, the selection
1353 1353 * state. Whatever this method returns will be passed back to it in
1354 1354 * future calls, as the state parameter. If it wants the DnD system to
1355 1355 * continue storing the same state, it must pass it back every time.
1356 1356 * Here's how this is used:
1357 1357 * <p>
1358 1358 * Let's say that on the first call to this method the component decides
1359 1359 * to save some state (because it is about to use the selection to show
1360 1360 * a drop index). It can return a state object to the caller encapsulating
1361 1361 * any saved selection state. On a second call, let's say the drop location
1362 1362 * is being changed to something else. The component doesn't need to
1363 1363 * restore anything yet, so it simply passes back the same state object
1364 1364 * to have the DnD system continue storing it. Finally, let's say this
1365 1365 * method is messaged with <code>null</code>. This means DnD
1366 1366 * is finished with this component for now, meaning it should restore
1367 1367 * state. At this point, it can use the state parameter to restore
1368 1368 * said state, and of course return <code>null</code> since there's
1369 1369 * no longer anything to store.
1370 1370 *
1371 1371 * @param location the drop location (as calculated by
1372 1372 * <code>dropLocationForPoint</code>) or <code>null</code>
1373 1373 * if there's no longer a valid drop location
1374 1374 * @param state the state object saved earlier for this component,
1375 1375 * or <code>null</code>
1376 1376 * @param forDrop whether or not the method is being called because an
1377 1377 * actual drop occurred
1378 1378 * @return any saved state for this component, or <code>null</code> if none
1379 1379 */
1380 1380 Object setDropLocation(TransferHandler.DropLocation location,
1381 1381 Object state,
1382 1382 boolean forDrop) {
1383 1383
1384 1384 Object retVal = null;
1385 1385 DropLocation listLocation = (DropLocation)location;
1386 1386
1387 1387 if (dropMode == DropMode.USE_SELECTION) {
1388 1388 if (listLocation == null) {
1389 1389 if (!forDrop && state != null) {
1390 1390 setSelectedIndices(((int[][])state)[0]);
1391 1391
1392 1392 int anchor = ((int[][])state)[1][0];
1393 1393 int lead = ((int[][])state)[1][1];
1394 1394
1395 1395 SwingUtilities2.setLeadAnchorWithoutSelection(
1396 1396 getSelectionModel(), lead, anchor);
1397 1397 }
1398 1398 } else {
1399 1399 if (dropLocation == null) {
1400 1400 int[] inds = getSelectedIndices();
1401 1401 retVal = new int[][] {inds, {getAnchorSelectionIndex(),
1402 1402 getLeadSelectionIndex()}};
1403 1403 } else {
1404 1404 retVal = state;
1405 1405 }
1406 1406
1407 1407 int index = listLocation.getIndex();
1408 1408 if (index == -1) {
1409 1409 clearSelection();
1410 1410 getSelectionModel().setAnchorSelectionIndex(-1);
1411 1411 getSelectionModel().setLeadSelectionIndex(-1);
1412 1412 } else {
1413 1413 setSelectionInterval(index, index);
1414 1414 }
1415 1415 }
1416 1416 }
1417 1417
1418 1418 DropLocation old = dropLocation;
1419 1419 dropLocation = listLocation;
1420 1420 firePropertyChange("dropLocation", old, dropLocation);
1421 1421
1422 1422 return retVal;
1423 1423 }
1424 1424
1425 1425 /**
1426 1426 * Returns the location that this component should visually indicate
1427 1427 * as the drop location during a DnD operation over the component,
1428 1428 * or {@code null} if no location is to currently be shown.
1429 1429 * <p>
1430 1430 * This method is not meant for querying the drop location
1431 1431 * from a {@code TransferHandler}, as the drop location is only
1432 1432 * set after the {@code TransferHandler}'s <code>canImport</code>
1433 1433 * has returned and has allowed for the location to be shown.
1434 1434 * <p>
1435 1435 * When this property changes, a property change event with
1436 1436 * name "dropLocation" is fired by the component.
1437 1437 * <p>
1438 1438 * By default, responsibility for listening for changes to this property
1439 1439 * and indicating the drop location visually lies with the list's
1440 1440 * {@code ListUI}, which may paint it directly and/or install a cell
1441 1441 * renderer to do so. Developers wishing to implement custom drop location
1442 1442 * painting and/or replace the default cell renderer, may need to honor
1443 1443 * this property.
1444 1444 *
1445 1445 * @return the drop location
1446 1446 * @see #setDropMode
1447 1447 * @see TransferHandler#canImport(TransferHandler.TransferSupport)
1448 1448 * @since 1.6
1449 1449 */
1450 1450 public final DropLocation getDropLocation() {
1451 1451 return dropLocation;
1452 1452 }
1453 1453
1454 1454 /**
1455 1455 * Returns the next list element whose {@code toString} value
1456 1456 * starts with the given prefix.
1457 1457 *
1458 1458 * @param prefix the string to test for a match
1459 1459 * @param startIndex the index for starting the search
1460 1460 * @param bias the search direction, either
1461 1461 * Position.Bias.Forward or Position.Bias.Backward.
1462 1462 * @return the index of the next list element that
1463 1463 * starts with the prefix; otherwise {@code -1}
1464 1464 * @exception IllegalArgumentException if prefix is {@code null}
1465 1465 * or startIndex is out of bounds
1466 1466 * @since 1.4
1467 1467 */
1468 1468 public int getNextMatch(String prefix, int startIndex, Position.Bias bias) {
1469 1469 ListModel<E> model = getModel();
1470 1470 int max = model.getSize();
1471 1471 if (prefix == null) {
1472 1472 throw new IllegalArgumentException();
1473 1473 }
1474 1474 if (startIndex < 0 || startIndex >= max) {
1475 1475 throw new IllegalArgumentException();
1476 1476 }
1477 1477 prefix = prefix.toUpperCase();
1478 1478
1479 1479 // start search from the next element after the selected element
1480 1480 int increment = (bias == Position.Bias.Forward) ? 1 : -1;
1481 1481 int index = startIndex;
1482 1482 do {
1483 1483 E element = model.getElementAt(index);
1484 1484
1485 1485 if (element != null) {
1486 1486 String string;
1487 1487
1488 1488 if (element instanceof String) {
1489 1489 string = ((String)element).toUpperCase();
1490 1490 }
1491 1491 else {
1492 1492 string = element.toString();
1493 1493 if (string != null) {
1494 1494 string = string.toUpperCase();
1495 1495 }
1496 1496 }
1497 1497
1498 1498 if (string != null && string.startsWith(prefix)) {
1499 1499 return index;
1500 1500 }
1501 1501 }
1502 1502 index = (index + increment + max) % max;
1503 1503 } while (index != startIndex);
1504 1504 return -1;
1505 1505 }
1506 1506
1507 1507 /**
1508 1508 * Returns the tooltip text to be used for the given event. This overrides
1509 1509 * {@code JComponent}'s {@code getToolTipText} to first check the cell
1510 1510 * renderer component for the cell over which the event occurred, returning
1511 1511 * its tooltip text, if any. This implementation allows you to specify
1512 1512 * tooltip text on the cell level, by using {@code setToolTipText} on your
1513 1513 * cell renderer component.
1514 1514 * <p>
1515 1515 * <strong>Note:</strong> For <code>JList</code> to properly display the
1516 1516 * tooltips of its renderers in this manner, <code>JList</code> must be a
1517 1517 * registered component with the <code>ToolTipManager</code>. This registration
1518 1518 * is done automatically in the constructor. However, if at a later point
1519 1519 * <code>JList</code> is unregistered, by way of a call to
1520 1520 * {@code setToolTipText(null)}, tips from the renderers will no longer display.
1521 1521 *
1522 1522 * @param event the {@code MouseEvent} to fetch the tooltip text for
1523 1523 * @see JComponent#setToolTipText
1524 1524 * @see JComponent#getToolTipText
1525 1525 */
1526 1526 public String getToolTipText(MouseEvent event) {
1527 1527 if(event != null) {
1528 1528 Point p = event.getPoint();
1529 1529 int index = locationToIndex(p);
1530 1530 ListCellRenderer<? super E> r = getCellRenderer();
1531 1531 Rectangle cellBounds;
1532 1532
1533 1533 if (index != -1 && r != null && (cellBounds =
1534 1534 getCellBounds(index, index)) != null &&
1535 1535 cellBounds.contains(p.x, p.y)) {
1536 1536 ListSelectionModel lsm = getSelectionModel();
1537 1537 Component rComponent = r.getListCellRendererComponent(
1538 1538 this, getModel().getElementAt(index), index,
1539 1539 lsm.isSelectedIndex(index),
1540 1540 (hasFocus() && (lsm.getLeadSelectionIndex() ==
1541 1541 index)));
1542 1542
1543 1543 if(rComponent instanceof JComponent) {
1544 1544 MouseEvent newEvent;
1545 1545
1546 1546 p.translate(-cellBounds.x, -cellBounds.y);
1547 1547 newEvent = new MouseEvent(rComponent, event.getID(),
1548 1548 event.getWhen(),
1549 1549 event.getModifiers(),
1550 1550 p.x, p.y,
1551 1551 event.getXOnScreen(),
1552 1552 event.getYOnScreen(),
1553 1553 event.getClickCount(),
1554 1554 event.isPopupTrigger(),
1555 1555 MouseEvent.NOBUTTON);
1556 1556
1557 1557 String tip = ((JComponent)rComponent).getToolTipText(
1558 1558 newEvent);
1559 1559
1560 1560 if (tip != null) {
1561 1561 return tip;
1562 1562 }
1563 1563 }
1564 1564 }
1565 1565 }
1566 1566 return super.getToolTipText();
1567 1567 }
1568 1568
1569 1569 /**
1570 1570 * --- ListUI Delegations ---
1571 1571 */
1572 1572
1573 1573
1574 1574 /**
1575 1575 * Returns the cell index closest to the given location in the list's
1576 1576 * coordinate system. To determine if the cell actually contains the
1577 1577 * specified location, compare the point against the cell's bounds,
1578 1578 * as provided by {@code getCellBounds}. This method returns {@code -1}
1579 1579 * if the model is empty
1580 1580 * <p>
1581 1581 * This is a cover method that delegates to the method of the same name
1582 1582 * in the list's {@code ListUI}. It returns {@code -1} if the list has
1583 1583 * no {@code ListUI}.
1584 1584 *
1585 1585 * @param location the coordinates of the point
1586 1586 * @return the cell index closest to the given location, or {@code -1}
1587 1587 */
1588 1588 public int locationToIndex(Point location) {
1589 1589 ListUI ui = getUI();
1590 1590 return (ui != null) ? ui.locationToIndex(this, location) : -1;
1591 1591 }
1592 1592
1593 1593
1594 1594 /**
1595 1595 * Returns the origin of the specified item in the list's coordinate
1596 1596 * system. This method returns {@code null} if the index isn't valid.
1597 1597 * <p>
1598 1598 * This is a cover method that delegates to the method of the same name
1599 1599 * in the list's {@code ListUI}. It returns {@code null} if the list has
1600 1600 * no {@code ListUI}.
1601 1601 *
1602 1602 * @param index the cell index
1603 1603 * @return the origin of the cell, or {@code null}
1604 1604 */
1605 1605 public Point indexToLocation(int index) {
1606 1606 ListUI ui = getUI();
1607 1607 return (ui != null) ? ui.indexToLocation(this, index) : null;
1608 1608 }
1609 1609
1610 1610
1611 1611 /**
1612 1612 * Returns the bounding rectangle, in the list's coordinate system,
1613 1613 * for the range of cells specified by the two indices.
1614 1614 * These indices can be supplied in any order.
1615 1615 * <p>
1616 1616 * If the smaller index is outside the list's range of cells, this method
1617 1617 * returns {@code null}. If the smaller index is valid, but the larger
1618 1618 * index is outside the list's range, the bounds of just the first index
1619 1619 * is returned. Otherwise, the bounds of the valid range is returned.
1620 1620 * <p>
1621 1621 * This is a cover method that delegates to the method of the same name
1622 1622 * in the list's {@code ListUI}. It returns {@code null} if the list has
1623 1623 * no {@code ListUI}.
1624 1624 *
1625 1625 * @param index0 the first index in the range
1626 1626 * @param index1 the second index in the range
1627 1627 * @return the bounding rectangle for the range of cells, or {@code null}
1628 1628 */
1629 1629 public Rectangle getCellBounds(int index0, int index1) {
1630 1630 ListUI ui = getUI();
1631 1631 return (ui != null) ? ui.getCellBounds(this, index0, index1) : null;
1632 1632 }
1633 1633
1634 1634
1635 1635 /**
1636 1636 * --- ListModel Support ---
1637 1637 */
1638 1638
1639 1639
1640 1640 /**
1641 1641 * Returns the data model that holds the list of items displayed
1642 1642 * by the <code>JList</code> component.
1643 1643 *
1644 1644 * @return the <code>ListModel</code> that provides the displayed
1645 1645 * list of items
1646 1646 * @see #setModel
1647 1647 */
1648 1648 public ListModel<E> getModel() {
1649 1649 return dataModel;
1650 1650 }
1651 1651
1652 1652 /**
1653 1653 * Sets the model that represents the contents or "value" of the
1654 1654 * list, notifies property change listeners, and then clears the
1655 1655 * list's selection.
1656 1656 * <p>
1657 1657 * This is a JavaBeans bound property.
1658 1658 *
1659 1659 * @param model the <code>ListModel</code> that provides the
1660 1660 * list of items for display
1661 1661 * @exception IllegalArgumentException if <code>model</code> is
1662 1662 * <code>null</code>
1663 1663 * @see #getModel
1664 1664 * @see #clearSelection
1665 1665 * @beaninfo
1666 1666 * bound: true
1667 1667 * attribute: visualUpdate true
1668 1668 * description: The object that contains the data to be drawn by this JList.
1669 1669 */
1670 1670 public void setModel(ListModel<E> model) {
1671 1671 if (model == null) {
1672 1672 throw new IllegalArgumentException("model must be non null");
1673 1673 }
1674 1674 ListModel<E> oldValue = dataModel;
1675 1675 dataModel = model;
1676 1676 firePropertyChange("model", oldValue, dataModel);
1677 1677 clearSelection();
1678 1678 }
1679 1679
1680 1680
1681 1681 /**
1682 1682 * Constructs a read-only <code>ListModel</code> from an array of items,
1683 1683 * and calls {@code setModel} with this model.
1684 1684 * <p>
1685 1685 * Attempts to pass a {@code null} value to this method results in
1686 1686 * undefined behavior and, most likely, exceptions. The created model
1687 1687 * references the given array directly. Attempts to modify the array
1688 1688 * after invoking this method results in undefined behavior.
1689 1689 *
1690 1690 * @param listData an array of {@code E} containing the items to
1691 1691 * display in the list
1692 1692 * @see #setModel
1693 1693 */
1694 1694 public void setListData(final E[] listData) {
1695 1695 setModel (
1696 1696 new AbstractListModel<E>() {
1697 1697 public int getSize() { return listData.length; }
1698 1698 public E getElementAt(int i) { return listData[i]; }
1699 1699 }
1700 1700 );
1701 1701 }
1702 1702
1703 1703
1704 1704 /**
1705 1705 * Constructs a read-only <code>ListModel</code> from a <code>Vector</code>
1706 1706 * and calls {@code setModel} with this model.
1707 1707 * <p>
1708 1708 * Attempts to pass a {@code null} value to this method results in
1709 1709 * undefined behavior and, most likely, exceptions. The created model
1710 1710 * references the given {@code Vector} directly. Attempts to modify the
1711 1711 * {@code Vector} after invoking this method results in undefined behavior.
1712 1712 *
1713 1713 * @param listData a <code>Vector</code> containing the items to
1714 1714 * display in the list
1715 1715 * @see #setModel
1716 1716 */
1717 1717 public void setListData(final Vector<? extends E> listData) {
1718 1718 setModel (
1719 1719 new AbstractListModel<E>() {
1720 1720 public int getSize() { return listData.size(); }
1721 1721 public E getElementAt(int i) { return listData.elementAt(i); }
1722 1722 }
1723 1723 );
1724 1724 }
1725 1725
1726 1726
1727 1727 /**
1728 1728 * --- ListSelectionModel delegations and extensions ---
1729 1729 */
1730 1730
1731 1731
1732 1732 /**
1733 1733 * Returns an instance of {@code DefaultListSelectionModel}; called
1734 1734 * during construction to initialize the list's selection model
1735 1735 * property.
1736 1736 *
1737 1737 * @return a {@code DefaultListSelecitonModel}, used to initialize
1738 1738 * the list's selection model property during construction
1739 1739 * @see #setSelectionModel
1740 1740 * @see DefaultListSelectionModel
1741 1741 */
1742 1742 protected ListSelectionModel createSelectionModel() {
1743 1743 return new DefaultListSelectionModel();
1744 1744 }
1745 1745
1746 1746
1747 1747 /**
1748 1748 * Returns the current selection model. The selection model maintains the
1749 1749 * selection state of the list. See the class level documentation for more
1750 1750 * details.
1751 1751 *
1752 1752 * @return the <code>ListSelectionModel</code> that maintains the
1753 1753 * list's selections
1754 1754 *
1755 1755 * @see #setSelectionModel
1756 1756 * @see ListSelectionModel
1757 1757 */
1758 1758 public ListSelectionModel getSelectionModel() {
1759 1759 return selectionModel;
1760 1760 }
1761 1761
1762 1762
1763 1763 /**
1764 1764 * Notifies {@code ListSelectionListener}s added directly to the list
1765 1765 * of selection changes made to the selection model. {@code JList}
1766 1766 * listens for changes made to the selection in the selection model,
1767 1767 * and forwards notification to listeners added to the list directly,
1768 1768 * by calling this method.
1769 1769 * <p>
1770 1770 * This method constructs a {@code ListSelectionEvent} with this list
1771 1771 * as the source, and the specified arguments, and sends it to the
1772 1772 * registered {@code ListSelectionListeners}.
1773 1773 *
1774 1774 * @param firstIndex the first index in the range, {@code <= lastIndex}
1775 1775 * @param lastIndex the last index in the range, {@code >= firstIndex}
1776 1776 * @param isAdjusting whether or not this is one in a series of
1777 1777 * multiple events, where changes are still being made
1778 1778 *
1779 1779 * @see #addListSelectionListener
1780 1780 * @see #removeListSelectionListener
1781 1781 * @see javax.swing.event.ListSelectionEvent
1782 1782 * @see EventListenerList
1783 1783 */
1784 1784 protected void fireSelectionValueChanged(int firstIndex, int lastIndex,
1785 1785 boolean isAdjusting)
1786 1786 {
1787 1787 Object[] listeners = listenerList.getListenerList();
1788 1788 ListSelectionEvent e = null;
1789 1789
1790 1790 for (int i = listeners.length - 2; i >= 0; i -= 2) {
1791 1791 if (listeners[i] == ListSelectionListener.class) {
1792 1792 if (e == null) {
1793 1793 e = new ListSelectionEvent(this, firstIndex, lastIndex,
1794 1794 isAdjusting);
1795 1795 }
1796 1796 ((ListSelectionListener)listeners[i+1]).valueChanged(e);
1797 1797 }
1798 1798 }
1799 1799 }
1800 1800
1801 1801
1802 1802 /* A ListSelectionListener that forwards ListSelectionEvents from
1803 1803 * the selectionModel to the JList ListSelectionListeners. The
1804 1804 * forwarded events only differ from the originals in that their
1805 1805 * source is the JList instead of the selectionModel itself.
1806 1806 */
1807 1807 private class ListSelectionHandler implements ListSelectionListener, Serializable
1808 1808 {
1809 1809 public void valueChanged(ListSelectionEvent e) {
1810 1810 fireSelectionValueChanged(e.getFirstIndex(),
1811 1811 e.getLastIndex(),
1812 1812 e.getValueIsAdjusting());
1813 1813 }
1814 1814 }
1815 1815
1816 1816
1817 1817 /**
1818 1818 * Adds a listener to the list, to be notified each time a change to the
1819 1819 * selection occurs; the preferred way of listening for selection state
1820 1820 * changes. {@code JList} takes care of listening for selection state
1821 1821 * changes in the selection model, and notifies the given listener of
1822 1822 * each change. {@code ListSelectionEvent}s sent to the listener have a
1823 1823 * {@code source} property set to this list.
1824 1824 *
1825 1825 * @param listener the {@code ListSelectionListener} to add
1826 1826 * @see #getSelectionModel
1827 1827 * @see #getListSelectionListeners
1828 1828 */
1829 1829 public void addListSelectionListener(ListSelectionListener listener)
1830 1830 {
1831 1831 if (selectionListener == null) {
1832 1832 selectionListener = new ListSelectionHandler();
1833 1833 getSelectionModel().addListSelectionListener(selectionListener);
1834 1834 }
1835 1835
1836 1836 listenerList.add(ListSelectionListener.class, listener);
1837 1837 }
1838 1838
1839 1839
1840 1840 /**
1841 1841 * Removes a selection listener from the list.
1842 1842 *
1843 1843 * @param listener the {@code ListSelectionListener} to remove
1844 1844 * @see #addListSelectionListener
1845 1845 * @see #getSelectionModel
1846 1846 */
1847 1847 public void removeListSelectionListener(ListSelectionListener listener) {
1848 1848 listenerList.remove(ListSelectionListener.class, listener);
1849 1849 }
1850 1850
1851 1851
1852 1852 /**
1853 1853 * Returns an array of all the {@code ListSelectionListener}s added
1854 1854 * to this {@code JList} by way of {@code addListSelectionListener}.
1855 1855 *
1856 1856 * @return all of the {@code ListSelectionListener}s on this list, or
1857 1857 * an empty array if no listeners have been added
1858 1858 * @see #addListSelectionListener
1859 1859 * @since 1.4
1860 1860 */
1861 1861 public ListSelectionListener[] getListSelectionListeners() {
1862 1862 return listenerList.getListeners(ListSelectionListener.class);
1863 1863 }
1864 1864
1865 1865
1866 1866 /**
1867 1867 * Sets the <code>selectionModel</code> for the list to a
1868 1868 * non-<code>null</code> <code>ListSelectionModel</code>
1869 1869 * implementation. The selection model handles the task of making single
1870 1870 * selections, selections of contiguous ranges, and non-contiguous
1871 1871 * selections.
1872 1872 * <p>
1873 1873 * This is a JavaBeans bound property.
1874 1874 *
1875 1875 * @param selectionModel the <code>ListSelectionModel</code> that
1876 1876 * implements the selections
1877 1877 * @exception IllegalArgumentException if <code>selectionModel</code>
1878 1878 * is <code>null</code>
1879 1879 * @see #getSelectionModel
1880 1880 * @beaninfo
1881 1881 * bound: true
1882 1882 * description: The selection model, recording which cells are selected.
1883 1883 */
1884 1884 public void setSelectionModel(ListSelectionModel selectionModel) {
1885 1885 if (selectionModel == null) {
1886 1886 throw new IllegalArgumentException("selectionModel must be non null");
1887 1887 }
1888 1888
1889 1889 /* Remove the forwarding ListSelectionListener from the old
1890 1890 * selectionModel, and add it to the new one, if necessary.
1891 1891 */
1892 1892 if (selectionListener != null) {
1893 1893 this.selectionModel.removeListSelectionListener(selectionListener);
1894 1894 selectionModel.addListSelectionListener(selectionListener);
1895 1895 }
1896 1896
1897 1897 ListSelectionModel oldValue = this.selectionModel;
1898 1898 this.selectionModel = selectionModel;
1899 1899 firePropertyChange("selectionModel", oldValue, selectionModel);
1900 1900 }
1901 1901
1902 1902
1903 1903 /**
1904 1904 * Sets the selection mode for the list. This is a cover method that sets
1905 1905 * the selection mode directly on the selection model.
1906 1906 * <p>
1907 1907 * The following list describes the accepted selection modes:
1908 1908 * <ul>
1909 1909 * <li>{@code ListSelectionModel.SINGLE_SELECTION} -
1910 1910 * Only one list index can be selected at a time. In this mode,
1911 1911 * {@code setSelectionInterval} and {@code addSelectionInterval} are
1912 1912 * equivalent, both replacing the current selection with the index
1913 1913 * represented by the second argument (the "lead").
1914 1914 * <li>{@code ListSelectionModel.SINGLE_INTERVAL_SELECTION} -
1915 1915 * Only one contiguous interval can be selected at a time.
1916 1916 * In this mode, {@code addSelectionInterval} behaves like
1917 1917 * {@code setSelectionInterval} (replacing the current selection},
1918 1918 * unless the given interval is immediately adjacent to or overlaps
1919 1919 * the existing selection, and can be used to grow the selection.
1920 1920 * <li>{@code ListSelectionModel.MULTIPLE_INTERVAL_SELECTION} -
1921 1921 * In this mode, there's no restriction on what can be selected.
1922 1922 * This mode is the default.
1923 1923 * </ul>
1924 1924 *
1925 1925 * @param selectionMode the selection mode
1926 1926 * @see #getSelectionMode
1927 1927 * @throws IllegalArgumentException if the selection mode isn't
1928 1928 * one of those allowed
1929 1929 * @beaninfo
1930 1930 * description: The selection mode.
1931 1931 * enum: SINGLE_SELECTION ListSelectionModel.SINGLE_SELECTION
1932 1932 * SINGLE_INTERVAL_SELECTION ListSelectionModel.SINGLE_INTERVAL_SELECTION
1933 1933 * MULTIPLE_INTERVAL_SELECTION ListSelectionModel.MULTIPLE_INTERVAL_SELECTION
1934 1934 */
1935 1935 public void setSelectionMode(int selectionMode) {
1936 1936 getSelectionModel().setSelectionMode(selectionMode);
1937 1937 }
1938 1938
1939 1939 /**
1940 1940 * Returns the current selection mode for the list. This is a cover
1941 1941 * method that delegates to the method of the same name on the
1942 1942 * list's selection model.
1943 1943 *
1944 1944 * @return the current selection mode
1945 1945 * @see #setSelectionMode
1946 1946 */
1947 1947 public int getSelectionMode() {
1948 1948 return getSelectionModel().getSelectionMode();
1949 1949 }
1950 1950
1951 1951
1952 1952 /**
1953 1953 * Returns the anchor selection index. This is a cover method that
1954 1954 * delegates to the method of the same name on the list's selection model.
1955 1955 *
1956 1956 * @return the anchor selection index
1957 1957 * @see ListSelectionModel#getAnchorSelectionIndex
1958 1958 */
1959 1959 public int getAnchorSelectionIndex() {
1960 1960 return getSelectionModel().getAnchorSelectionIndex();
1961 1961 }
1962 1962
1963 1963
1964 1964 /**
1965 1965 * Returns the lead selection index. This is a cover method that
1966 1966 * delegates to the method of the same name on the list's selection model.
1967 1967 *
1968 1968 * @return the lead selection index
1969 1969 * @see ListSelectionModel#getLeadSelectionIndex
1970 1970 * @beaninfo
1971 1971 * description: The lead selection index.
1972 1972 */
1973 1973 public int getLeadSelectionIndex() {
1974 1974 return getSelectionModel().getLeadSelectionIndex();
1975 1975 }
1976 1976
1977 1977
1978 1978 /**
1979 1979 * Returns the smallest selected cell index, or {@code -1} if the selection
1980 1980 * is empty. This is a cover method that delegates to the method of the same
1981 1981 * name on the list's selection model.
1982 1982 *
1983 1983 * @return the smallest selected cell index, or {@code -1}
1984 1984 * @see ListSelectionModel#getMinSelectionIndex
1985 1985 */
1986 1986 public int getMinSelectionIndex() {
1987 1987 return getSelectionModel().getMinSelectionIndex();
1988 1988 }
1989 1989
1990 1990
1991 1991 /**
1992 1992 * Returns the largest selected cell index, or {@code -1} if the selection
1993 1993 * is empty. This is a cover method that delegates to the method of the same
1994 1994 * name on the list's selection model.
1995 1995 *
1996 1996 * @return the largest selected cell index
1997 1997 * @see ListSelectionModel#getMaxSelectionIndex
1998 1998 */
1999 1999 public int getMaxSelectionIndex() {
2000 2000 return getSelectionModel().getMaxSelectionIndex();
2001 2001 }
2002 2002
2003 2003
2004 2004 /**
2005 2005 * Returns {@code true} if the specified index is selected,
2006 2006 * else {@code false}. This is a cover method that delegates to the method
2007 2007 * of the same name on the list's selection model.
2008 2008 *
2009 2009 * @param index index to be queried for selection state
2010 2010 * @return {@code true} if the specified index is selected,
2011 2011 * else {@code false}
2012 2012 * @see ListSelectionModel#isSelectedIndex
2013 2013 * @see #setSelectedIndex
2014 2014 */
2015 2015 public boolean isSelectedIndex(int index) {
2016 2016 return getSelectionModel().isSelectedIndex(index);
2017 2017 }
2018 2018
2019 2019
2020 2020 /**
2021 2021 * Returns {@code true} if nothing is selected, else {@code false}.
2022 2022 * This is a cover method that delegates to the method of the same
2023 2023 * name on the list's selection model.
2024 2024 *
2025 2025 * @return {@code true} if nothing is selected, else {@code false}
2026 2026 * @see ListSelectionModel#isSelectionEmpty
2027 2027 * @see #clearSelection
2028 2028 */
2029 2029 public boolean isSelectionEmpty() {
2030 2030 return getSelectionModel().isSelectionEmpty();
2031 2031 }
2032 2032
2033 2033
2034 2034 /**
2035 2035 * Clears the selection; after calling this method, {@code isSelectionEmpty}
2036 2036 * will return {@code true}. This is a cover method that delegates to the
2037 2037 * method of the same name on the list's selection model.
2038 2038 *
2039 2039 * @see ListSelectionModel#clearSelection
2040 2040 * @see #isSelectionEmpty
2041 2041 */
2042 2042 public void clearSelection() {
2043 2043 getSelectionModel().clearSelection();
2044 2044 }
2045 2045
2046 2046
2047 2047 /**
2048 2048 * Selects the specified interval. Both {@code anchor} and {@code lead}
2049 2049 * indices are included. {@code anchor} doesn't have to be less than or
2050 2050 * equal to {@code lead}. This is a cover method that delegates to the
2051 2051 * method of the same name on the list's selection model.
2052 2052 * <p>
2053 2053 * Refer to the documentation of the selection model class being used
2054 2054 * for details on how values less than {@code 0} are handled.
2055 2055 *
2056 2056 * @param anchor the first index to select
2057 2057 * @param lead the last index to select
2058 2058 * @see ListSelectionModel#setSelectionInterval
2059 2059 * @see DefaultListSelectionModel#setSelectionInterval
2060 2060 * @see #createSelectionModel
2061 2061 * @see #addSelectionInterval
2062 2062 * @see #removeSelectionInterval
2063 2063 */
2064 2064 public void setSelectionInterval(int anchor, int lead) {
2065 2065 getSelectionModel().setSelectionInterval(anchor, lead);
2066 2066 }
2067 2067
2068 2068
2069 2069 /**
2070 2070 * Sets the selection to be the union of the specified interval with current
2071 2071 * selection. Both the {@code anchor} and {@code lead} indices are
2072 2072 * included. {@code anchor} doesn't have to be less than or
2073 2073 * equal to {@code lead}. This is a cover method that delegates to the
2074 2074 * method of the same name on the list's selection model.
2075 2075 * <p>
2076 2076 * Refer to the documentation of the selection model class being used
2077 2077 * for details on how values less than {@code 0} are handled.
2078 2078 *
2079 2079 * @param anchor the first index to add to the selection
2080 2080 * @param lead the last index to add to the selection
2081 2081 * @see ListSelectionModel#addSelectionInterval
2082 2082 * @see DefaultListSelectionModel#addSelectionInterval
2083 2083 * @see #createSelectionModel
2084 2084 * @see #setSelectionInterval
2085 2085 * @see #removeSelectionInterval
2086 2086 */
2087 2087 public void addSelectionInterval(int anchor, int lead) {
2088 2088 getSelectionModel().addSelectionInterval(anchor, lead);
2089 2089 }
2090 2090
2091 2091
2092 2092 /**
2093 2093 * Sets the selection to be the set difference of the specified interval
2094 2094 * and the current selection. Both the {@code index0} and {@code index1}
2095 2095 * indices are removed. {@code index0} doesn't have to be less than or
2096 2096 * equal to {@code index1}. This is a cover method that delegates to the
2097 2097 * method of the same name on the list's selection model.
2098 2098 * <p>
2099 2099 * Refer to the documentation of the selection model class being used
2100 2100 * for details on how values less than {@code 0} are handled.
2101 2101 *
2102 2102 * @param index0 the first index to remove from the selection
2103 2103 * @param index1 the last index to remove from the selection
2104 2104 * @see ListSelectionModel#removeSelectionInterval
2105 2105 * @see DefaultListSelectionModel#removeSelectionInterval
2106 2106 * @see #createSelectionModel
2107 2107 * @see #setSelectionInterval
2108 2108 * @see #addSelectionInterval
2109 2109 */
2110 2110 public void removeSelectionInterval(int index0, int index1) {
2111 2111 getSelectionModel().removeSelectionInterval(index0, index1);
2112 2112 }
2113 2113
2114 2114
2115 2115 /**
2116 2116 * Sets the selection model's {@code valueIsAdjusting} property. When
2117 2117 * {@code true}, upcoming changes to selection should be considered part
2118 2118 * of a single change. This property is used internally and developers
2119 2119 * typically need not call this method. For example, when the model is being
2120 2120 * updated in response to a user drag, the value of the property is set
2121 2121 * to {@code true} when the drag is initiated and set to {@code false}
2122 2122 * when the drag is finished. This allows listeners to update only
2123 2123 * when a change has been finalized, rather than handling all of the
2124 2124 * intermediate values.
2125 2125 * <p>
2126 2126 * You may want to use this directly if making a series of changes
2127 2127 * that should be considered part of a single change.
2128 2128 * <p>
2129 2129 * This is a cover method that delegates to the method of the same name on
2130 2130 * the list's selection model. See the documentation for
2131 2131 * {@link javax.swing.ListSelectionModel#setValueIsAdjusting} for
2132 2132 * more details.
2133 2133 *
2134 2134 * @param b the new value for the property
2135 2135 * @see ListSelectionModel#setValueIsAdjusting
2136 2136 * @see javax.swing.event.ListSelectionEvent#getValueIsAdjusting
2137 2137 * @see #getValueIsAdjusting
2138 2138 */
2139 2139 public void setValueIsAdjusting(boolean b) {
2140 2140 getSelectionModel().setValueIsAdjusting(b);
2141 2141 }
2142 2142
2143 2143
2144 2144 /**
2145 2145 * Returns the value of the selection model's {@code isAdjusting} property.
2146 2146 * <p>
2147 2147 * This is a cover method that delegates to the method of the same name on
2148 2148 * the list's selection model.
2149 2149 *
2150 2150 * @return the value of the selection model's {@code isAdjusting} property.
2151 2151 *
2152 2152 * @see #setValueIsAdjusting
2153 2153 * @see ListSelectionModel#getValueIsAdjusting
2154 2154 */
2155 2155 public boolean getValueIsAdjusting() {
2156 2156 return getSelectionModel().getValueIsAdjusting();
2157 2157 }
2158 2158
2159 2159
2160 2160 /**
2161 2161 * Returns an array of all of the selected indices, in increasing
2162 2162 * order.
2163 2163 *
2164 2164 * @return all of the selected indices, in increasing order,
2165 2165 * or an empty array if nothing is selected
2166 2166 * @see #removeSelectionInterval
2167 2167 * @see #addListSelectionListener
2168 2168 */
2169 2169 @Transient
2170 2170 public int[] getSelectedIndices() {
2171 2171 ListSelectionModel sm = getSelectionModel();
2172 2172 int iMin = sm.getMinSelectionIndex();
2173 2173 int iMax = sm.getMaxSelectionIndex();
2174 2174
2175 2175 if ((iMin < 0) || (iMax < 0)) {
2176 2176 return new int[0];
2177 2177 }
2178 2178
2179 2179 int[] rvTmp = new int[1+ (iMax - iMin)];
2180 2180 int n = 0;
2181 2181 for(int i = iMin; i <= iMax; i++) {
2182 2182 if (sm.isSelectedIndex(i)) {
2183 2183 rvTmp[n++] = i;
2184 2184 }
2185 2185 }
2186 2186 int[] rv = new int[n];
2187 2187 System.arraycopy(rvTmp, 0, rv, 0, n);
2188 2188 return rv;
2189 2189 }
2190 2190
2191 2191
2192 2192 /**
2193 2193 * Selects a single cell. Does nothing if the given index is greater
2194 2194 * than or equal to the model size. This is a convenience method that uses
2195 2195 * {@code setSelectionInterval} on the selection model. Refer to the
2196 2196 * documentation for the selection model class being used for details on
2197 2197 * how values less than {@code 0} are handled.
2198 2198 *
2199 2199 * @param index the index of the cell to select
2200 2200 * @see ListSelectionModel#setSelectionInterval
2201 2201 * @see #isSelectedIndex
2202 2202 * @see #addListSelectionListener
2203 2203 * @beaninfo
2204 2204 * description: The index of the selected cell.
2205 2205 */
2206 2206 public void setSelectedIndex(int index) {
2207 2207 if (index >= getModel().getSize()) {
2208 2208 return;
2209 2209 }
2210 2210 getSelectionModel().setSelectionInterval(index, index);
2211 2211 }
2212 2212
2213 2213
2214 2214 /**
2215 2215 * Changes the selection to be the set of indices specified by the given
2216 2216 * array. Indices greater than or equal to the model size are ignored.
2217 2217 * This is a convenience method that clears the selection and then uses
2218 2218 * {@code addSelectionInterval} on the selection model to add the indices.
2219 2219 * Refer to the documentation of the selection model class being used for
2220 2220 * details on how values less than {@code 0} are handled.
2221 2221 *
2222 2222 * @param indices an array of the indices of the cells to select,
2223 2223 * {@code non-null}
2224 2224 * @see ListSelectionModel#addSelectionInterval
2225 2225 * @see #isSelectedIndex
2226 2226 * @see #addListSelectionListener
2227 2227 * @throws NullPointerException if the given array is {@code null}
2228 2228 */
2229 2229 public void setSelectedIndices(int[] indices) {
2230 2230 ListSelectionModel sm = getSelectionModel();
2231 2231 sm.clearSelection();
2232 2232 int size = getModel().getSize();
2233 2233 for (int i : indices) {
2234 2234 if (i < size) {
2235 2235 sm.addSelectionInterval(i, i);
2236 2236 }
2237 2237 }
2238 2238 }
2239 2239
2240 2240
2241 2241 /**
2242 2242 * Returns an array of all the selected values, in increasing order based
2243 2243 * on their indices in the list.
2244 2244 *
2245 2245 * @return the selected values, or an empty array if nothing is selected
2246 2246 * @see #isSelectedIndex
2247 2247 * @see #getModel
2248 2248 * @see #addListSelectionListener
2249 2249 *
2250 2250 * @deprecated As of JDK 1.7, replaced by {@link #getSelectedValuesList()}
2251 2251 */
2252 2252 @Deprecated
2253 2253 public Object[] getSelectedValues() {
2254 2254 ListSelectionModel sm = getSelectionModel();
2255 2255 ListModel<E> dm = getModel();
2256 2256
2257 2257 int iMin = sm.getMinSelectionIndex();
2258 2258 int iMax = sm.getMaxSelectionIndex();
2259 2259
2260 2260 if ((iMin < 0) || (iMax < 0)) {
2261 2261 return new Object[0];
2262 2262 }
2263 2263
2264 2264 Object[] rvTmp = new Object[1+ (iMax - iMin)];
2265 2265 int n = 0;
2266 2266 for(int i = iMin; i <= iMax; i++) {
2267 2267 if (sm.isSelectedIndex(i)) {
2268 2268 rvTmp[n++] = dm.getElementAt(i);
2269 2269 }
2270 2270 }
2271 2271 Object[] rv = new Object[n];
2272 2272 System.arraycopy(rvTmp, 0, rv, 0, n);
2273 2273 return rv;
2274 2274 }
2275 2275
2276 2276 /**
2277 2277 * Returns a list of all the selected items, in increasing order based
2278 2278 * on their indices in the list.
2279 2279 *
2280 2280 * @return the selected items, or an empty list if nothing is selected
2281 2281 * @see #isSelectedIndex
2282 2282 * @see #getModel
2283 2283 * @see #addListSelectionListener
2284 2284 *
2285 2285 * @since 1.7
2286 2286 */
2287 2287 public List<E> getSelectedValuesList() {
2288 2288 ListSelectionModel sm = getSelectionModel();
2289 2289 ListModel<E> dm = getModel();
2290 2290
2291 2291 int iMin = sm.getMinSelectionIndex();
2292 2292 int iMax = sm.getMaxSelectionIndex();
2293 2293
2294 2294 if ((iMin < 0) || (iMax < 0)) {
2295 2295 return Collections.emptyList();
2296 2296 }
2297 2297
2298 2298 List<E> selectedItems = new ArrayList<E>();
2299 2299 for(int i = iMin; i <= iMax; i++) {
2300 2300 if (sm.isSelectedIndex(i)) {
2301 2301 selectedItems.add(dm.getElementAt(i));
2302 2302 }
2303 2303 }
2304 2304 return selectedItems;
2305 2305 }
2306 2306
2307 2307
2308 2308 /**
2309 2309 * Returns the smallest selected cell index; <i>the selection</i> when only
2310 2310 * a single item is selected in the list. When multiple items are selected,
2311 2311 * it is simply the smallest selected index. Returns {@code -1} if there is
2312 2312 * no selection.
2313 2313 * <p>
2314 2314 * This method is a cover that delegates to {@code getMinSelectionIndex}.
2315 2315 *
2316 2316 * @return the smallest selected cell index
2317 2317 * @see #getMinSelectionIndex
2318 2318 * @see #addListSelectionListener
2319 2319 */
2320 2320 public int getSelectedIndex() {
2321 2321 return getMinSelectionIndex();
2322 2322 }
2323 2323
2324 2324
2325 2325 /**
2326 2326 * Returns the value for the smallest selected cell index;
2327 2327 * <i>the selected value</i> when only a single item is selected in the
2328 2328 * list. When multiple items are selected, it is simply the value for the
2329 2329 * smallest selected index. Returns {@code null} if there is no selection.
2330 2330 * <p>
2331 2331 * This is a convenience method that simply returns the model value for
2332 2332 * {@code getMinSelectionIndex}.
2333 2333 *
2334 2334 * @return the first selected value
2335 2335 * @see #getMinSelectionIndex
2336 2336 * @see #getModel
2337 2337 * @see #addListSelectionListener
2338 2338 */
2339 2339 public E getSelectedValue() {
2340 2340 int i = getMinSelectionIndex();
2341 2341 return (i == -1) ? null : getModel().getElementAt(i);
2342 2342 }
2343 2343
2344 2344
2345 2345 /**
2346 2346 * Selects the specified object from the list.
2347 2347 *
2348 2348 * @param anObject the object to select
2349 2349 * @param shouldScroll {@code true} if the list should scroll to display
2350 2350 * the selected object, if one exists; otherwise {@code false}
2351 2351 */
2352 2352 public void setSelectedValue(Object anObject,boolean shouldScroll) {
2353 2353 if(anObject == null)
2354 2354 setSelectedIndex(-1);
2355 2355 else if(!anObject.equals(getSelectedValue())) {
2356 2356 int i,c;
2357 2357 ListModel<E> dm = getModel();
2358 2358 for(i=0,c=dm.getSize();i<c;i++)
2359 2359 if(anObject.equals(dm.getElementAt(i))){
2360 2360 setSelectedIndex(i);
2361 2361 if(shouldScroll)
2362 2362 ensureIndexIsVisible(i);
2363 2363 repaint(); /** FIX-ME setSelectedIndex does not redraw all the time with the basic l&f**/
2364 2364 return;
2365 2365 }
2366 2366 setSelectedIndex(-1);
2367 2367 }
2368 2368 repaint(); /** FIX-ME setSelectedIndex does not redraw all the time with the basic l&f**/
2369 2369 }
2370 2370
2371 2371
2372 2372
2373 2373 /**
2374 2374 * --- The Scrollable Implementation ---
2375 2375 */
2376 2376
2377 2377 private void checkScrollableParameters(Rectangle visibleRect, int orientation) {
2378 2378 if (visibleRect == null) {
2379 2379 throw new IllegalArgumentException("visibleRect must be non-null");
2380 2380 }
2381 2381 switch (orientation) {
2382 2382 case SwingConstants.VERTICAL:
2383 2383 case SwingConstants.HORIZONTAL:
2384 2384 break;
2385 2385 default:
2386 2386 throw new IllegalArgumentException("orientation must be one of: VERTICAL, HORIZONTAL");
2387 2387 }
2388 2388 }
2389 2389
2390 2390
2391 2391 /**
2392 2392 * Computes the size of viewport needed to display {@code visibleRowCount}
2393 2393 * rows. The value returned by this method depends on the layout
2394 2394 * orientation:
2395 2395 * <p>
2396 2396 * <b>{@code VERTICAL}:</b>
2397 2397 * <br>
2398 2398 * This is trivial if both {@code fixedCellWidth} and {@code fixedCellHeight}
2399 2399 * have been set (either explicitly or by specifying a prototype cell value).
2400 2400 * The width is simply the {@code fixedCellWidth} plus the list's horizontal
2401 2401 * insets. The height is the {@code fixedCellHeight} multiplied by the
2402 2402 * {@code visibleRowCount}, plus the list's vertical insets.
2403 2403 * <p>
2404 2404 * If either {@code fixedCellWidth} or {@code fixedCellHeight} haven't been
2405 2405 * specified, heuristics are used. If the model is empty, the width is
2406 2406 * the {@code fixedCellWidth}, if greater than {@code 0}, or a hard-coded
2407 2407 * value of {@code 256}. The height is the {@code fixedCellHeight} multiplied
2408 2408 * by {@code visibleRowCount}, if {@code fixedCellHeight} is greater than
2409 2409 * {@code 0}, otherwise it is a hard-coded value of {@code 16} multiplied by
2410 2410 * {@code visibleRowCount}.
2411 2411 * <p>
2412 2412 * If the model isn't empty, the width is the preferred size's width,
2413 2413 * typically the width of the widest list element. The height is the
2414 2414 * {@code fixedCellHeight} multiplied by the {@code visibleRowCount},
2415 2415 * plus the list's vertical insets.
2416 2416 * <p>
2417 2417 * <b>{@code VERTICAL_WRAP} or {@code HORIZONTAL_WRAP}:</b>
2418 2418 * <br>
2419 2419 * This method simply returns the value from {@code getPreferredSize}.
2420 2420 * The list's {@code ListUI} is expected to override {@code getPreferredSize}
2421 2421 * to return an appropriate value.
2422 2422 *
2423 2423 * @return a dimension containing the size of the viewport needed
2424 2424 * to display {@code visibleRowCount} rows
2425 2425 * @see #getPreferredScrollableViewportSize
2426 2426 * @see #setPrototypeCellValue
2427 2427 */
2428 2428 public Dimension getPreferredScrollableViewportSize()
2429 2429 {
2430 2430 if (getLayoutOrientation() != VERTICAL) {
2431 2431 return getPreferredSize();
2432 2432 }
2433 2433 Insets insets = getInsets();
2434 2434 int dx = insets.left + insets.right;
2435 2435 int dy = insets.top + insets.bottom;
2436 2436
2437 2437 int visibleRowCount = getVisibleRowCount();
2438 2438 int fixedCellWidth = getFixedCellWidth();
2439 2439 int fixedCellHeight = getFixedCellHeight();
2440 2440
2441 2441 if ((fixedCellWidth > 0) && (fixedCellHeight > 0)) {
2442 2442 int width = fixedCellWidth + dx;
2443 2443 int height = (visibleRowCount * fixedCellHeight) + dy;
2444 2444 return new Dimension(width, height);
2445 2445 }
2446 2446 else if (getModel().getSize() > 0) {
2447 2447 int width = getPreferredSize().width;
2448 2448 int height;
2449 2449 Rectangle r = getCellBounds(0, 0);
2450 2450 if (r != null) {
2451 2451 height = (visibleRowCount * r.height) + dy;
2452 2452 }
2453 2453 else {
2454 2454 // Will only happen if UI null, shouldn't matter what we return
2455 2455 height = 1;
2456 2456 }
2457 2457 return new Dimension(width, height);
2458 2458 }
2459 2459 else {
2460 2460 fixedCellWidth = (fixedCellWidth > 0) ? fixedCellWidth : 256;
2461 2461 fixedCellHeight = (fixedCellHeight > 0) ? fixedCellHeight : 16;
2462 2462 return new Dimension(fixedCellWidth, fixedCellHeight * visibleRowCount);
2463 2463 }
2464 2464 }
2465 2465
2466 2466
2467 2467 /**
2468 2468 * Returns the distance to scroll to expose the next or previous
2469 2469 * row (for vertical scrolling) or column (for horizontal scrolling).
2470 2470 * <p>
2471 2471 * For horizontal scrolling, if the layout orientation is {@code VERTICAL},
2472 2472 * then the list's font size is returned (or {@code 1} if the font is
2473 2473 * {@code null}).
2474 2474 *
2475 2475 * @param visibleRect the view area visible within the viewport
2476 2476 * @param orientation {@code SwingConstants.HORIZONTAL} or
2477 2477 * {@code SwingConstants.VERTICAL}
2478 2478 * @param direction less or equal to zero to scroll up/back,
2479 2479 * greater than zero for down/forward
2480 2480 * @return the "unit" increment for scrolling in the specified direction;
2481 2481 * always positive
2482 2482 * @see #getScrollableBlockIncrement
2483 2483 * @see Scrollable#getScrollableUnitIncrement
2484 2484 * @throws IllegalArgumentException if {@code visibleRect} is {@code null}, or
2485 2485 * {@code orientation} isn't one of {@code SwingConstants.VERTICAL} or
2486 2486 * {@code SwingConstants.HORIZONTAL}
2487 2487 */
2488 2488 public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction)
2489 2489 {
2490 2490 checkScrollableParameters(visibleRect, orientation);
2491 2491
2492 2492 if (orientation == SwingConstants.VERTICAL) {
2493 2493 int row = locationToIndex(visibleRect.getLocation());
2494 2494
2495 2495 if (row == -1) {
2496 2496 return 0;
2497 2497 }
2498 2498 else {
2499 2499 /* Scroll Down */
2500 2500 if (direction > 0) {
2501 2501 Rectangle r = getCellBounds(row, row);
2502 2502 return (r == null) ? 0 : r.height - (visibleRect.y - r.y);
2503 2503 }
2504 2504 /* Scroll Up */
2505 2505 else {
2506 2506 Rectangle r = getCellBounds(row, row);
2507 2507
2508 2508 /* The first row is completely visible and it's row 0.
2509 2509 * We're done.
2510 2510 */
2511 2511 if ((r.y == visibleRect.y) && (row == 0)) {
2512 2512 return 0;
2513 2513 }
2514 2514 /* The first row is completely visible, return the
2515 2515 * height of the previous row or 0 if the first row
2516 2516 * is the top row of the list.
2517 2517 */
2518 2518 else if (r.y == visibleRect.y) {
2519 2519 Point loc = r.getLocation();
2520 2520 loc.y--;
2521 2521 int prevIndex = locationToIndex(loc);
2522 2522 Rectangle prevR = getCellBounds(prevIndex, prevIndex);
2523 2523
2524 2524 if (prevR == null || prevR.y >= r.y) {
2525 2525 return 0;
2526 2526 }
2527 2527 return prevR.height;
2528 2528 }
2529 2529 /* The first row is partially visible, return the
2530 2530 * height of hidden part.
2531 2531 */
2532 2532 else {
2533 2533 return visibleRect.y - r.y;
2534 2534 }
2535 2535 }
2536 2536 }
2537 2537 } else if (orientation == SwingConstants.HORIZONTAL &&
2538 2538 getLayoutOrientation() != JList.VERTICAL) {
2539 2539 boolean leftToRight = getComponentOrientation().isLeftToRight();
2540 2540 int index;
2541 2541 Point leadingPoint;
2542 2542
2543 2543 if (leftToRight) {
2544 2544 leadingPoint = visibleRect.getLocation();
2545 2545 }
2546 2546 else {
2547 2547 leadingPoint = new Point(visibleRect.x + visibleRect.width -1,
2548 2548 visibleRect.y);
2549 2549 }
2550 2550 index = locationToIndex(leadingPoint);
2551 2551
2552 2552 if (index != -1) {
2553 2553 Rectangle cellBounds = getCellBounds(index, index);
2554 2554 if (cellBounds != null && cellBounds.contains(leadingPoint)) {
2555 2555 int leadingVisibleEdge;
2556 2556 int leadingCellEdge;
2557 2557
2558 2558 if (leftToRight) {
2559 2559 leadingVisibleEdge = visibleRect.x;
2560 2560 leadingCellEdge = cellBounds.x;
2561 2561 }
2562 2562 else {
2563 2563 leadingVisibleEdge = visibleRect.x + visibleRect.width;
2564 2564 leadingCellEdge = cellBounds.x + cellBounds.width;
2565 2565 }
2566 2566
2567 2567 if (leadingCellEdge != leadingVisibleEdge) {
2568 2568 if (direction < 0) {
2569 2569 // Show remainder of leading cell
2570 2570 return Math.abs(leadingVisibleEdge - leadingCellEdge);
2571 2571
2572 2572 }
2573 2573 else if (leftToRight) {
2574 2574 // Hide rest of leading cell
2575 2575 return leadingCellEdge + cellBounds.width - leadingVisibleEdge;
2576 2576 }
2577 2577 else {
2578 2578 // Hide rest of leading cell
2579 2579 return leadingVisibleEdge - cellBounds.x;
2580 2580 }
2581 2581 }
2582 2582 // ASSUME: All cells are the same width
2583 2583 return cellBounds.width;
2584 2584 }
2585 2585 }
2586 2586 }
2587 2587 Font f = getFont();
2588 2588 return (f != null) ? f.getSize() : 1;
2589 2589 }
2590 2590
2591 2591
2592 2592 /**
2593 2593 * Returns the distance to scroll to expose the next or previous block.
2594 2594 * <p>
2595 2595 * For vertical scrolling, the following rules are used:
2596 2596 * <ul>
2597 2597 * <li>if scrolling down, returns the distance to scroll so that the last
2598 2598 * visible element becomes the first completely visible element
2599 2599 * <li>if scrolling up, returns the distance to scroll so that the first
2600 2600 * visible element becomes the last completely visible element
2601 2601 * <li>returns {@code visibleRect.height} if the list is empty
2602 2602 * </ul>
2603 2603 * <p>
2604 2604 * For horizontal scrolling, when the layout orientation is either
2605 2605 * {@code VERTICAL_WRAP} or {@code HORIZONTAL_WRAP}:
2606 2606 * <ul>
2607 2607 * <li>if scrolling right, returns the distance to scroll so that the
2608 2608 * last visible element becomes
2609 2609 * the first completely visible element
2610 2610 * <li>if scrolling left, returns the distance to scroll so that the first
2611 2611 * visible element becomes the last completely visible element
2612 2612 * <li>returns {@code visibleRect.width} if the list is empty
2613 2613 * </ul>
2614 2614 * <p>
2615 2615 * For horizontal scrolling and {@code VERTICAL} orientation,
2616 2616 * returns {@code visibleRect.width}.
2617 2617 * <p>
2618 2618 * Note that the value of {@code visibleRect} must be the equal to
2619 2619 * {@code this.getVisibleRect()}.
2620 2620 *
2621 2621 * @param visibleRect the view area visible within the viewport
2622 2622 * @param orientation {@code SwingConstants.HORIZONTAL} or
2623 2623 * {@code SwingConstants.VERTICAL}
2624 2624 * @param direction less or equal to zero to scroll up/back,
2625 2625 * greater than zero for down/forward
2626 2626 * @return the "block" increment for scrolling in the specified direction;
2627 2627 * always positive
2628 2628 * @see #getScrollableUnitIncrement
2629 2629 * @see Scrollable#getScrollableBlockIncrement
2630 2630 * @throws IllegalArgumentException if {@code visibleRect} is {@code null}, or
2631 2631 * {@code orientation} isn't one of {@code SwingConstants.VERTICAL} or
2632 2632 * {@code SwingConstants.HORIZONTAL}
2633 2633 */
2634 2634 public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
2635 2635 checkScrollableParameters(visibleRect, orientation);
2636 2636 if (orientation == SwingConstants.VERTICAL) {
2637 2637 int inc = visibleRect.height;
2638 2638 /* Scroll Down */
2639 2639 if (direction > 0) {
2640 2640 // last cell is the lowest left cell
2641 2641 int last = locationToIndex(new Point(visibleRect.x, visibleRect.y+visibleRect.height-1));
2642 2642 if (last != -1) {
2643 2643 Rectangle lastRect = getCellBounds(last,last);
2644 2644 if (lastRect != null) {
2645 2645 inc = lastRect.y - visibleRect.y;
2646 2646 if ( (inc == 0) && (last < getModel().getSize()-1) ) {
2647 2647 inc = lastRect.height;
2648 2648 }
2649 2649 }
2650 2650 }
2651 2651 }
2652 2652 /* Scroll Up */
2653 2653 else {
2654 2654 int newFirst = locationToIndex(new Point(visibleRect.x, visibleRect.y-visibleRect.height));
2655 2655 int first = getFirstVisibleIndex();
2656 2656 if (newFirst != -1) {
2657 2657 if (first == -1) {
2658 2658 first = locationToIndex(visibleRect.getLocation());
2659 2659 }
2660 2660 Rectangle newFirstRect = getCellBounds(newFirst,newFirst);
2661 2661 Rectangle firstRect = getCellBounds(first,first);
2662 2662 if ((newFirstRect != null) && (firstRect!=null)) {
2663 2663 while ( (newFirstRect.y + visibleRect.height <
2664 2664 firstRect.y + firstRect.height) &&
2665 2665 (newFirstRect.y < firstRect.y) ) {
2666 2666 newFirst++;
2667 2667 newFirstRect = getCellBounds(newFirst,newFirst);
2668 2668 }
2669 2669 inc = visibleRect.y - newFirstRect.y;
2670 2670 if ( (inc <= 0) && (newFirstRect.y > 0)) {
2671 2671 newFirst--;
2672 2672 newFirstRect = getCellBounds(newFirst,newFirst);
2673 2673 if (newFirstRect != null) {
2674 2674 inc = visibleRect.y - newFirstRect.y;
2675 2675 }
2676 2676 }
2677 2677 }
2678 2678 }
2679 2679 }
2680 2680 return inc;
2681 2681 }
2682 2682 else if (orientation == SwingConstants.HORIZONTAL &&
2683 2683 getLayoutOrientation() != JList.VERTICAL) {
2684 2684 boolean leftToRight = getComponentOrientation().isLeftToRight();
2685 2685 int inc = visibleRect.width;
2686 2686 /* Scroll Right (in ltr mode) or Scroll Left (in rtl mode) */
2687 2687 if (direction > 0) {
2688 2688 // position is upper right if ltr, or upper left otherwise
2689 2689 int x = visibleRect.x + (leftToRight ? (visibleRect.width - 1) : 0);
2690 2690 int last = locationToIndex(new Point(x, visibleRect.y));
2691 2691
2692 2692 if (last != -1) {
2693 2693 Rectangle lastRect = getCellBounds(last,last);
2694 2694 if (lastRect != null) {
2695 2695 if (leftToRight) {
2696 2696 inc = lastRect.x - visibleRect.x;
2697 2697 } else {
2698 2698 inc = visibleRect.x + visibleRect.width
2699 2699 - (lastRect.x + lastRect.width);
2700 2700 }
2701 2701 if (inc < 0) {
2702 2702 inc += lastRect.width;
2703 2703 } else if ( (inc == 0) && (last < getModel().getSize()-1) ) {
2704 2704 inc = lastRect.width;
2705 2705 }
2706 2706 }
2707 2707 }
2708 2708 }
2709 2709 /* Scroll Left (in ltr mode) or Scroll Right (in rtl mode) */
2710 2710 else {
2711 2711 // position is upper left corner of the visibleRect shifted
2712 2712 // left by the visibleRect.width if ltr, or upper right shifted
2713 2713 // right by the visibleRect.width otherwise
2714 2714 int x = visibleRect.x + (leftToRight
2715 2715 ? -visibleRect.width
2716 2716 : visibleRect.width - 1 + visibleRect.width);
2717 2717 int first = locationToIndex(new Point(x, visibleRect.y));
2718 2718
2719 2719 if (first != -1) {
2720 2720 Rectangle firstRect = getCellBounds(first,first);
2721 2721 if (firstRect != null) {
2722 2722 // the right of the first cell
2723 2723 int firstRight = firstRect.x + firstRect.width;
2724 2724
2725 2725 if (leftToRight) {
2726 2726 if ((firstRect.x < visibleRect.x - visibleRect.width)
2727 2727 && (firstRight < visibleRect.x)) {
2728 2728 inc = visibleRect.x - firstRight;
2729 2729 } else {
2730 2730 inc = visibleRect.x - firstRect.x;
2731 2731 }
2732 2732 } else {
2733 2733 int visibleRight = visibleRect.x + visibleRect.width;
2734 2734
2735 2735 if ((firstRight > visibleRight + visibleRect.width)
2736 2736 && (firstRect.x > visibleRight)) {
2737 2737 inc = firstRect.x - visibleRight;
2738 2738 } else {
2739 2739 inc = firstRight - visibleRight;
2740 2740 }
2741 2741 }
2742 2742 }
2743 2743 }
2744 2744 }
2745 2745 return inc;
2746 2746 }
2747 2747 return visibleRect.width;
2748 2748 }
2749 2749
2750 2750
2751 2751 /**
2752 2752 * Returns {@code true} if this {@code JList} is displayed in a
2753 2753 * {@code JViewport} and the viewport is wider than the list's
2754 2754 * preferred width, or if the layout orientation is {@code HORIZONTAL_WRAP}
2755 2755 * and {@code visibleRowCount <= 0}; otherwise returns {@code false}.
2756 2756 * <p>
2757 2757 * If {@code false}, then don't track the viewport's width. This allows
2758 2758 * horizontal scrolling if the {@code JViewport} is itself embedded in a
2759 2759 * {@code JScrollPane}.
2760 2760 *
2761 2761 * @return whether or not an enclosing viewport should force the list's
2762 2762 * width to match its own
2763 2763 * @see Scrollable#getScrollableTracksViewportWidth
2764 2764 */
2765 2765 public boolean getScrollableTracksViewportWidth() {
2766 2766 if (getLayoutOrientation() == HORIZONTAL_WRAP &&
2767 2767 getVisibleRowCount() <= 0) {
2768 2768 return true;
2769 2769 }
2770 2770 Container parent = SwingUtilities.getUnwrappedParent(this);
2771 2771 if (parent instanceof JViewport) {
2772 2772 return parent.getWidth() > getPreferredSize().width;
2773 2773 }
2774 2774 return false;
2775 2775 }
2776 2776
2777 2777 /**
2778 2778 * Returns {@code true} if this {@code JList} is displayed in a
2779 2779 * {@code JViewport} and the viewport is taller than the list's
2780 2780 * preferred height, or if the layout orientation is {@code VERTICAL_WRAP}
2781 2781 * and {@code visibleRowCount <= 0}; otherwise returns {@code false}.
2782 2782 * <p>
2783 2783 * If {@code false}, then don't track the viewport's height. This allows
2784 2784 * vertical scrolling if the {@code JViewport} is itself embedded in a
2785 2785 * {@code JScrollPane}.
2786 2786 *
2787 2787 * @return whether or not an enclosing viewport should force the list's
2788 2788 * height to match its own
2789 2789 * @see Scrollable#getScrollableTracksViewportHeight
2790 2790 */
2791 2791 public boolean getScrollableTracksViewportHeight() {
2792 2792 if (getLayoutOrientation() == VERTICAL_WRAP &&
2793 2793 getVisibleRowCount() <= 0) {
2794 2794 return true;
2795 2795 }
2796 2796 Container parent = SwingUtilities.getUnwrappedParent(this);
2797 2797 if (parent instanceof JViewport) {
2798 2798 return parent.getHeight() > getPreferredSize().height;
2799 2799 }
2800 2800 return false;
2801 2801 }
2802 2802
2803 2803
2804 2804 /*
2805 2805 * See {@code readObject} and {@code writeObject} in {@code JComponent}
2806 2806 * for more information about serialization in Swing.
2807 2807 */
2808 2808 private void writeObject(ObjectOutputStream s) throws IOException {
2809 2809 s.defaultWriteObject();
2810 2810 if (getUIClassID().equals(uiClassID)) {
2811 2811 byte count = JComponent.getWriteObjCounter(this);
2812 2812 JComponent.setWriteObjCounter(this, --count);
2813 2813 if (count == 0 && ui != null) {
2814 2814 ui.installUI(this);
2815 2815 }
2816 2816 }
2817 2817 }
2818 2818
2819 2819
2820 2820 /**
2821 2821 * Returns a {@code String} representation of this {@code JList}.
2822 2822 * This method is intended to be used only for debugging purposes,
2823 2823 * and the content and format of the returned {@code String} may vary
2824 2824 * between implementations. The returned {@code String} may be empty,
2825 2825 * but may not be {@code null}.
2826 2826 *
2827 2827 * @return a {@code String} representation of this {@code JList}.
2828 2828 */
2829 2829 protected String paramString() {
2830 2830 String selectionForegroundString = (selectionForeground != null ?
2831 2831 selectionForeground.toString() :
2832 2832 "");
2833 2833 String selectionBackgroundString = (selectionBackground != null ?
2834 2834 selectionBackground.toString() :
2835 2835 "");
2836 2836
2837 2837 return super.paramString() +
2838 2838 ",fixedCellHeight=" + fixedCellHeight +
2839 2839 ",fixedCellWidth=" + fixedCellWidth +
2840 2840 ",horizontalScrollIncrement=" + horizontalScrollIncrement +
2841 2841 ",selectionBackground=" + selectionBackgroundString +
2842 2842 ",selectionForeground=" + selectionForegroundString +
2843 2843 ",visibleRowCount=" + visibleRowCount +
2844 2844 ",layoutOrientation=" + layoutOrientation;
2845 2845 }
2846 2846
2847 2847
2848 2848 /**
2849 2849 * --- Accessibility Support ---
2850 2850 */
2851 2851
2852 2852 /**
2853 2853 * Gets the {@code AccessibleContext} associated with this {@code JList}.
2854 2854 * For {@code JList}, the {@code AccessibleContext} takes the form of an
2855 2855 * {@code AccessibleJList}.
2856 2856 * <p>
2857 2857 * A new {@code AccessibleJList} instance is created if necessary.
2858 2858 *
2859 2859 * @return an {@code AccessibleJList} that serves as the
2860 2860 * {@code AccessibleContext} of this {@code JList}
2861 2861 */
2862 2862 public AccessibleContext getAccessibleContext() {
2863 2863 if (accessibleContext == null) {
2864 2864 accessibleContext = new AccessibleJList();
2865 2865 }
2866 2866 return accessibleContext;
2867 2867 }
2868 2868
2869 2869 /**
2870 2870 * This class implements accessibility support for the
2871 2871 * {@code JList} class. It provides an implementation of the
2872 2872 * Java Accessibility API appropriate to list user-interface
2873 2873 * elements.
2874 2874 * <p>
2875 2875 * <strong>Warning:</strong>
2876 2876 * Serialized objects of this class will not be compatible with
2877 2877 * future Swing releases. The current serialization support is
2878 2878 * appropriate for short term storage or RMI between applications running
2879 2879 * the same version of Swing. As of 1.4, support for long term storage
2880 2880 * of all JavaBeans™
2881 2881 * has been added to the <code>java.beans</code> package.
2882 2882 * Please see {@link java.beans.XMLEncoder}.
2883 2883 */
2884 2884 protected class AccessibleJList extends AccessibleJComponent
2885 2885 implements AccessibleSelection, PropertyChangeListener,
2886 2886 ListSelectionListener, ListDataListener {
2887 2887
2888 2888 int leadSelectionIndex;
2889 2889
2890 2890 public AccessibleJList() {
2891 2891 super();
2892 2892 JList.this.addPropertyChangeListener(this);
2893 2893 JList.this.getSelectionModel().addListSelectionListener(this);
2894 2894 JList.this.getModel().addListDataListener(this);
2895 2895 leadSelectionIndex = JList.this.getLeadSelectionIndex();
2896 2896 }
2897 2897
2898 2898 /**
2899 2899 * Property Change Listener change method. Used to track changes
2900 2900 * to the DataModel and ListSelectionModel, in order to re-set
2901 2901 * listeners to those for reporting changes there via the Accessibility
2902 2902 * PropertyChange mechanism.
2903 2903 *
2904 2904 * @param e PropertyChangeEvent
2905 2905 */
2906 2906 public void propertyChange(PropertyChangeEvent e) {
2907 2907 String name = e.getPropertyName();
2908 2908 Object oldValue = e.getOldValue();
2909 2909 Object newValue = e.getNewValue();
2910 2910
2911 2911 // re-set listData listeners
2912 2912 if (name.compareTo("model") == 0) {
2913 2913
2914 2914 if (oldValue != null && oldValue instanceof ListModel) {
2915 2915 ((ListModel) oldValue).removeListDataListener(this);
2916 2916 }
2917 2917 if (newValue != null && newValue instanceof ListModel) {
2918 2918 ((ListModel) newValue).addListDataListener(this);
2919 2919 }
2920 2920
2921 2921 // re-set listSelectionModel listeners
2922 2922 } else if (name.compareTo("selectionModel") == 0) {
2923 2923
2924 2924 if (oldValue != null && oldValue instanceof ListSelectionModel) {
2925 2925 ((ListSelectionModel) oldValue).removeListSelectionListener(this);
2926 2926 }
2927 2927 if (newValue != null && newValue instanceof ListSelectionModel) {
2928 2928 ((ListSelectionModel) newValue).addListSelectionListener(this);
2929 2929 }
2930 2930
2931 2931 firePropertyChange(
2932 2932 AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY,
2933 2933 Boolean.valueOf(false), Boolean.valueOf(true));
2934 2934 }
2935 2935 }
2936 2936
2937 2937 /**
2938 2938 * List Selection Listener value change method. Used to fire
2939 2939 * the property change
2940 2940 *
2941 2941 * @param e ListSelectionEvent
2942 2942 *
2943 2943 */
2944 2944 public void valueChanged(ListSelectionEvent e) {
2945 2945 int oldLeadSelectionIndex = leadSelectionIndex;
2946 2946 leadSelectionIndex = JList.this.getLeadSelectionIndex();
2947 2947 if (oldLeadSelectionIndex != leadSelectionIndex) {
2948 2948 Accessible oldLS, newLS;
2949 2949 oldLS = (oldLeadSelectionIndex >= 0)
2950 2950 ? getAccessibleChild(oldLeadSelectionIndex)
2951 2951 : null;
2952 2952 newLS = (leadSelectionIndex >= 0)
2953 2953 ? getAccessibleChild(leadSelectionIndex)
2954 2954 : null;
2955 2955 firePropertyChange(AccessibleContext.ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY,
2956 2956 oldLS, newLS);
2957 2957 }
2958 2958
2959 2959 firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
2960 2960 Boolean.valueOf(false), Boolean.valueOf(true));
2961 2961 firePropertyChange(AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY,
2962 2962 Boolean.valueOf(false), Boolean.valueOf(true));
2963 2963
2964 2964 // Process the State changes for Multiselectable
2965 2965 AccessibleStateSet s = getAccessibleStateSet();
2966 2966 ListSelectionModel lsm = JList.this.getSelectionModel();
2967 2967 if (lsm.getSelectionMode() != ListSelectionModel.SINGLE_SELECTION) {
2968 2968 if (!s.contains(AccessibleState.MULTISELECTABLE)) {
2969 2969 s.add(AccessibleState.MULTISELECTABLE);
2970 2970 firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
2971 2971 null, AccessibleState.MULTISELECTABLE);
2972 2972 }
2973 2973 } else {
2974 2974 if (s.contains(AccessibleState.MULTISELECTABLE)) {
2975 2975 s.remove(AccessibleState.MULTISELECTABLE);
2976 2976 firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
2977 2977 AccessibleState.MULTISELECTABLE, null);
2978 2978 }
2979 2979 }
2980 2980 }
2981 2981
2982 2982 /**
2983 2983 * List Data Listener interval added method. Used to fire the visible data property change
2984 2984 *
2985 2985 * @param e ListDataEvent
2986 2986 *
2987 2987 */
2988 2988 public void intervalAdded(ListDataEvent e) {
2989 2989 firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
2990 2990 Boolean.valueOf(false), Boolean.valueOf(true));
2991 2991 }
2992 2992
2993 2993 /**
2994 2994 * List Data Listener interval removed method. Used to fire the visible data property change
2995 2995 *
2996 2996 * @param e ListDataEvent
2997 2997 *
2998 2998 */
2999 2999 public void intervalRemoved(ListDataEvent e) {
3000 3000 firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
3001 3001 Boolean.valueOf(false), Boolean.valueOf(true));
3002 3002 }
3003 3003
3004 3004 /**
3005 3005 * List Data Listener contents changed method. Used to fire the visible data property change
3006 3006 *
3007 3007 * @param e ListDataEvent
3008 3008 *
3009 3009 */
3010 3010 public void contentsChanged(ListDataEvent e) {
3011 3011 firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
3012 3012 Boolean.valueOf(false), Boolean.valueOf(true));
3013 3013 }
3014 3014
3015 3015 // AccessibleContext methods
3016 3016
3017 3017 /**
3018 3018 * Get the state set of this object.
3019 3019 *
3020 3020 * @return an instance of AccessibleState containing the current state
3021 3021 * of the object
3022 3022 * @see AccessibleState
3023 3023 */
3024 3024 public AccessibleStateSet getAccessibleStateSet() {
3025 3025 AccessibleStateSet states = super.getAccessibleStateSet();
3026 3026 if (selectionModel.getSelectionMode() !=
3027 3027 ListSelectionModel.SINGLE_SELECTION) {
3028 3028 states.add(AccessibleState.MULTISELECTABLE);
3029 3029 }
3030 3030 return states;
3031 3031 }
3032 3032
3033 3033 /**
3034 3034 * Get the role of this object.
3035 3035 *
3036 3036 * @return an instance of AccessibleRole describing the role of the
3037 3037 * object
3038 3038 * @see AccessibleRole
3039 3039 */
3040 3040 public AccessibleRole getAccessibleRole() {
3041 3041 return AccessibleRole.LIST;
3042 3042 }
3043 3043
3044 3044 /**
3045 3045 * Returns the <code>Accessible</code> child contained at
3046 3046 * the local coordinate <code>Point</code>, if one exists.
3047 3047 * Otherwise returns <code>null</code>.
3048 3048 *
3049 3049 * @return the <code>Accessible</code> at the specified
3050 3050 * location, if it exists
3051 3051 */
3052 3052 public Accessible getAccessibleAt(Point p) {
3053 3053 int i = locationToIndex(p);
3054 3054 if (i >= 0) {
3055 3055 return new AccessibleJListChild(JList.this, i);
3056 3056 } else {
3057 3057 return null;
3058 3058 }
3059 3059 }
3060 3060
3061 3061 /**
3062 3062 * Returns the number of accessible children in the object. If all
3063 3063 * of the children of this object implement Accessible, than this
3064 3064 * method should return the number of children of this object.
3065 3065 *
3066 3066 * @return the number of accessible children in the object.
3067 3067 */
3068 3068 public int getAccessibleChildrenCount() {
3069 3069 return getModel().getSize();
3070 3070 }
3071 3071
3072 3072 /**
3073 3073 * Return the nth Accessible child of the object.
3074 3074 *
3075 3075 * @param i zero-based index of child
3076 3076 * @return the nth Accessible child of the object
3077 3077 */
3078 3078 public Accessible getAccessibleChild(int i) {
3079 3079 if (i >= getModel().getSize()) {
3080 3080 return null;
3081 3081 } else {
3082 3082 return new AccessibleJListChild(JList.this, i);
3083 3083 }
3084 3084 }
3085 3085
3086 3086 /**
3087 3087 * Get the AccessibleSelection associated with this object. In the
3088 3088 * implementation of the Java Accessibility API for this class,
3089 3089 * return this object, which is responsible for implementing the
3090 3090 * AccessibleSelection interface on behalf of itself.
3091 3091 *
3092 3092 * @return this object
3093 3093 */
3094 3094 public AccessibleSelection getAccessibleSelection() {
3095 3095 return this;
3096 3096 }
3097 3097
3098 3098
3099 3099 // AccessibleSelection methods
3100 3100
3101 3101 /**
3102 3102 * Returns the number of items currently selected.
3103 3103 * If no items are selected, the return value will be 0.
3104 3104 *
3105 3105 * @return the number of items currently selected.
3106 3106 */
3107 3107 public int getAccessibleSelectionCount() {
3108 3108 return JList.this.getSelectedIndices().length;
3109 3109 }
3110 3110
3111 3111 /**
3112 3112 * Returns an Accessible representing the specified selected item
3113 3113 * in the object. If there isn't a selection, or there are
3114 3114 * fewer items selected than the integer passed in, the return
3115 3115 * value will be <code>null</code>.
3116 3116 *
3117 3117 * @param i the zero-based index of selected items
3118 3118 * @return an Accessible containing the selected item
3119 3119 */
3120 3120 public Accessible getAccessibleSelection(int i) {
3121 3121 int len = getAccessibleSelectionCount();
3122 3122 if (i < 0 || i >= len) {
3123 3123 return null;
3124 3124 } else {
3125 3125 return getAccessibleChild(JList.this.getSelectedIndices()[i]);
3126 3126 }
3127 3127 }
3128 3128
3129 3129 /**
3130 3130 * Returns true if the current child of this object is selected.
3131 3131 *
3132 3132 * @param i the zero-based index of the child in this Accessible
3133 3133 * object.
3134 3134 * @see AccessibleContext#getAccessibleChild
3135 3135 */
3136 3136 public boolean isAccessibleChildSelected(int i) {
3137 3137 return isSelectedIndex(i);
3138 3138 }
3139 3139
3140 3140 /**
3141 3141 * Adds the specified selected item in the object to the object's
3142 3142 * selection. If the object supports multiple selections,
3143 3143 * the specified item is added to any existing selection, otherwise
3144 3144 * it replaces any existing selection in the object. If the
3145 3145 * specified item is already selected, this method has no effect.
3146 3146 *
3147 3147 * @param i the zero-based index of selectable items
3148 3148 */
3149 3149 public void addAccessibleSelection(int i) {
3150 3150 JList.this.addSelectionInterval(i, i);
3151 3151 }
3152 3152
3153 3153 /**
3154 3154 * Removes the specified selected item in the object from the object's
3155 3155 * selection. If the specified item isn't currently selected, this
3156 3156 * method has no effect.
3157 3157 *
3158 3158 * @param i the zero-based index of selectable items
3159 3159 */
3160 3160 public void removeAccessibleSelection(int i) {
3161 3161 JList.this.removeSelectionInterval(i, i);
3162 3162 }
3163 3163
3164 3164 /**
3165 3165 * Clears the selection in the object, so that nothing in the
3166 3166 * object is selected.
3167 3167 */
3168 3168 public void clearAccessibleSelection() {
3169 3169 JList.this.clearSelection();
3170 3170 }
3171 3171
3172 3172 /**
3173 3173 * Causes every selected item in the object to be selected
3174 3174 * if the object supports multiple selections.
3175 3175 */
3176 3176 public void selectAllAccessibleSelection() {
3177 3177 JList.this.addSelectionInterval(0, getAccessibleChildrenCount() -1);
3178 3178 }
3179 3179
3180 3180 /**
3181 3181 * This class implements accessibility support appropriate
3182 3182 * for list children.
3183 3183 */
3184 3184 protected class AccessibleJListChild extends AccessibleContext
3185 3185 implements Accessible, AccessibleComponent {
3186 3186 private JList<E> parent = null;
3187 3187 private int indexInParent;
3188 3188 private Component component = null;
3189 3189 private AccessibleContext accessibleContext = null;
3190 3190 private ListModel<E> listModel;
3191 3191 private ListCellRenderer<? super E> cellRenderer = null;
3192 3192
3193 3193 public AccessibleJListChild(JList<E> parent, int indexInParent) {
3194 3194 this.parent = parent;
3195 3195 this.setAccessibleParent(parent);
3196 3196 this.indexInParent = indexInParent;
3197 3197 if (parent != null) {
3198 3198 listModel = parent.getModel();
3199 3199 cellRenderer = parent.getCellRenderer();
3200 3200 }
3201 3201 }
3202 3202
3203 3203 private Component getCurrentComponent() {
3204 3204 return getComponentAtIndex(indexInParent);
3205 3205 }
3206 3206
3207 3207 private AccessibleContext getCurrentAccessibleContext() {
3208 3208 Component c = getComponentAtIndex(indexInParent);
3209 3209 if (c instanceof Accessible) {
3210 3210 return c.getAccessibleContext();
3211 3211 } else {
3212 3212 return null;
3213 3213 }
3214 3214 }
3215 3215
3216 3216 private Component getComponentAtIndex(int index) {
3217 3217 if (index < 0 || index >= listModel.getSize()) {
3218 3218 return null;
3219 3219 }
3220 3220 if ((parent != null)
3221 3221 && (listModel != null)
3222 3222 && cellRenderer != null) {
3223 3223 E value = listModel.getElementAt(index);
3224 3224 boolean isSelected = parent.isSelectedIndex(index);
3225 3225 boolean isFocussed = parent.isFocusOwner()
3226 3226 && (index == parent.getLeadSelectionIndex());
3227 3227 return cellRenderer.getListCellRendererComponent(
3228 3228 parent,
3229 3229 value,
3230 3230 index,
3231 3231 isSelected,
3232 3232 isFocussed);
3233 3233 } else {
3234 3234 return null;
3235 3235 }
3236 3236 }
3237 3237
3238 3238
3239 3239 // Accessible Methods
3240 3240 /**
3241 3241 * Get the AccessibleContext for this object. In the
3242 3242 * implementation of the Java Accessibility API for this class,
3243 3243 * returns this object, which is its own AccessibleContext.
3244 3244 *
3245 3245 * @return this object
3246 3246 */
3247 3247 public AccessibleContext getAccessibleContext() {
3248 3248 return this;
3249 3249 }
3250 3250
3251 3251
3252 3252 // AccessibleContext methods
3253 3253
3254 3254 public String getAccessibleName() {
3255 3255 AccessibleContext ac = getCurrentAccessibleContext();
3256 3256 if (ac != null) {
3257 3257 return ac.getAccessibleName();
3258 3258 } else {
3259 3259 return null;
3260 3260 }
3261 3261 }
3262 3262
3263 3263 public void setAccessibleName(String s) {
3264 3264 AccessibleContext ac = getCurrentAccessibleContext();
3265 3265 if (ac != null) {
3266 3266 ac.setAccessibleName(s);
3267 3267 }
3268 3268 }
3269 3269
3270 3270 public String getAccessibleDescription() {
3271 3271 AccessibleContext ac = getCurrentAccessibleContext();
3272 3272 if (ac != null) {
3273 3273 return ac.getAccessibleDescription();
3274 3274 } else {
3275 3275 return null;
3276 3276 }
3277 3277 }
3278 3278
3279 3279 public void setAccessibleDescription(String s) {
3280 3280 AccessibleContext ac = getCurrentAccessibleContext();
3281 3281 if (ac != null) {
3282 3282 ac.setAccessibleDescription(s);
3283 3283 }
3284 3284 }
3285 3285
3286 3286 public AccessibleRole getAccessibleRole() {
3287 3287 AccessibleContext ac = getCurrentAccessibleContext();
3288 3288 if (ac != null) {
3289 3289 return ac.getAccessibleRole();
3290 3290 } else {
3291 3291 return null;
3292 3292 }
3293 3293 }
3294 3294
3295 3295 public AccessibleStateSet getAccessibleStateSet() {
3296 3296 AccessibleContext ac = getCurrentAccessibleContext();
3297 3297 AccessibleStateSet s;
3298 3298 if (ac != null) {
3299 3299 s = ac.getAccessibleStateSet();
3300 3300 } else {
3301 3301 s = new AccessibleStateSet();
3302 3302 }
3303 3303
3304 3304 s.add(AccessibleState.SELECTABLE);
3305 3305 if (parent.isFocusOwner()
3306 3306 && (indexInParent == parent.getLeadSelectionIndex())) {
3307 3307 s.add(AccessibleState.ACTIVE);
3308 3308 }
3309 3309 if (parent.isSelectedIndex(indexInParent)) {
3310 3310 s.add(AccessibleState.SELECTED);
3311 3311 }
3312 3312 if (this.isShowing()) {
3313 3313 s.add(AccessibleState.SHOWING);
3314 3314 } else if (s.contains(AccessibleState.SHOWING)) {
3315 3315 s.remove(AccessibleState.SHOWING);
3316 3316 }
3317 3317 if (this.isVisible()) {
3318 3318 s.add(AccessibleState.VISIBLE);
3319 3319 } else if (s.contains(AccessibleState.VISIBLE)) {
3320 3320 s.remove(AccessibleState.VISIBLE);
3321 3321 }
3322 3322 s.add(AccessibleState.TRANSIENT); // cell-rendered
3323 3323 return s;
3324 3324 }
3325 3325
3326 3326 public int getAccessibleIndexInParent() {
3327 3327 return indexInParent;
3328 3328 }
3329 3329
3330 3330 public int getAccessibleChildrenCount() {
3331 3331 AccessibleContext ac = getCurrentAccessibleContext();
3332 3332 if (ac != null) {
3333 3333 return ac.getAccessibleChildrenCount();
3334 3334 } else {
3335 3335 return 0;
3336 3336 }
3337 3337 }
3338 3338
3339 3339 public Accessible getAccessibleChild(int i) {
3340 3340 AccessibleContext ac = getCurrentAccessibleContext();
3341 3341 if (ac != null) {
3342 3342 Accessible accessibleChild = ac.getAccessibleChild(i);
3343 3343 ac.setAccessibleParent(this);
3344 3344 return accessibleChild;
3345 3345 } else {
3346 3346 return null;
3347 3347 }
3348 3348 }
3349 3349
3350 3350 public Locale getLocale() {
3351 3351 AccessibleContext ac = getCurrentAccessibleContext();
3352 3352 if (ac != null) {
3353 3353 return ac.getLocale();
3354 3354 } else {
3355 3355 return null;
3356 3356 }
3357 3357 }
3358 3358
3359 3359 public void addPropertyChangeListener(PropertyChangeListener l) {
3360 3360 AccessibleContext ac = getCurrentAccessibleContext();
3361 3361 if (ac != null) {
3362 3362 ac.addPropertyChangeListener(l);
3363 3363 }
3364 3364 }
3365 3365
3366 3366 public void removePropertyChangeListener(PropertyChangeListener l) {
3367 3367 AccessibleContext ac = getCurrentAccessibleContext();
3368 3368 if (ac != null) {
3369 3369 ac.removePropertyChangeListener(l);
3370 3370 }
3371 3371 }
3372 3372
3373 3373 public AccessibleAction getAccessibleAction() {
3374 3374 return getCurrentAccessibleContext().getAccessibleAction();
3375 3375 }
3376 3376
3377 3377 /**
3378 3378 * Get the AccessibleComponent associated with this object. In the
3379 3379 * implementation of the Java Accessibility API for this class,
3380 3380 * return this object, which is responsible for implementing the
3381 3381 * AccessibleComponent interface on behalf of itself.
3382 3382 *
3383 3383 * @return this object
3384 3384 */
3385 3385 public AccessibleComponent getAccessibleComponent() {
3386 3386 return this; // to override getBounds()
3387 3387 }
3388 3388
3389 3389 public AccessibleSelection getAccessibleSelection() {
3390 3390 return getCurrentAccessibleContext().getAccessibleSelection();
3391 3391 }
3392 3392
3393 3393 public AccessibleText getAccessibleText() {
3394 3394 return getCurrentAccessibleContext().getAccessibleText();
3395 3395 }
3396 3396
3397 3397 public AccessibleValue getAccessibleValue() {
3398 3398 return getCurrentAccessibleContext().getAccessibleValue();
3399 3399 }
3400 3400
3401 3401
3402 3402 // AccessibleComponent methods
3403 3403
3404 3404 public Color getBackground() {
3405 3405 AccessibleContext ac = getCurrentAccessibleContext();
3406 3406 if (ac instanceof AccessibleComponent) {
3407 3407 return ((AccessibleComponent) ac).getBackground();
3408 3408 } else {
3409 3409 Component c = getCurrentComponent();
3410 3410 if (c != null) {
3411 3411 return c.getBackground();
3412 3412 } else {
3413 3413 return null;
3414 3414 }
3415 3415 }
3416 3416 }
3417 3417
3418 3418 public void setBackground(Color c) {
3419 3419 AccessibleContext ac = getCurrentAccessibleContext();
3420 3420 if (ac instanceof AccessibleComponent) {
3421 3421 ((AccessibleComponent) ac).setBackground(c);
3422 3422 } else {
3423 3423 Component cp = getCurrentComponent();
3424 3424 if (cp != null) {
3425 3425 cp.setBackground(c);
3426 3426 }
3427 3427 }
3428 3428 }
3429 3429
3430 3430 public Color getForeground() {
3431 3431 AccessibleContext ac = getCurrentAccessibleContext();
3432 3432 if (ac instanceof AccessibleComponent) {
3433 3433 return ((AccessibleComponent) ac).getForeground();
3434 3434 } else {
3435 3435 Component c = getCurrentComponent();
3436 3436 if (c != null) {
3437 3437 return c.getForeground();
3438 3438 } else {
3439 3439 return null;
3440 3440 }
3441 3441 }
3442 3442 }
3443 3443
3444 3444 public void setForeground(Color c) {
3445 3445 AccessibleContext ac = getCurrentAccessibleContext();
3446 3446 if (ac instanceof AccessibleComponent) {
3447 3447 ((AccessibleComponent) ac).setForeground(c);
3448 3448 } else {
3449 3449 Component cp = getCurrentComponent();
3450 3450 if (cp != null) {
3451 3451 cp.setForeground(c);
3452 3452 }
3453 3453 }
3454 3454 }
3455 3455
3456 3456 public Cursor getCursor() {
3457 3457 AccessibleContext ac = getCurrentAccessibleContext();
3458 3458 if (ac instanceof AccessibleComponent) {
3459 3459 return ((AccessibleComponent) ac).getCursor();
3460 3460 } else {
3461 3461 Component c = getCurrentComponent();
3462 3462 if (c != null) {
3463 3463 return c.getCursor();
3464 3464 } else {
3465 3465 Accessible ap = getAccessibleParent();
3466 3466 if (ap instanceof AccessibleComponent) {
3467 3467 return ((AccessibleComponent) ap).getCursor();
3468 3468 } else {
3469 3469 return null;
3470 3470 }
3471 3471 }
3472 3472 }
3473 3473 }
3474 3474
3475 3475 public void setCursor(Cursor c) {
3476 3476 AccessibleContext ac = getCurrentAccessibleContext();
3477 3477 if (ac instanceof AccessibleComponent) {
3478 3478 ((AccessibleComponent) ac).setCursor(c);
3479 3479 } else {
3480 3480 Component cp = getCurrentComponent();
3481 3481 if (cp != null) {
3482 3482 cp.setCursor(c);
3483 3483 }
3484 3484 }
3485 3485 }
3486 3486
3487 3487 public Font getFont() {
3488 3488 AccessibleContext ac = getCurrentAccessibleContext();
3489 3489 if (ac instanceof AccessibleComponent) {
3490 3490 return ((AccessibleComponent) ac).getFont();
3491 3491 } else {
3492 3492 Component c = getCurrentComponent();
3493 3493 if (c != null) {
3494 3494 return c.getFont();
3495 3495 } else {
3496 3496 return null;
3497 3497 }
3498 3498 }
3499 3499 }
3500 3500
3501 3501 public void setFont(Font f) {
3502 3502 AccessibleContext ac = getCurrentAccessibleContext();
3503 3503 if (ac instanceof AccessibleComponent) {
3504 3504 ((AccessibleComponent) ac).setFont(f);
3505 3505 } else {
3506 3506 Component c = getCurrentComponent();
3507 3507 if (c != null) {
3508 3508 c.setFont(f);
3509 3509 }
3510 3510 }
3511 3511 }
3512 3512
3513 3513 public FontMetrics getFontMetrics(Font f) {
3514 3514 AccessibleContext ac = getCurrentAccessibleContext();
3515 3515 if (ac instanceof AccessibleComponent) {
3516 3516 return ((AccessibleComponent) ac).getFontMetrics(f);
3517 3517 } else {
3518 3518 Component c = getCurrentComponent();
3519 3519 if (c != null) {
3520 3520 return c.getFontMetrics(f);
3521 3521 } else {
3522 3522 return null;
3523 3523 }
3524 3524 }
3525 3525 }
3526 3526
3527 3527 public boolean isEnabled() {
3528 3528 AccessibleContext ac = getCurrentAccessibleContext();
3529 3529 if (ac instanceof AccessibleComponent) {
3530 3530 return ((AccessibleComponent) ac).isEnabled();
3531 3531 } else {
3532 3532 Component c = getCurrentComponent();
3533 3533 if (c != null) {
3534 3534 return c.isEnabled();
3535 3535 } else {
3536 3536 return false;
3537 3537 }
3538 3538 }
3539 3539 }
3540 3540
3541 3541 public void setEnabled(boolean b) {
3542 3542 AccessibleContext ac = getCurrentAccessibleContext();
3543 3543 if (ac instanceof AccessibleComponent) {
3544 3544 ((AccessibleComponent) ac).setEnabled(b);
3545 3545 } else {
3546 3546 Component c = getCurrentComponent();
3547 3547 if (c != null) {
3548 3548 c.setEnabled(b);
3549 3549 }
3550 3550 }
3551 3551 }
3552 3552
3553 3553 public boolean isVisible() {
3554 3554 int fi = parent.getFirstVisibleIndex();
3555 3555 int li = parent.getLastVisibleIndex();
3556 3556 // The UI incorrectly returns a -1 for the last
3557 3557 // visible index if the list is smaller than the
3558 3558 // viewport size.
3559 3559 if (li == -1) {
3560 3560 li = parent.getModel().getSize() - 1;
3561 3561 }
3562 3562 return ((indexInParent >= fi)
3563 3563 && (indexInParent <= li));
3564 3564 }
3565 3565
3566 3566 public void setVisible(boolean b) {
3567 3567 }
3568 3568
3569 3569 public boolean isShowing() {
3570 3570 return (parent.isShowing() && isVisible());
3571 3571 }
3572 3572
3573 3573 public boolean contains(Point p) {
3574 3574 AccessibleContext ac = getCurrentAccessibleContext();
3575 3575 if (ac instanceof AccessibleComponent) {
3576 3576 Rectangle r = ((AccessibleComponent) ac).getBounds();
3577 3577 return r.contains(p);
3578 3578 } else {
3579 3579 Component c = getCurrentComponent();
3580 3580 if (c != null) {
3581 3581 Rectangle r = c.getBounds();
3582 3582 return r.contains(p);
3583 3583 } else {
3584 3584 return getBounds().contains(p);
3585 3585 }
3586 3586 }
3587 3587 }
3588 3588
3589 3589 public Point getLocationOnScreen() {
3590 3590 if (parent != null) {
3591 3591 Point listLocation = parent.getLocationOnScreen();
3592 3592 Point componentLocation = parent.indexToLocation(indexInParent);
3593 3593 if (componentLocation != null) {
3594 3594 componentLocation.translate(listLocation.x, listLocation.y);
3595 3595 return componentLocation;
3596 3596 } else {
3597 3597 return null;
3598 3598 }
3599 3599 } else {
3600 3600 return null;
3601 3601 }
3602 3602 }
3603 3603
3604 3604 public Point getLocation() {
3605 3605 if (parent != null) {
3606 3606 return parent.indexToLocation(indexInParent);
3607 3607 } else {
3608 3608 return null;
3609 3609 }
3610 3610 }
3611 3611
3612 3612 public void setLocation(Point p) {
3613 3613 if ((parent != null) && (parent.contains(p))) {
3614 3614 ensureIndexIsVisible(indexInParent);
3615 3615 }
3616 3616 }
3617 3617
3618 3618 public Rectangle getBounds() {
3619 3619 if (parent != null) {
3620 3620 return parent.getCellBounds(indexInParent,indexInParent);
3621 3621 } else {
3622 3622 return null;
3623 3623 }
3624 3624 }
3625 3625
3626 3626 public void setBounds(Rectangle r) {
3627 3627 AccessibleContext ac = getCurrentAccessibleContext();
3628 3628 if (ac instanceof AccessibleComponent) {
3629 3629 ((AccessibleComponent) ac).setBounds(r);
3630 3630 }
3631 3631 }
3632 3632
3633 3633 public Dimension getSize() {
3634 3634 Rectangle cellBounds = this.getBounds();
3635 3635 if (cellBounds != null) {
3636 3636 return cellBounds.getSize();
3637 3637 } else {
3638 3638 return null;
3639 3639 }
3640 3640 }
3641 3641
3642 3642 public void setSize (Dimension d) {
3643 3643 AccessibleContext ac = getCurrentAccessibleContext();
3644 3644 if (ac instanceof AccessibleComponent) {
3645 3645 ((AccessibleComponent) ac).setSize(d);
3646 3646 } else {
3647 3647 Component c = getCurrentComponent();
3648 3648 if (c != null) {
3649 3649 c.setSize(d);
3650 3650 }
3651 3651 }
3652 3652 }
3653 3653
3654 3654 public Accessible getAccessibleAt(Point p) {
3655 3655 AccessibleContext ac = getCurrentAccessibleContext();
3656 3656 if (ac instanceof AccessibleComponent) {
3657 3657 return ((AccessibleComponent) ac).getAccessibleAt(p);
3658 3658 } else {
3659 3659 return null;
3660 3660 }
3661 3661 }
3662 3662
3663 3663 public boolean isFocusTraversable() {
3664 3664 AccessibleContext ac = getCurrentAccessibleContext();
3665 3665 if (ac instanceof AccessibleComponent) {
3666 3666 return ((AccessibleComponent) ac).isFocusTraversable();
3667 3667 } else {
3668 3668 Component c = getCurrentComponent();
3669 3669 if (c != null) {
3670 3670 return c.isFocusTraversable();
3671 3671 } else {
3672 3672 return false;
3673 3673 }
3674 3674 }
3675 3675 }
3676 3676
3677 3677 public void requestFocus() {
3678 3678 AccessibleContext ac = getCurrentAccessibleContext();
3679 3679 if (ac instanceof AccessibleComponent) {
3680 3680 ((AccessibleComponent) ac).requestFocus();
3681 3681 } else {
3682 3682 Component c = getCurrentComponent();
3683 3683 if (c != null) {
3684 3684 c.requestFocus();
3685 3685 }
3686 3686 }
3687 3687 }
3688 3688
3689 3689 public void addFocusListener(FocusListener l) {
3690 3690 AccessibleContext ac = getCurrentAccessibleContext();
3691 3691 if (ac instanceof AccessibleComponent) {
3692 3692 ((AccessibleComponent) ac).addFocusListener(l);
3693 3693 } else {
3694 3694 Component c = getCurrentComponent();
3695 3695 if (c != null) {
3696 3696 c.addFocusListener(l);
3697 3697 }
3698 3698 }
3699 3699 }
3700 3700
3701 3701 public void removeFocusListener(FocusListener l) {
3702 3702 AccessibleContext ac = getCurrentAccessibleContext();
3703 3703 if (ac instanceof AccessibleComponent) {
3704 3704 ((AccessibleComponent) ac).removeFocusListener(l);
3705 3705 } else {
3706 3706 Component c = getCurrentComponent();
3707 3707 if (c != null) {
3708 3708 c.removeFocusListener(l);
3709 3709 }
3710 3710 }
3711 3711 }
3712 3712
3713 3713 // TIGER - 4733624
3714 3714 /**
3715 3715 * Returns the icon for the element renderer, as the only item
3716 3716 * of an array of <code>AccessibleIcon</code>s or a <code>null</code> array
3717 3717 * if the renderer component contains no icons.
3718 3718 *
3719 3719 * @return an array containing the accessible icon
3720 3720 * or a <code>null</code> array if none
3721 3721 * @since 1.3
3722 3722 */
3723 3723 public AccessibleIcon [] getAccessibleIcon() {
3724 3724 AccessibleContext ac = getCurrentAccessibleContext();
3725 3725 if (ac != null) {
3726 3726 return ac.getAccessibleIcon();
3727 3727 } else {
3728 3728 return null;
3729 3729 }
3730 3730 }
3731 3731 } // inner class AccessibleJListChild
3732 3732 } // inner class AccessibleJList
3733 3733 }
↓ open down ↓ |
3462 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX