OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [javax/] [swing/] [JList.java] - Blame information for rev 775

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.