1. /*
  2. * @(#)JList.java 1.112 04/05/05
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.swing;
  8. import java.awt.event.*;
  9. import java.awt.*;
  10. import java.util.Vector;
  11. import java.util.Locale;
  12. import java.beans.*;
  13. import javax.swing.event.*;
  14. import javax.accessibility.*;
  15. import javax.swing.plaf.*;
  16. import javax.swing.text.Position;
  17. import java.io.ObjectOutputStream;
  18. import java.io.ObjectInputStream;
  19. import java.io.IOException;
  20. import java.io.Serializable;
  21. /**
  22. * A component that allows the user to select one or more objects from a
  23. * list. A separate model, <code>ListModel</code>, represents the contents
  24. * of the list. It's easy to display an array or vector of objects, using
  25. * a <code>JList</code> constructor that builds a <code>ListModel</code>
  26. * instance for you:
  27. * <pre>
  28. * // Create a JList that displays the strings in data[]
  29. *
  30. * String[] data = {"one", "two", "three", "four"};
  31. * JList dataList = new JList(data);
  32. *
  33. * // The value of the JList model property is an object that provides
  34. * // a read-only view of the data. It was constructed automatically.
  35. *
  36. * for(int i = 0; i < dataList.getModel().getSize(); i++) {
  37. * System.out.println(dataList.getModel().getElementAt(i));
  38. * }
  39. *
  40. * // Create a JList that displays the superclass of JList.class.
  41. * // We store the superclasses in a java.util.Vector.
  42. *
  43. * Vector superClasses = new Vector();
  44. * Class rootClass = javax.swing.JList.class;
  45. * for(Class cls = rootClass; cls != null; cls = cls.getSuperclass()) {
  46. * superClasses.addElement(cls);
  47. * }
  48. * JList classList = new JList(superClasses);
  49. * </pre>
  50. * <p>
  51. * <code>JList</code> doesn't support scrolling directly.
  52. * To create a scrolling
  53. * list you make the <code>JList</code> the viewport view of a
  54. * <code>JScrollPane</code>. For example:
  55. * <pre>
  56. * JScrollPane scrollPane = new JScrollPane(dataList);
  57. * // Or in two steps:
  58. * JScrollPane scrollPane = new JScrollPane();
  59. * scrollPane.getViewport().setView(dataList);
  60. * </pre>
  61. * <p>
  62. * By default the <code>JList</code> selection model allows any
  63. * combination of items to be selected at a time, using the constant
  64. * <code>MULTIPLE_INTERVAL_SELECTION</code>.
  65. * The selection state is actually managed
  66. * by a separate delegate object, an instance of
  67. * <code>ListSelectionModel</code>.
  68. * However <code>JList</code> provides convenient properties for
  69. * managing the selection.
  70. * <pre>
  71. * String[] data = {"one", "two", "three", "four"};
  72. * JList dataList = new JList(data);
  73. *
  74. * dataList.setSelectedIndex(1); // select "two"
  75. * dataList.getSelectedValue(); // returns "two"
  76. * </pre>
  77. * <p>
  78. * The contents of a <code>JList</code> can be dynamic,
  79. * in other words, the list elements can
  80. * change value and the size of the list can change after the
  81. * <code>JList</code> has
  82. * been created. The <code>JList</code> observes changes in its model with a
  83. * <code>swing.event.ListDataListener</code> implementation. A correct
  84. * implementation of <code>ListModel</code> notifies
  85. * it's listeners each time a change occurs. The changes are
  86. * characterized by a <code>swing.event.ListDataEvent</code>, which identifies
  87. * the range of list indices that have been modified, added, or removed.
  88. * Simple dynamic-content <code>JList</code> applications can use the
  89. * <code>DefaultListModel</code> class to store list elements. This class
  90. * implements the <code>ListModel</code> interface and provides the
  91. * <code>java.util.Vector</code> API as well. Applications that need to
  92. * provide custom <code>ListModel</code> implementations can subclass
  93. * <code>AbstractListModel</code>, which provides basic
  94. * <code>ListDataListener</code> support. For example:
  95. * <pre>
  96. * // This list model has about 2^16 elements. Enjoy scrolling.
  97. *
  98. * <a name="prototype_example">
  99. * ListModel bigData = new AbstractListModel() {
  100. * public int getSize() { return Short.MAX_VALUE; }
  101. * public Object getElementAt(int index) { return "Index " + index; }
  102. * };
  103. *
  104. * JList bigDataList = new JList(bigData);
  105. *
  106. * // We don't want the JList implementation to compute the width
  107. * // or height of all of the list cells, so we give it a string
  108. * // that's as big as we'll need for any cell. It uses this to
  109. * // compute values for the fixedCellWidth and fixedCellHeight
  110. * // properties.
  111. *
  112. * bigDataList.setPrototypeCellValue("Index 1234567890");
  113. * </pre>
  114. * <p>
  115. * <code>JList</code> uses a <code>java.awt.Component</code>, provided by
  116. * a delegate called the
  117. * <code>cellRendererer</code>, to paint the visible cells in the list.
  118. * The cell renderer component is used like a "rubber stamp" to paint
  119. * each visible row. Each time the <code>JList</code> needs to paint a cell
  120. * it asks the cell renderer for the component, moves it into place
  121. * using <code>setBounds()</code> and then draws it by calling its paint method.
  122. * The default cell renderer uses a <code>JLabel</code> component to render
  123. * the string value of each component. You can substitute your
  124. * own cell renderer, using code like this:
  125. * <pre>
  126. * // Display an icon and a string for each object in the list.
  127. *
  128. * <a name="cellrenderer_example">
  129. * class MyCellRenderer extends JLabel implements ListCellRenderer {
  130. * final static ImageIcon longIcon = new ImageIcon("long.gif");
  131. * final static ImageIcon shortIcon = new ImageIcon("short.gif");
  132. *
  133. * // This is the only method defined by ListCellRenderer.
  134. * // We just reconfigure the JLabel each time we're called.
  135. *
  136. * public Component getListCellRendererComponent(
  137. * JList list,
  138. * Object value, // value to display
  139. * int index, // cell index
  140. * boolean isSelected, // is the cell selected
  141. * boolean cellHasFocus) // the list and the cell have the focus
  142. * {
  143. * String s = value.toString();
  144. * setText(s);
  145. * setIcon((s.length() > 10) ? longIcon : shortIcon);
  146. * if (isSelected) {
  147. * setBackground(list.getSelectionBackground());
  148. * setForeground(list.getSelectionForeground());
  149. * }
  150. * else {
  151. * setBackground(list.getBackground());
  152. * setForeground(list.getForeground());
  153. * }
  154. * setEnabled(list.isEnabled());
  155. * setFont(list.getFont());
  156. * setOpaque(true);
  157. * return this;
  158. * }
  159. * }
  160. *
  161. * String[] data = {"one", "two", "three", "four"};
  162. * JList dataList = new JList(data);
  163. * dataList.setCellRenderer(new MyCellRenderer());
  164. * </pre>
  165. * <p>
  166. * <code>JList</code> doesn't provide any special support for handling double or
  167. * triple (or N) mouse clicks however it's easy to handle them using
  168. * a <code>MouseListener</code>. Use the <code>JList</code> method
  169. * <code>locationToIndex()</code> to
  170. * determine what cell was clicked. For example:
  171. * <pre>
  172. * final JList list = new JList(dataModel);
  173. * MouseListener mouseListener = new MouseAdapter() {
  174. * public void mouseClicked(MouseEvent e) {
  175. * if (e.getClickCount() == 2) {
  176. * int index = list.locationToIndex(e.getPoint());
  177. * System.out.println("Double clicked on Item " + index);
  178. * }
  179. * }
  180. * };
  181. * list.addMouseListener(mouseListener);
  182. * </pre>
  183. * Note that in this example the <code>dataList</code> is <code>final</code>
  184. * because it's referred to by the anonymous <code>MouseListener</code> class.
  185. * <p>
  186. * <strong>Warning:</strong>
  187. * Serialized objects of this class will not be compatible with
  188. * future Swing releases. The current serialization support is
  189. * appropriate for short term storage or RMI between applications running
  190. * the same version of Swing. As of 1.4, support for long term storage
  191. * of all JavaBeans<sup><font size="-2">TM</font></sup>
  192. * has been added to the <code>java.beans</code> package.
  193. * Please see {@link java.beans.XMLEncoder}.
  194. *
  195. * <p>
  196. * See <a href="http://java.sun.com/docs/books/tutorial/uiswing/components/list.html">How to Use Lists</a>
  197. * in <a href="http://java.sun.com/Series/Tutorial/index.html"><em>The Java Tutorial</em></a>
  198. * for further documentation.
  199. * Also see the article <a href="http://java.sun.com/products/jfc/tsc/tech_topics/jlist_1/jlist.html">Advanced JList Programming</a>
  200. * in <a href="http://java.sun.com/products/jfc/tsc"><em>The Swing Connection</em></a>.
  201. * <p>
  202. * @see ListModel
  203. * @see AbstractListModel
  204. * @see DefaultListModel
  205. * @see ListSelectionModel
  206. * @see DefaultListSelectionModel
  207. * @see ListCellRenderer
  208. *
  209. * @beaninfo
  210. * attribute: isContainer false
  211. * description: A component which allows for the selection of one or more objects from a list.
  212. *
  213. * @version 1.112 05/05/04
  214. * @author Hans Muller
  215. */
  216. public class JList extends JComponent implements Scrollable, Accessible
  217. {
  218. /**
  219. * @see #getUIClassID
  220. * @see #readObject
  221. */
  222. private static final String uiClassID = "ListUI";
  223. /**
  224. * Indicates the default layout: one column of cells.
  225. * @see #setLayoutOrientation
  226. * @since 1.4
  227. */
  228. public static final int VERTICAL = 0;
  229. /**
  230. * Indicates "newspaper style" layout with the cells flowing vertically
  231. * then horizontally.
  232. * @see #setLayoutOrientation
  233. * @since 1.4
  234. */
  235. public static final int VERTICAL_WRAP = 1;
  236. /**
  237. * Indicates "newspaper style" with the cells flowing horizontally
  238. * then vertically.
  239. * @see #setLayoutOrientation
  240. * @since 1.4
  241. */
  242. public static final int HORIZONTAL_WRAP = 2;
  243. private int fixedCellWidth = -1;
  244. private int fixedCellHeight = -1;
  245. private int horizontalScrollIncrement = -1;
  246. private Object prototypeCellValue;
  247. private int visibleRowCount = 8;
  248. private Color selectionForeground;
  249. private Color selectionBackground;
  250. private boolean dragEnabled;
  251. private ListSelectionModel selectionModel;
  252. private ListModel dataModel;
  253. private ListCellRenderer cellRenderer;
  254. private ListSelectionListener selectionListener;
  255. /**
  256. * How to layout the cells, defaults to <code>VERTICAL</code>.
  257. */
  258. private int layoutOrientation;
  259. /**
  260. * Constructs a <code>JList</code> that displays the elements in the
  261. * specified, non-<code>null</code> model.
  262. * All <code>JList</code> constructors delegate to this one.
  263. *
  264. * @param dataModel the data model for this list
  265. * @exception IllegalArgumentException if <code>dataModel</code>
  266. * is <code>null</code>
  267. */
  268. public JList(ListModel dataModel)
  269. {
  270. if (dataModel == null) {
  271. throw new IllegalArgumentException("dataModel must be non null");
  272. }
  273. // Register with the ToolTipManager so that tooltips from the
  274. // renderer show through.
  275. ToolTipManager toolTipManager = ToolTipManager.sharedInstance();
  276. toolTipManager.registerComponent(this);
  277. layoutOrientation = VERTICAL;
  278. this.dataModel = dataModel;
  279. selectionModel = createSelectionModel();
  280. setAutoscrolls(true);
  281. setOpaque(true);
  282. updateUI();
  283. }
  284. /**
  285. * Constructs a <code>JList</code> that displays the elements in
  286. * the specified array. This constructor just delegates to the
  287. * <code>ListModel</code> constructor.
  288. *
  289. * @param listData the array of Objects to be loaded into the data model
  290. */
  291. public JList(final Object[] listData)
  292. {
  293. this (
  294. new AbstractListModel() {
  295. public int getSize() { return listData.length; }
  296. public Object getElementAt(int i) { return listData[i]; }
  297. }
  298. );
  299. }
  300. /**
  301. * Constructs a <code>JList</code> that displays the elements in
  302. * the specified <code>Vector</code>. This constructor just
  303. * delegates to the <code>ListModel</code> constructor.
  304. *
  305. * @param listData the <code>Vector</code> to be loaded into the
  306. * data model
  307. */
  308. public JList(final Vector<?> listData) {
  309. this (
  310. new AbstractListModel() {
  311. public int getSize() { return listData.size(); }
  312. public Object getElementAt(int i) { return listData.elementAt(i); }
  313. }
  314. );
  315. }
  316. /**
  317. * Constructs a <code>JList</code> with an empty model.
  318. */
  319. public JList() {
  320. this (
  321. new AbstractListModel() {
  322. public int getSize() { return 0; }
  323. public Object getElementAt(int i) { return "No Data Model"; }
  324. }
  325. );
  326. }
  327. /**
  328. * Returns the look and feel (L&F) object that renders this component.
  329. *
  330. * @return the <code>ListUI</code> object that renders this component
  331. */
  332. public ListUI getUI() {
  333. return (ListUI)ui;
  334. }
  335. /**
  336. * Sets the look and feel (L&F) object that renders this component.
  337. *
  338. * @param ui the <code>ListUI</code> L&F object
  339. * @see UIDefaults#getUI
  340. * @beaninfo
  341. * bound: true
  342. * hidden: true
  343. * attribute: visualUpdate true
  344. * description: The UI object that implements the Component's LookAndFeel.
  345. */
  346. public void setUI(ListUI ui) {
  347. super.setUI(ui);
  348. }
  349. /**
  350. * Resets the UI property with the value from the current look and feel.
  351. *
  352. * @see UIManager#getUI
  353. */
  354. public void updateUI() {
  355. setUI((ListUI)UIManager.getUI(this));
  356. invalidate();
  357. }
  358. /**
  359. * Returns the suffix used to construct the name of the look and feel
  360. * (L&F) class used to render this component.
  361. *
  362. * @return the string "ListUI"
  363. * @see JComponent#getUIClassID
  364. * @see UIDefaults#getUI
  365. */
  366. public String getUIClassID() {
  367. return uiClassID;
  368. }
  369. /* -----private-----
  370. * This method is called by setPrototypeCellValue and setCellRenderer
  371. * to update the fixedCellWidth and fixedCellHeight properties from the
  372. * current value of prototypeCellValue (if it's non null).
  373. * <p>
  374. * This method sets fixedCellWidth and fixedCellHeight but does <b>not</b>
  375. * generate PropertyChangeEvents for them.
  376. *
  377. * @see #setPrototypeCellValue
  378. * @see #setCellRenderer
  379. */
  380. private void updateFixedCellSize()
  381. {
  382. ListCellRenderer cr = getCellRenderer();
  383. Object value = getPrototypeCellValue();
  384. if ((cr != null) && (value != null)) {
  385. Component c = cr.getListCellRendererComponent(this, value, 0, false, false);
  386. /* The ListUI implementation will add Component c to its private
  387. * CellRendererPane however we can't assume that's already
  388. * been done here. So we temporarily set the one "inherited"
  389. * property that may affect the renderer components preferred size:
  390. * its font.
  391. */
  392. Font f = c.getFont();
  393. c.setFont(getFont());
  394. Dimension d = c.getPreferredSize();
  395. fixedCellWidth = d.width;
  396. fixedCellHeight = d.height;
  397. c.setFont(f);
  398. }
  399. }
  400. /**
  401. * Returns the cell width of the "prototypical cell" -- a cell used
  402. * for the calculation of cell widths, because it has the same value
  403. * as all other list items.
  404. *
  405. * @return the value of the <code>prototypeCellValue</code> property
  406. * @see #setPrototypeCellValue
  407. */
  408. public Object getPrototypeCellValue() {
  409. return prototypeCellValue;
  410. }
  411. /**
  412. * Computes the <code>fixedCellWidth</code> and
  413. * <code>fixedCellHeight</code> properties
  414. * by configuring the <code>cellRenderer</code> to index equals
  415. * zero for the specified value and then computing the renderer
  416. * component's preferred size. These properties are useful when the
  417. * list is too long to allow <code>JList</code> to compute the
  418. * width/height of each cell and there is a single cell value that is
  419. * known to occupy as much space as any of the others.
  420. * <p>
  421. * Note that we do set the <code>fixedCellWidth</code> and
  422. * <code>fixedCellHeight</code> properties here but only a
  423. * <code>prototypeCellValue PropertyChangeEvent</code> is fired.
  424. * <p>
  425. * To see an example which sets this property,
  426. * see the <a href = #prototype_example>class description</a> above.
  427. * <p>
  428. * The default value of this property is <code>null</code>.
  429. * <p>
  430. * This is a JavaBeans bound property.
  431. *
  432. * @param prototypeCellValue the value on which to base
  433. * <code>fixedCellWidth</code> and
  434. * <code>fixedCellHeight</code>
  435. * @see #getPrototypeCellValue
  436. * @see #setFixedCellWidth
  437. * @see #setFixedCellHeight
  438. * @see JComponent#addPropertyChangeListener
  439. * @beaninfo
  440. * bound: true
  441. * attribute: visualUpdate true
  442. * description: The cell prototype value, used to compute cell width and height.
  443. */
  444. public void setPrototypeCellValue(Object prototypeCellValue) {
  445. Object oldValue = this.prototypeCellValue;
  446. this.prototypeCellValue = prototypeCellValue;
  447. /* If the cellRenderer has changed and prototypeCellValue
  448. * was set, then recompute fixedCellWidth and fixedCellHeight.
  449. */
  450. if ((prototypeCellValue != null) && !prototypeCellValue.equals(oldValue)) {
  451. updateFixedCellSize();
  452. }
  453. firePropertyChange("prototypeCellValue", oldValue, prototypeCellValue);
  454. }
  455. /**
  456. * Returns the fixed cell width value -- the value specified by setting
  457. * the <code>fixedCellWidth</code> property, rather than that calculated
  458. * from the list elements.
  459. *
  460. * @return the fixed cell width
  461. * @see #setFixedCellWidth
  462. */
  463. public int getFixedCellWidth() {
  464. return fixedCellWidth;
  465. }
  466. /**
  467. * Sets the width of every cell in the list. If <code>width</code> is -1,
  468. * cell widths are computed by applying <code>getPreferredSize</code>
  469. * to the <code>cellRenderer</code> component for each list element.
  470. * <p>
  471. * The default value of this property is -1.
  472. * <p>
  473. * This is a JavaBeans bound property.
  474. *
  475. * @param width the width, in pixels, for all cells in this list
  476. * @see #getPrototypeCellValue
  477. * @see #setFixedCellWidth
  478. * @see JComponent#addPropertyChangeListener
  479. * @beaninfo
  480. * bound: true
  481. * attribute: visualUpdate true
  482. * description: Defines a fixed cell width when greater than zero.
  483. */
  484. public void setFixedCellWidth(int width) {
  485. int oldValue = fixedCellWidth;
  486. fixedCellWidth = width;
  487. firePropertyChange("fixedCellWidth", oldValue, fixedCellWidth);
  488. }
  489. /**
  490. * Returns the fixed cell height value -- the value specified by setting
  491. * the <code>fixedCellHeight</code> property,
  492. * rather than that calculated from the list elements.
  493. *
  494. * @return the fixed cell height, in pixels
  495. * @see #setFixedCellHeight
  496. */
  497. public int getFixedCellHeight() {
  498. return fixedCellHeight;
  499. }
  500. /**
  501. * Sets the height of every cell in the list. If <code>height</code>
  502. * is -1, cell
  503. * heights are computed by applying <code>getPreferredSize</code>
  504. * to the <code>cellRenderer</code> component for each list element.
  505. * <p>
  506. * The default value of this property is -1.
  507. * <p>
  508. * This is a JavaBeans bound property.
  509. *
  510. * @param height an integer giving the height, in pixels, for all cells
  511. * in this list
  512. * @see #getPrototypeCellValue
  513. * @see #setFixedCellWidth
  514. * @see JComponent#addPropertyChangeListener
  515. * @beaninfo
  516. * bound: true
  517. * attribute: visualUpdate true
  518. * description: Defines a fixed cell height when greater than zero.
  519. */
  520. public void setFixedCellHeight(int height) {
  521. int oldValue = fixedCellHeight;
  522. fixedCellHeight = height;
  523. firePropertyChange("fixedCellHeight", oldValue, fixedCellHeight);
  524. }
  525. /**
  526. * Returns the object that renders the list items.
  527. *
  528. * @return the <code>ListCellRenderer</code>
  529. * @see #setCellRenderer
  530. */
  531. public ListCellRenderer getCellRenderer() {
  532. return cellRenderer;
  533. }
  534. /**
  535. * Sets the delegate that's used to paint each cell in the list. If
  536. * <code>prototypeCellValue</code> was set then the
  537. * <code>fixedCellWidth</code> and <code>fixedCellHeight</code>
  538. * properties are set as well. Only one <code>PropertyChangeEvent</code>
  539. * is generated however - for the <code>cellRenderer</code> property.
  540. * <p>
  541. * The default value of this property is provided by the ListUI
  542. * delegate, i.e. by the look and feel implementation.
  543. * <p>
  544. * To see an example which sets the cell renderer,
  545. * see the <a href = #cellrenderer_example>class description</a> above.
  546. * <p>
  547. * This is a JavaBeans bound property.
  548. *
  549. * @param cellRenderer the <code>ListCellRenderer</code>
  550. * that paints list cells
  551. * @see #getCellRenderer
  552. * @beaninfo
  553. * bound: true
  554. * attribute: visualUpdate true
  555. * description: The component used to draw the cells.
  556. */
  557. public void setCellRenderer(ListCellRenderer cellRenderer) {
  558. ListCellRenderer oldValue = this.cellRenderer;
  559. this.cellRenderer = cellRenderer;
  560. /* If the cellRenderer has changed and prototypeCellValue
  561. * was set, then recompute fixedCellWidth and fixedCellHeight.
  562. */
  563. if ((cellRenderer != null) && !cellRenderer.equals(oldValue)) {
  564. updateFixedCellSize();
  565. }
  566. firePropertyChange("cellRenderer", oldValue, cellRenderer);
  567. }
  568. /**
  569. * Returns the selection foreground color.
  570. *
  571. * @return the <code>Color</code> object for the foreground property
  572. * @see #setSelectionForeground
  573. * @see #setSelectionBackground
  574. */
  575. public Color getSelectionForeground() {
  576. return selectionForeground;
  577. }
  578. /**
  579. * Sets the foreground color for selected cells. Cell renderers
  580. * can use this color to render text and graphics for selected
  581. * cells.
  582. * <p>
  583. * The default value of this property is defined by the look
  584. * and feel implementation.
  585. * <p>
  586. * This is a JavaBeans bound property.
  587. *
  588. * @param selectionForeground the <code>Color</code> to use in the foreground
  589. * for selected list items
  590. * @see #getSelectionForeground
  591. * @see #setSelectionBackground
  592. * @see #setForeground
  593. * @see #setBackground
  594. * @see #setFont
  595. * @beaninfo
  596. * bound: true
  597. * attribute: visualUpdate true
  598. * description: The foreground color of selected cells.
  599. */
  600. public void setSelectionForeground(Color selectionForeground) {
  601. Color oldValue = this.selectionForeground;
  602. this.selectionForeground = selectionForeground;
  603. firePropertyChange("selectionForeground", oldValue, selectionForeground);
  604. }
  605. /**
  606. * Returns the background color for selected cells.
  607. *
  608. * @return the <code>Color</code> used for the background of
  609. * selected list items
  610. * @see #setSelectionBackground
  611. * @see #setSelectionForeground
  612. */
  613. public Color getSelectionBackground() {
  614. return selectionBackground;
  615. }
  616. /**
  617. * Sets the background color for selected cells. Cell renderers
  618. * can use this color to the fill selected cells.
  619. * <p>
  620. * The default value of this property is defined by the look
  621. * and feel implementation.
  622. * <p>
  623. * This is a JavaBeans bound property.
  624. *
  625. * @param selectionBackground the <code>Color</code> to use for the
  626. * background of selected cells
  627. * @see #getSelectionBackground
  628. * @see #setSelectionForeground
  629. * @see #setForeground
  630. * @see #setBackground
  631. * @see #setFont
  632. * @beaninfo
  633. * bound: true
  634. * attribute: visualUpdate true
  635. * description: The background color of selected cells.
  636. */
  637. public void setSelectionBackground(Color selectionBackground) {
  638. Color oldValue = this.selectionBackground;
  639. this.selectionBackground = selectionBackground;
  640. firePropertyChange("selectionBackground", oldValue, selectionBackground);
  641. }
  642. /**
  643. * Returns the preferred number of visible rows.
  644. *
  645. * @return an integer indicating the preferred number of rows to display
  646. * without using a scroll bar
  647. * @see #setVisibleRowCount
  648. */
  649. public int getVisibleRowCount() {
  650. return visibleRowCount;
  651. }
  652. /**
  653. * Sets the preferred number of rows in the list that can be displayed
  654. * without a scrollbar, as determined by the nearest
  655. * <code>JViewport</code> ancestor, if any.
  656. * The value of this property only affects the value of
  657. * the <code>JList</code>'s <code>preferredScrollableViewportSize</code>.
  658. * <p>
  659. * The default value of this property is 8.
  660. * <p>
  661. * This is a JavaBeans bound property.
  662. *
  663. * @param visibleRowCount an integer specifying the preferred number of
  664. * visible rows
  665. * @see #getVisibleRowCount
  666. * @see JComponent#getVisibleRect
  667. * @see JViewport
  668. * @beaninfo
  669. * bound: true
  670. * attribute: visualUpdate true
  671. * description: The preferred number of cells that can be displayed without a scroll bar.
  672. */
  673. public void setVisibleRowCount(int visibleRowCount) {
  674. int oldValue = this.visibleRowCount;
  675. this.visibleRowCount = Math.max(0, visibleRowCount);
  676. firePropertyChange("visibleRowCount", oldValue, visibleRowCount);
  677. }
  678. /**
  679. * Returns <code>JList.VERTICAL</code> if the layout is a single
  680. * column of cells, or <code>JList.VERTICAL_WRAP</code> if the layout
  681. * is "newspaper style" with the content flowing vertically then
  682. * horizontally or <code>JList.HORIZONTAL_WRAP</code> if the layout is
  683. * "newspaper style" with the content flowing horizontally then
  684. * vertically.
  685. *
  686. * @return the value of the layoutOrientation property
  687. * @see #setLayoutOrientation
  688. * @since 1.4
  689. */
  690. public int getLayoutOrientation() {
  691. return layoutOrientation;
  692. }
  693. /**
  694. * Defines the way list cells are layed out. Consider a <code>JList</code>
  695. * with four cells, this can be layed out in one of the following ways:
  696. * <pre>
  697. * 0
  698. * 1
  699. * 2
  700. * 3
  701. * </pre>
  702. * <pre>
  703. * 0 1
  704. * 2 3
  705. * </pre>
  706. * <pre>
  707. * 0 2
  708. * 1 3
  709. * </pre>
  710. * <p>
  711. * These correspond to the following values:
  712. *
  713. * <table border="1"
  714. * summary="Describes layouts VERTICAL, HORIZONTAL_WRAP, and VERTICAL_WRAP">
  715. * <tr><th><p align="left">Value</p></th><th><p align="left">Description</p></th></tr>
  716. * <tr><td><code>JList.VERTICAL</code>
  717. * <td>The cells should be layed out vertically in one column.
  718. * <tr><td><code>JList.HORIZONTAL_WRAP</code>
  719. * <td>The cells should be layed out horizontally, wrapping to
  720. * a new row as necessary. The number
  721. * of rows to use will either be defined by
  722. * <code>getVisibleRowCount</code> if > 0, otherwise the
  723. * number of rows will be determined by the width of the
  724. * <code>JList</code>.
  725. * <tr><td><code>JList.VERTICAL_WRAP</code>
  726. * <td>The cells should be layed out vertically, wrapping to a
  727. * new column as necessary. The number
  728. * of rows to use will either be defined by
  729. * <code>getVisibleRowCount</code> if > 0, otherwise the
  730. * number of rows will be determined by the height of the
  731. * <code>JList</code>.
  732. * </table>
  733. * The default value of this property is <code>JList.VERTICAL</code>.
  734. * <p>
  735. * This will throw an <code>IllegalArgumentException</code> if
  736. * <code>layoutOrientation</code> is not one of
  737. * <code>JList.HORIZONTAL_WRAP</code> or <code>JList.VERTICAL</code> or
  738. * <code>JList.VERTICAL_WRAP</code>
  739. *
  740. * @param layoutOrientation New orientation, one of
  741. * <code>JList.HORIZONTAL_WRAP</code>, <code>JList.VERTICAL</code>
  742. * or <code>JList.VERTICAL_WRAP</code>.
  743. * @see #getLayoutOrientation
  744. * @see #setVisibleRowCount
  745. * @see #getScrollableTracksViewportHeight
  746. * @since 1.4
  747. * @beaninfo
  748. * bound: true
  749. * attribute: visualUpdate true
  750. * description: Defines the way list cells are layed out.
  751. * enum: VERTICAL JList.VERTICAL
  752. * HORIZONTAL_WRAP JList.HORIZONTAL_WRAP
  753. * VERTICAL_WRAP JList.VERTICAL_WRAP
  754. */
  755. public void setLayoutOrientation(int layoutOrientation) {
  756. int oldValue = this.layoutOrientation;
  757. switch (layoutOrientation) {
  758. case VERTICAL:
  759. case VERTICAL_WRAP:
  760. case HORIZONTAL_WRAP:
  761. this.layoutOrientation = layoutOrientation;
  762. firePropertyChange("layoutOrientation", oldValue, layoutOrientation);
  763. break;
  764. default:
  765. throw new IllegalArgumentException("layoutOrientation must be one of: VERTICAL, HORIZONTAL_WRAP or VERTICAL_WRAP");
  766. }
  767. }
  768. /**
  769. * Returns the index of the first visible cell. The cell considered
  770. * to be "first" depends on the list's <code>componentOrientation</code>
  771. * property. If the orientation is horizontal left-to-right, then
  772. * the first visible cell is in the list's upper-left corner. If
  773. * the orientation is horizontal right-to-left, then the first
  774. * visible cell is in the list's upper-right corner. If nothing is
  775. * visible or the list is empty, a -1 is returned. Note that the returned
  776. * cell may only be partially visible.
  777. *
  778. * @return the index of the first visible cell
  779. * @see #getLastVisibleIndex
  780. * @see JComponent#getVisibleRect
  781. */
  782. public int getFirstVisibleIndex() {
  783. Rectangle r = getVisibleRect();
  784. int first;
  785. if (this.getComponentOrientation().isLeftToRight()) {
  786. first = locationToIndex(r.getLocation());
  787. } else {
  788. first = locationToIndex(new Point((r.x + r.width) - 1, r.y));
  789. }
  790. if (first != -1) {
  791. Rectangle bounds = getCellBounds(first, first);
  792. if (bounds != null) {
  793. SwingUtilities.computeIntersection(r.x, r.y, r.width, r.height, bounds);
  794. if (bounds.width == 0 || bounds.height == 0) {
  795. first = -1;
  796. }
  797. }
  798. }
  799. return first;
  800. }
  801. /**
  802. * Returns the index of the last visible cell. The cell considered
  803. * to be "last" depends on the list's <code>componentOrientation</code>
  804. * property. If the orientation is horizontal left-to-right, then
  805. * the last visible cell is in the JList's lower-right corner. If
  806. * the orientation is horizontal right-to-left, then the last visible
  807. * cell is in the JList's lower-left corner. If nothing is visible
  808. * or the list is empty, a -1 is returned. Note that the returned
  809. * cell may only be partially visible.
  810. *
  811. * @return the index of the last visible cell
  812. * @see #getFirstVisibleIndex
  813. * @see JComponent#getVisibleRect
  814. */
  815. public int getLastVisibleIndex() {
  816. boolean leftToRight = this.getComponentOrientation().isLeftToRight();
  817. Rectangle r = getVisibleRect();
  818. Point lastPoint;
  819. if (leftToRight) {
  820. lastPoint = new Point((r.x + r.width) - 1, (r.y + r.height) - 1);
  821. } else {
  822. lastPoint = new Point(r.x, (r.y + r.height) - 1);
  823. }
  824. int location = locationToIndex(lastPoint);
  825. if (location != -1) {
  826. Rectangle bounds = getCellBounds(location, location);
  827. if (bounds != null) {
  828. SwingUtilities.computeIntersection(r.x, r.y, r.width, r.height, bounds);
  829. if (bounds.width == 0 || bounds.height == 0) {
  830. // Try the lower left corner, and then go across checking
  831. // each cell.
  832. Point visibleLL = new Point(r.x, lastPoint.y);
  833. int last;
  834. int llIndex = -1;
  835. int lrIndex = location;
  836. location = -1;
  837. do {
  838. last = llIndex;
  839. llIndex = locationToIndex(visibleLL);
  840. if (llIndex != -1) {
  841. bounds = getCellBounds(llIndex, llIndex);
  842. if (llIndex != lrIndex && bounds != null &&
  843. bounds.contains(visibleLL)) {
  844. location = llIndex;
  845. visibleLL.x = bounds.x + bounds.width + 1;
  846. if (visibleLL.x >= lastPoint.x) {
  847. // Past visible region, bail.
  848. last = llIndex;
  849. }
  850. }
  851. else {
  852. last = llIndex;
  853. }
  854. }
  855. } while (llIndex != -1 && last != llIndex);
  856. }
  857. }
  858. }
  859. return location;
  860. }
  861. /**
  862. * Scrolls the viewport to make the specified cell completely visible.
  863. * Note, for this method to work, the <code>JList</code> must be
  864. * displayed within a <code>JViewport</code>.
  865. *
  866. * @param index the index of the cell to make visible
  867. * @see JComponent#scrollRectToVisible
  868. * @see #getVisibleRect
  869. */
  870. public void ensureIndexIsVisible(int index) {
  871. Rectangle cellBounds = getCellBounds(index, index);
  872. if (cellBounds != null) {
  873. scrollRectToVisible(cellBounds);
  874. }
  875. }
  876. /**
  877. * Sets the <code>dragEnabled</code> property,
  878. * which must be <code>true</code> to enable
  879. * automatic drag handling (the first part of drag and drop)
  880. * on this component.
  881. * The <code>transferHandler</code> property needs to be set
  882. * to a non-<code>null</code> value for the drag to do
  883. * anything. The default value of the <code>dragEnabled</code>
  884. * property
  885. * is <code>false</code>.
  886. *
  887. * <p>
  888. *
  889. * When automatic drag handling is enabled,
  890. * most look and feels begin a drag-and-drop operation
  891. * whenever the user presses the mouse button over a selection
  892. * and then moves the mouse a few pixels.
  893. * Setting this property to <code>true</code>
  894. * can therefore have a subtle effect on
  895. * how selections behave.
  896. *
  897. * <p>
  898. *
  899. * Some look and feels might not support automatic drag and drop;
  900. * they will ignore this property. You can work around such
  901. * look and feels by modifying the component
  902. * to directly call the <code>exportAsDrag</code> method of a
  903. * <code>TransferHandler</code>.
  904. *
  905. * @param b the value to set the <code>dragEnabled</code> property to
  906. * @exception HeadlessException if
  907. * <code>b</code> is <code>true</code> and
  908. * <code>GraphicsEnvironment.isHeadless()</code>
  909. * returns <code>true</code>
  910. * @see java.awt.GraphicsEnvironment#isHeadless
  911. * @see #getDragEnabled
  912. * @see #setTransferHandler
  913. * @see TransferHandler
  914. * @since 1.4
  915. *
  916. * @beaninfo
  917. * description: determines whether automatic drag handling is enabled
  918. * bound: false
  919. */
  920. public void setDragEnabled(boolean b) {
  921. if (b && GraphicsEnvironment.isHeadless()) {
  922. throw new HeadlessException();
  923. }
  924. dragEnabled = b;
  925. }
  926. /**
  927. * Gets the <code>dragEnabled</code> property.
  928. *
  929. * @return the value of the <code>dragEnabled</code> property
  930. * @see #setDragEnabled
  931. * @since 1.4
  932. */
  933. public boolean getDragEnabled() {
  934. return dragEnabled;
  935. }
  936. /**
  937. * Returns the next list element that starts with
  938. * a prefix.
  939. *
  940. * @param prefix the string to test for a match
  941. * @param startIndex the index for starting the search
  942. * @param bias the search direction, either
  943. * Position.Bias.Forward or Position.Bias.Backward.
  944. * @return the index of the next list element that
  945. * starts with the prefix; otherwise -1
  946. * @exception IllegalArgumentException if prefix is null
  947. * or startIndex is out of bounds
  948. * @since 1.4
  949. */
  950. public int getNextMatch(String prefix, int startIndex, Position.Bias bias) {
  951. ListModel model = getModel();
  952. int max = model.getSize();
  953. if (prefix == null) {
  954. throw new IllegalArgumentException();
  955. }
  956. if (startIndex < 0 || startIndex >= max) {
  957. throw new IllegalArgumentException();
  958. }
  959. prefix = prefix.toUpperCase();
  960. // start search from the next element after the selected element
  961. int increment = (bias == Position.Bias.Forward) ? 1 : -1;
  962. int index = startIndex;
  963. do {
  964. Object o = model.getElementAt(index);
  965. if (o != null) {
  966. String string;
  967. if (o instanceof String) {
  968. string = ((String)o).toUpperCase();
  969. }
  970. else {
  971. string = o.toString();
  972. if (string != null) {
  973. string = string.toUpperCase();
  974. }
  975. }
  976. if (string != null && string.startsWith(prefix)) {
  977. return index;
  978. }
  979. }
  980. index = (index + increment + max) % max;
  981. } while (index != startIndex);
  982. return -1;
  983. }
  984. /**
  985. * Overrides <code>JComponent</code>'s <code>getToolTipText</code>
  986. * method in order to allow the renderer's tips to be used
  987. * if it has text set.
  988. * <p>
  989. * <bold>Note:</bold> For <code>JList</code> to properly display
  990. * tooltips of its renderers
  991. * <code>JList</code> must be a registered component with the
  992. * <code>ToolTipManager</code>.
  993. * This is done automatically in the constructor,
  994. * but if at a later point <code>JList</code> is told
  995. * <code>setToolTipText(null)</code> it will unregister the list
  996. * component, and no tips from renderers will display anymore.
  997. *
  998. * @see JComponent#getToolTipText
  999. */
  1000. public String getToolTipText(MouseEvent event) {
  1001. if(event != null) {
  1002. Point p = event.getPoint();
  1003. int index = locationToIndex(p);
  1004. ListCellRenderer r = getCellRenderer();
  1005. Rectangle cellBounds;
  1006. if (index != -1 && r != null && (cellBounds =
  1007. getCellBounds(index, index)) != null &&
  1008. cellBounds.contains(p.x, p.y)) {
  1009. ListSelectionModel lsm = getSelectionModel();
  1010. Component rComponent = r.getListCellRendererComponent(
  1011. this, getModel().getElementAt(index), index,
  1012. lsm.isSelectedIndex(index),
  1013. (hasFocus() && (lsm.getLeadSelectionIndex() ==
  1014. index)));
  1015. if(rComponent instanceof JComponent) {
  1016. MouseEvent newEvent;
  1017. p.translate(-cellBounds.x, -cellBounds.y);
  1018. newEvent = new MouseEvent(rComponent, event.getID(),
  1019. event.getWhen(),
  1020. event.getModifiers(),
  1021. p.x, p.y, event.getClickCount(),
  1022. event.isPopupTrigger());
  1023. String tip = ((JComponent)rComponent).getToolTipText(
  1024. newEvent);
  1025. if (tip != null) {
  1026. return tip;
  1027. }
  1028. }
  1029. }
  1030. }
  1031. return super.getToolTipText();
  1032. }
  1033. /**
  1034. * --- ListUI Delegations ---
  1035. */
  1036. /**
  1037. * Convert a point in <code>JList</code> coordinates to the closest index
  1038. * of the cell at that location. To determine if the cell actually
  1039. * contains the specified location use a combination of this method and
  1040. * <code>getCellBounds</code>. Returns -1 if the model is empty.
  1041. *
  1042. * @param location the coordinates of the cell, relative to
  1043. * <code>JList</code>
  1044. * @return an integer -- the index of the cell at the given location, or -1.
  1045. */
  1046. public int locationToIndex(Point location) {
  1047. ListUI ui = getUI();
  1048. return (ui != null) ? ui.locationToIndex(this, location) : -1;
  1049. }
  1050. /**
  1051. * Returns the origin of the specified item in <code>JList</code>
  1052. * coordinates. Returns <code>null</code> if <code>index</code> isn't valid.
  1053. *
  1054. * @param index the index of the <code>JList</code> cell
  1055. * @return the origin of the index'th cell
  1056. */
  1057. public Point indexToLocation(int index) {
  1058. ListUI ui = getUI();
  1059. return (ui != null) ? ui.indexToLocation(this, index) : null;
  1060. }
  1061. /**
  1062. * Returns the bounds of the specified range of items in <code>JList</code>
  1063. * coordinates. Returns <code>null</code> if index isn't valid.
  1064. *
  1065. * @param index0 the index of the first <code>JList</code> cell in the range
  1066. * @param index1 the index of the last <code>JList</code> cell in the range
  1067. * @return the bounds of the indexed cells in pixels
  1068. */
  1069. public Rectangle getCellBounds(int index0, int index1) {
  1070. ListUI ui = getUI();
  1071. return (ui != null) ? ui.getCellBounds(this, index0, index1) : null;
  1072. }
  1073. /**
  1074. * --- ListModel Support ---
  1075. */
  1076. /**
  1077. * Returns the data model that holds the list of items displayed
  1078. * by the <code>JList</code> component.
  1079. *
  1080. * @return the <code>ListModel</code> that provides the displayed
  1081. * list of items
  1082. * @see #setModel
  1083. */
  1084. public ListModel getModel() {
  1085. return dataModel;
  1086. }
  1087. /**
  1088. * Sets the model that represents the contents or "value" of the
  1089. * list and clears the list selection after notifying
  1090. * <code>PropertyChangeListeners</code>.
  1091. * <p>
  1092. * This is a JavaBeans bound property.
  1093. *
  1094. * @param model the <code>ListModel</code> that provides the
  1095. * list of items for display
  1096. * @exception IllegalArgumentException if <code>model</code> is
  1097. * <code>null</code>
  1098. * @see #getModel
  1099. * @beaninfo
  1100. * bound: true
  1101. * attribute: visualUpdate true
  1102. * description: The object that contains the data to be drawn by this JList.
  1103. */
  1104. public void setModel(ListModel model) {
  1105. if (model == null) {
  1106. throw new IllegalArgumentException("model must be non null");
  1107. }
  1108. ListModel oldValue = dataModel;
  1109. dataModel = model;
  1110. firePropertyChange("model", oldValue, dataModel);
  1111. clearSelection();
  1112. }
  1113. /**
  1114. * Constructs a <code>ListModel</code> from an array of objects and then
  1115. * applies <code>setModel</code> to it.
  1116. *
  1117. * @param listData an array of Objects containing the items to display
  1118. * in the list
  1119. * @see #setModel
  1120. */
  1121. public void setListData(final Object[] listData) {
  1122. setModel (
  1123. new AbstractListModel() {
  1124. public int getSize() { return listData.length; }
  1125. public Object getElementAt(int i) { return listData[i]; }
  1126. }
  1127. );
  1128. }
  1129. /**
  1130. * Constructs a <code>ListModel</code> from a <code>Vector</code> and then
  1131. * applies <code>setModel</code> to it.
  1132. *
  1133. * @param listData a <code>Vector</code> containing the items to
  1134. * display in the list
  1135. * @see #setModel
  1136. */
  1137. public void setListData(final Vector<?> listData) {
  1138. setModel (
  1139. new AbstractListModel() {
  1140. public int getSize() { return listData.size(); }
  1141. public Object getElementAt(int i) { return listData.elementAt(i); }
  1142. }
  1143. );
  1144. }
  1145. /**
  1146. * --- ListSelectionModel delegations and extensions ---
  1147. */
  1148. /**
  1149. * Returns an instance of <code>DefaultListSelectionModel</code>. This
  1150. * method is used by the constructor to initialize the
  1151. * <code>selectionModel</code> property.
  1152. *
  1153. * @return the <code>ListSelectionModel</code> used by this
  1154. * <code>JList</code>.
  1155. * @see #setSelectionModel
  1156. * @see DefaultListSelectionModel
  1157. */
  1158. protected ListSelectionModel createSelectionModel() {
  1159. return new DefaultListSelectionModel();
  1160. }
  1161. /**
  1162. * Returns the value of the current selection model. The selection
  1163. * model handles the task of making single selections, selections
  1164. * of contiguous ranges, and non-contiguous selections.
  1165. *
  1166. * @return the <code>ListSelectionModel</code> that implements
  1167. * list selections
  1168. * @see #setSelectionModel
  1169. * @see ListSelectionModel
  1170. */
  1171. public ListSelectionModel getSelectionModel() {
  1172. return selectionModel;
  1173. }
  1174. /**
  1175. * Notifies <code>JList</code> <code>ListSelectionListener</code>s that
  1176. * the selection model has changed. It's used to forward
  1177. * <code>ListSelectionEvents</code> from the <code>selectionModel</code>
  1178. * to the <code>ListSelectionListener</code>s added directly to the
  1179. * <code>JList</code>.
  1180. * @param firstIndex the first selected index
  1181. * @param lastIndex the last selected index
  1182. * @param isAdjusting true if multiple changes are being made
  1183. *
  1184. * @see #addListSelectionListener
  1185. * @see #removeListSelectionListener
  1186. * @see EventListenerList
  1187. */
  1188. protected void fireSelectionValueChanged(int firstIndex, int lastIndex,
  1189. boolean isAdjusting)
  1190. {
  1191. Object[] listeners = listenerList.getListenerList();
  1192. ListSelectionEvent e = null;
  1193. for (int i = listeners.length - 2; i >= 0; i -= 2) {
  1194. if (listeners[i] == ListSelectionListener.class) {
  1195. if (e == null) {
  1196. e = new ListSelectionEvent(this, firstIndex, lastIndex,
  1197. isAdjusting);
  1198. }
  1199. ((ListSelectionListener)listeners[i+1]).valueChanged(e);
  1200. }
  1201. }
  1202. }
  1203. /* A ListSelectionListener that forwards ListSelectionEvents from
  1204. * the selectionModel to the JList ListSelectionListeners. The
  1205. * forwarded events only differ from the originals in that their
  1206. * source is the JList instead of the selectionModel itself.
  1207. */
  1208. private class ListSelectionHandler implements ListSelectionListener, Serializable
  1209. {
  1210. public void valueChanged(ListSelectionEvent e) {
  1211. fireSelectionValueChanged(e.getFirstIndex(),
  1212. e.getLastIndex(),
  1213. e.getValueIsAdjusting());
  1214. }
  1215. }
  1216. /**
  1217. * Adds a listener to the list that's notified each time a change
  1218. * to the selection occurs. Listeners added directly to the
  1219. * <code>JList</code>
  1220. * will have their <code>ListSelectionEvent.getSource() ==
  1221. * this JList</code>
  1222. * (instead of the <code>ListSelectionModel</code>).
  1223. *
  1224. * @param listener the <code>ListSelectionListener</code> to add
  1225. * @see #getSelectionModel
  1226. * @see #getListSelectionListeners
  1227. */
  1228. public void addListSelectionListener(ListSelectionListener listener)
  1229. {
  1230. if (selectionListener == null) {
  1231. selectionListener = new ListSelectionHandler();
  1232. getSelectionModel().addListSelectionListener(selectionListener);
  1233. }
  1234. listenerList.add(ListSelectionListener.class, listener);
  1235. }
  1236. /**
  1237. * Removes a listener from the list that's notified each time a
  1238. * change to the selection occurs.
  1239. *
  1240. * @param listener the <code>ListSelectionListener</code> to remove
  1241. * @see #addListSelectionListener
  1242. * @see #getSelectionModel
  1243. */
  1244. public void removeListSelectionListener(ListSelectionListener listener) {
  1245. listenerList.remove(ListSelectionListener.class, listener);
  1246. }
  1247. /**
  1248. * Returns an array of all the <code>ListSelectionListener</code>s added
  1249. * to this JList with addListSelectionListener().
  1250. *
  1251. * @return all of the <code>ListSelectionListener</code>s added or an empty
  1252. * array if no listeners have been added
  1253. * @see #addListSelectionListener
  1254. * @since 1.4
  1255. */
  1256. public ListSelectionListener[] getListSelectionListeners() {
  1257. return (ListSelectionListener[])listenerList.getListeners(
  1258. ListSelectionListener.class);
  1259. }
  1260. /**
  1261. * Sets the <code>selectionModel</code> for the list to a
  1262. * non-<code>null</code> <code>ListSelectionModel</code>
  1263. * implementation. The selection model handles the task of making single
  1264. * selections, selections of contiguous ranges, and non-contiguous
  1265. * selections.
  1266. * <p>
  1267. * This is a JavaBeans bound property.
  1268. *
  1269. * @param selectionModel the <code>ListSelectionModel</code> that
  1270. * implements the selections
  1271. * @exception IllegalArgumentException if <code>selectionModel</code>
  1272. * is <code>null</code>
  1273. * @see #getSelectionModel
  1274. * @beaninfo
  1275. * bound: true
  1276. * description: The selection model, recording which cells are selected.
  1277. */
  1278. public void setSelectionModel(ListSelectionModel selectionModel) {
  1279. if (selectionModel == null) {
  1280. throw new IllegalArgumentException("selectionModel must be non null");
  1281. }
  1282. /* Remove the forwarding ListSelectionListener from the old
  1283. * selectionModel, and add it to the new one, if necessary.
  1284. */
  1285. if (selectionListener != null) {
  1286. this.selectionModel.removeListSelectionListener(selectionListener);
  1287. selectionModel.addListSelectionListener(selectionListener);
  1288. }
  1289. ListSelectionModel oldValue = this.selectionModel;
  1290. this.selectionModel = selectionModel;
  1291. firePropertyChange("selectionModel", oldValue, selectionModel);
  1292. }
  1293. /**
  1294. * Determines whether single-item or multiple-item
  1295. * selections are allowed.
  1296. * The following <code>selectionMode</code> values are allowed:
  1297. * <ul>
  1298. * <li> <code>ListSelectionModel.SINGLE_SELECTION</code>
  1299. * Only one list index can be selected at a time. In this
  1300. * mode the <code>setSelectionInterval</code> and
  1301. * <code>addSelectionInterval</code>
  1302. * methods are equivalent, and only the second index
  1303. * argument is used.
  1304. * <li> <code>ListSelectionModel.SINGLE_INTERVAL_SELECTION</code>
  1305. * One contiguous index interval can be selected at a time.
  1306. * In this mode <code>setSelectionInterval</code> and
  1307. * <code>addSelectionInterval</code>
  1308. * are equivalent.
  1309. * <li> <code>ListSelectionModel.MULTIPLE_INTERVAL_SELECTION</code>
  1310. * In this mode, there's no restriction on what can be selected.
  1311. * This is the default.
  1312. * </ul>
  1313. *
  1314. * @param selectionMode an integer specifying the type of selections
  1315. * that are permissible
  1316. * @see #getSelectionMode
  1317. * @beaninfo
  1318. * description: The selection mode.
  1319. * enum: SINGLE_SELECTION ListSelectionModel.SINGLE_SELECTION
  1320. * SINGLE_INTERVAL_SELECTION ListSelectionModel.SINGLE_INTERVAL_SELECTION
  1321. * MULTIPLE_INTERVAL_SELECTION ListSelectionModel.MULTIPLE_INTERVAL_SELECTION
  1322. */
  1323. public void setSelectionMode(int selectionMode) {
  1324. getSelectionModel().setSelectionMode(selectionMode);
  1325. }
  1326. /**
  1327. * Returns whether single-item or multiple-item selections are allowed.
  1328. *
  1329. * @return the value of the <code>selectionMode</code> property
  1330. * @see #setSelectionMode
  1331. */
  1332. public int getSelectionMode() {
  1333. return getSelectionModel().getSelectionMode();
  1334. }
  1335. /**
  1336. * Returns the first index argument from the most recent
  1337. * <code>addSelectionModel</code> or <code>setSelectionInterval</code> call.
  1338. * This is a convenience method that just delegates to the
  1339. * <code>selectionModel</code>.
  1340. *
  1341. * @return the index that most recently anchored an interval selection
  1342. * @see ListSelectionModel#getAnchorSelectionIndex
  1343. * @see #addSelectionInterval
  1344. * @see #setSelectionInterval
  1345. * @see #addListSelectionListener
  1346. */
  1347. public int getAnchorSelectionIndex() {
  1348. return getSelectionModel().getAnchorSelectionIndex();
  1349. }
  1350. /**
  1351. * Returns the second index argument from the most recent
  1352. * <code>addSelectionInterval</code> or <code>setSelectionInterval</code>
  1353. * call.
  1354. * This is a convenience method that just delegates to the
  1355. * <code>selectionModel</code>.
  1356. *
  1357. * @return the index that most recently ended a interval selection
  1358. * @see ListSelectionModel#getLeadSelectionIndex
  1359. * @see #addSelectionInterval
  1360. * @see #setSelectionInterval
  1361. * @see #addListSelectionListener
  1362. * @beaninfo
  1363. * description: The lead selection index.
  1364. */
  1365. public int getLeadSelectionIndex() {
  1366. return getSelectionModel().getLeadSelectionIndex();
  1367. }
  1368. /**
  1369. * Returns the smallest selected cell index.
  1370. * This is a convenience method that just delegates to the
  1371. * <code>selectionModel</code>.
  1372. *
  1373. * @return the smallest selected cell index
  1374. * @see ListSelectionModel#getMinSelectionIndex
  1375. * @see #addListSelectionListener
  1376. */
  1377. public int getMinSelectionIndex() {
  1378. return getSelectionModel().getMinSelectionIndex();
  1379. }
  1380. /**
  1381. * Returns the largest selected cell index.
  1382. * This is a convenience method that just delegates to the
  1383. * <code>selectionModel</code>.
  1384. *
  1385. * @return the largest selected cell index
  1386. * @see ListSelectionModel#getMaxSelectionIndex
  1387. * @see #addListSelectionListener
  1388. */
  1389. public int getMaxSelectionIndex() {
  1390. return getSelectionModel().getMaxSelectionIndex();
  1391. }
  1392. /**
  1393. * Returns true if the specified index is selected.
  1394. * This is a convenience method that just delegates to the
  1395. * <code>selectionModel</code>.
  1396. *
  1397. * @param index index to be queried for selection state
  1398. * @return true if the specified index is selected
  1399. * @see ListSelectionModel#isSelectedIndex
  1400. * @see #setSelectedIndex
  1401. * @see #addListSelectionListener
  1402. */
  1403. public boolean isSelectedIndex(int index) {
  1404. return getSelectionModel().isSelectedIndex(index);
  1405. }
  1406. /**
  1407. * Returns true if nothing is selected.
  1408. * This is a convenience method that just delegates to the
  1409. * <code>selectionModel</code>.
  1410. *
  1411. * @return true if nothing is selected
  1412. * @see ListSelectionModel#isSelectionEmpty
  1413. * @see #clearSelection
  1414. * @see #addListSelectionListener
  1415. */
  1416. public boolean isSelectionEmpty() {
  1417. return getSelectionModel().isSelectionEmpty();
  1418. }
  1419. /**
  1420. * Clears the selection - after calling this method
  1421. * <code>isSelectionEmpty</code> will return true.
  1422. * This is a convenience method that just delegates to the
  1423. * <code>selectionModel</code>.
  1424. *
  1425. * @see ListSelectionModel#clearSelection
  1426. * @see #isSelectionEmpty
  1427. * @see #addListSelectionListener
  1428. */
  1429. public void clearSelection() {
  1430. getSelectionModel().clearSelection();
  1431. }
  1432. /**
  1433. * Selects the specified interval. Both the <code>anchor</code>
  1434. * and <code>lead</code> indices are included. It's not
  1435. * necessary for <code>anchor</code> to be less than <code>lead</code>.
  1436. * This is a convenience method that just delegates to the
  1437. * <code>selectionModel</code>.
  1438. * The <code>DefaultListSelectionModel</code> implementation
  1439. * will do nothing if either <code>anchor</code> or
  1440. * <code>lead</code> are -1.
  1441. * If <code>anchor</code> or <code>lead</code> are less than -1,
  1442. * <code>IndexOutOfBoundsException</code> is thrown.
  1443. *
  1444. * @param anchor the first index to select
  1445. * @param lead the last index to select
  1446. * @exception IndexOutOfBoundsException if either <code>anchor</code>
  1447. * or <code>lead</code> are less than -1
  1448. * @see ListSelectionModel#setSelectionInterval
  1449. * @see #addSelectionInterval
  1450. * @see #removeSelectionInterval
  1451. * @see #addListSelectionListener
  1452. */
  1453. public void setSelectionInterval(int anchor, int lead) {
  1454. getSelectionModel().setSelectionInterval(anchor, lead);
  1455. }
  1456. /**
  1457. * Sets the selection to be the union of the specified interval with current
  1458. * selection. Both the anchor and lead indices are
  1459. * included. It's not necessary for anchor to be less than lead.
  1460. * This is a convenience method that just delegates to the
  1461. * <code>selectionModel</code>. The
  1462. * <code>DefaultListSelectionModel</code> implementation
  1463. * will do nothing if either <code>anchor</code> or
  1464. * <code>lead</code> are -1.
  1465. * If <code>anchor</code> or <code>lead</code> are less than -1,
  1466. * <code>IndexOutOfBoundsException</code> is thrown.
  1467. *
  1468. * @param anchor the first index to add to the selection
  1469. * @param lead the last index to add to the selection
  1470. * @see ListSelectionModel#addSelectionInterval
  1471. * @see #setSelectionInterval
  1472. * @see #removeSelectionInterval
  1473. * @see #addListSelectionListener
  1474. * @exception IndexOutOfBoundsException if either <code>anchor</code>
  1475. * or <code>lead</code> are less than -1
  1476. */
  1477. public void addSelectionInterval(int anchor, int lead) {
  1478. getSelectionModel().addSelectionInterval(anchor, lead);
  1479. }
  1480. /**
  1481. * Sets the selection to be the set difference of the specified interval
  1482. * and the current selection. Both the <code>index0</code> and
  1483. * <code>index1</code> indices are removed. It's not necessary for
  1484. * <code>index0</code> to be less than <code>index1</code>.
  1485. * This is a convenience method that just delegates to the
  1486. * <code>selectionModel</code>.
  1487. * The <code>DefaultListSelectionModel</code> implementation
  1488. * will do nothing if either <code>index0</code> or
  1489. * <code>index1</code> are -1.
  1490. * If <code>index0</code> or <code>index1</code> are less than -1,
  1491. * <code>IndexOutOfBoundsException</code> is thrown.
  1492. *
  1493. * @param index0 the first index to remove from the selection
  1494. * @param index1 the last index to remove from the selection
  1495. * @exception IndexOutOfBoundsException if either <code>index0</code>
  1496. * or <code>index1</code> are less than -1
  1497. * @see ListSelectionModel#removeSelectionInterval
  1498. * @see #setSelectionInterval
  1499. * @see #addSelectionInterval
  1500. * @see #addListSelectionListener
  1501. */
  1502. public void removeSelectionInterval(int index0, int index1) {
  1503. getSelectionModel().removeSelectionInterval(index0, index1);
  1504. }
  1505. /**
  1506. * Sets the data model's <code>isAdjusting</code> property to true,
  1507. * so that a single event will be generated when all of the selection
  1508. * events have finished (for example, when the mouse is being
  1509. * dragged over the list in selection mode).
  1510. *
  1511. * @param b the boolean value for the property value
  1512. * @see ListSelectionModel#setValueIsAdjusting
  1513. */
  1514. public void setValueIsAdjusting(boolean b) {
  1515. getSelectionModel().setValueIsAdjusting(b);
  1516. }
  1517. /**
  1518. * Returns the value of the data model's <code>isAdjusting</code> property.
  1519. * This value is true if multiple changes are being made.
  1520. *
  1521. * @return true if multiple selection-changes are occurring, as
  1522. * when the mouse is being dragged over the list
  1523. * @see ListSelectionModel#getValueIsAdjusting
  1524. */
  1525. public boolean getValueIsAdjusting() {
  1526. return getSelectionModel().getValueIsAdjusting();
  1527. }
  1528. /**
  1529. * Returns an array of all of the selected indices in increasing
  1530. * order.
  1531. *
  1532. * @return all of the selected indices, in increasing order
  1533. * @see #removeSelectionInterval
  1534. * @see #addListSelectionListener
  1535. */
  1536. public int[] getSelectedIndices() {
  1537. ListSelectionModel sm = getSelectionModel();
  1538. int iMin = sm.getMinSelectionIndex();
  1539. int iMax = sm.getMaxSelectionIndex();
  1540. if ((iMin < 0) || (iMax < 0)) {
  1541. return new int[0];
  1542. }
  1543. int[] rvTmp = new int[1+ (iMax - iMin)];
  1544. int n = 0;
  1545. for(int i = iMin; i <= iMax; i++) {
  1546. if (sm.isSelectedIndex(i)) {
  1547. rvTmp[n++] = i;
  1548. }
  1549. }
  1550. int[] rv = new int[n];
  1551. System.arraycopy(rvTmp, 0, rv, 0, n);
  1552. return rv;
  1553. }
  1554. /**
  1555. * Selects a single cell.
  1556. *
  1557. * @param index the index of the one cell to select
  1558. * @see ListSelectionModel#setSelectionInterval
  1559. * @see #isSelectedIndex
  1560. * @see #addListSelectionListener
  1561. * @beaninfo
  1562. * description: The index of the selected cell.
  1563. */
  1564. public void setSelectedIndex(int index) {
  1565. if (index >= getModel().getSize()) {
  1566. return;
  1567. }
  1568. getSelectionModel().setSelectionInterval(index, index);
  1569. }
  1570. /**
  1571. * Selects a set of cells.
  1572. *
  1573. * @param indices an array of the indices of the cells to select
  1574. * @see ListSelectionModel#addSelectionInterval
  1575. * @see #isSelectedIndex
  1576. * @see #addListSelectionListener
  1577. */
  1578. public void setSelectedIndices(int[] indices) {
  1579. ListSelectionModel sm = getSelectionModel();
  1580. sm.clearSelection();
  1581. int size = getModel().getSize();
  1582. for(int i = 0; i < indices.length; i++) {
  1583. if (indices[i] < size) {
  1584. sm.addSelectionInterval(indices[i], indices[i]);
  1585. }
  1586. }
  1587. }
  1588. /**
  1589. * Returns an array of the values for the selected cells.
  1590. * The returned values are sorted in increasing index order.
  1591. *
  1592. * @return the selected values or an empty list if
  1593. * nothing is selected
  1594. * @see #isSelectedIndex
  1595. * @see #getModel
  1596. * @see #addListSelectionListener
  1597. */
  1598. public Object[] getSelectedValues() {
  1599. ListSelectionModel sm = getSelectionModel();
  1600. ListModel dm = getModel();
  1601. int iMin = sm.getMinSelectionIndex();
  1602. int iMax = sm.getMaxSelectionIndex();
  1603. if ((iMin < 0) || (iMax < 0)) {
  1604. return new Object[0];
  1605. }
  1606. Object[] rvTmp = new Object[1+ (iMax - iMin)];
  1607. int n = 0;
  1608. for(int i = iMin; i <= iMax; i++) {
  1609. if (sm.isSelectedIndex(i)) {
  1610. rvTmp[n++] = dm.getElementAt(i);
  1611. }
  1612. }
  1613. Object[] rv = new Object[n];
  1614. System.arraycopy(rvTmp, 0, rv, 0, n);
  1615. return rv;
  1616. }
  1617. /**
  1618. * Returns the first selected index; returns -1 if there is no
  1619. * selected item.
  1620. *
  1621. * @return the value of <code>getMinSelectionIndex</code>
  1622. * @see #getMinSelectionIndex
  1623. * @see #addListSelectionListener
  1624. */
  1625. public int getSelectedIndex() {
  1626. return getMinSelectionIndex();
  1627. }
  1628. /**
  1629. * Returns the first selected value, or <code>null</code> if the
  1630. * selection is empty.
  1631. *
  1632. * @return the first selected value
  1633. * @see #getMinSelectionIndex
  1634. * @see #getModel
  1635. * @see #addListSelectionListener
  1636. */
  1637. public Object getSelectedValue() {
  1638. int i = getMinSelectionIndex();
  1639. return (i == -1) ? null : getModel().getElementAt(i);
  1640. }
  1641. // PENDING(hmuller) this should move to BasicComboBoxUI
  1642. /**
  1643. * Selects the specified object from the list.
  1644. *
  1645. * @param anObject the object to select
  1646. * @param shouldScroll true if the list should scroll to display
  1647. * the selected object, if one exists; otherwise false
  1648. */
  1649. public void setSelectedValue(Object anObject,boolean shouldScroll) {
  1650. if(anObject == null)
  1651. setSelectedIndex(-1);
  1652. else if(!anObject.equals(getSelectedValue())) {
  1653. int i,c;
  1654. ListModel dm = getModel();
  1655. for(i=0,c=dm.getSize();i<c;i++)
  1656. if(anObject.equals(dm.getElementAt(i))){
  1657. setSelectedIndex(i);
  1658. if(shouldScroll)
  1659. ensureIndexIsVisible(i);
  1660. repaint(); /** FIX-ME setSelectedIndex does not redraw all the time with the basic l&f**/
  1661. return;
  1662. }
  1663. setSelectedIndex(-1);
  1664. }
  1665. repaint(); /** FIX-ME setSelectedIndex does not redraw all the time with the basic l&f**/
  1666. }
  1667. /**
  1668. * --- The Scrollable Implementation ---
  1669. */
  1670. private void checkScrollableParameters(Rectangle visibleRect, int orientation) {
  1671. if (visibleRect == null) {
  1672. throw new IllegalArgumentException("visibleRect must be non-null");
  1673. }
  1674. switch (orientation) {
  1675. case SwingConstants.VERTICAL:
  1676. case SwingConstants.HORIZONTAL:
  1677. break;
  1678. default:
  1679. throw new IllegalArgumentException("orientation must be one of: VERTICAL, HORIZONTAL");
  1680. }
  1681. }
  1682. /**
  1683. * Computes the size of the viewport needed to display
  1684. * <code>visibleRowCount</code>
  1685. * rows. This is trivial if
  1686. * <code>fixedCellWidth</code> and <code>fixedCellHeight</code>
  1687. * were specified. Note that they can be specified implicitly with
  1688. * the <code>prototypeCellValue</code> property.
  1689. * If <code>fixedCellWidth</code> wasn't specified,
  1690. * it's computed by finding the widest list element.
  1691. * If <code>fixedCellHeight</code>
  1692. * wasn't specified then we resort to heuristics:
  1693. * <ul>
  1694. * <li>
  1695. * If the model isn't empty we just multiply the height of the first row
  1696. * by <code>visibleRowCount</code>.
  1697. * <li>
  1698. * If the model is empty, (<code>JList.getModel().getSize() == 0</code>),
  1699. * then we just allocate 16 pixels per visible row, and 256 pixels
  1700. * for the width (unless <code>fixedCellWidth</code> was set),
  1701. * and hope for the best.
  1702. * </ul>
  1703. * If the layout orientation is not <code>VERTICAL</code>, than this will
  1704. * return the value from <code>getPreferredSize</code>. The current
  1705. * <code>ListUI</code> is expected to override
  1706. * <code>getPreferredSize</code> to return an appropriate value.
  1707. *
  1708. * @return a dimension containing the size of the viewport needed
  1709. * to display <code>visibleRowCount</code> rows
  1710. * @see #getPreferredScrollableViewportSize
  1711. * @see #setPrototypeCellValue
  1712. */
  1713. public Dimension getPreferredScrollableViewportSize()
  1714. {
  1715. if (getLayoutOrientation() != VERTICAL) {
  1716. return getPreferredSize();
  1717. }
  1718. Insets insets = getInsets();
  1719. int dx = insets.left + insets.right;
  1720. int dy = insets.top + insets.bottom;
  1721. int visibleRowCount = getVisibleRowCount();
  1722. int fixedCellWidth = getFixedCellWidth();
  1723. int fixedCellHeight = getFixedCellHeight();
  1724. if ((fixedCellWidth > 0) && (fixedCellHeight > 0)) {
  1725. int width = fixedCellWidth + dx;
  1726. int height = (visibleRowCount * fixedCellHeight) + dy;
  1727. return new Dimension(width, height);
  1728. }
  1729. else if (getModel().getSize() > 0) {
  1730. int width = getPreferredSize().width;
  1731. int height;
  1732. Rectangle r = getCellBounds(0, 0);
  1733. if (r != null) {
  1734. height = (visibleRowCount * r.height) + dy;
  1735. }
  1736. else {
  1737. // Will only happen if UI null, shouldn't matter what we return
  1738. height = 1;
  1739. }
  1740. return new Dimension(width, height);
  1741. }
  1742. else {
  1743. fixedCellWidth = (fixedCellWidth > 0) ? fixedCellWidth : 256;
  1744. fixedCellHeight = (fixedCellHeight > 0) ? fixedCellHeight : 16;
  1745. return new Dimension(fixedCellWidth, fixedCellHeight * visibleRowCount);
  1746. }
  1747. }
  1748. /**
  1749. * Returns the distance to scroll to expose the next or previous
  1750. * row (for vertical scrolling) or column (for horizontal scrolling).
  1751. * <p>
  1752. * For horizontal scrolling if the list is layed out vertically
  1753. * (the orientation is <code>VERTICAL</code>) than the lists font size
  1754. * or 1 is returned if the font is <code>null</code> is used.
  1755. * <p>
  1756. * Note that the value of <code>visibleRect</code> must be the equal to
  1757. * <code>this.getVisibleRect()</code>.
  1758. *
  1759. * @param visibleRect the visible rectangle
  1760. * @param orientation HORIZONTAL or VERTICAL
  1761. * @param direction if <= 0, then scroll UP; if > 0, then scroll DOWN
  1762. * @return the distance, in pixels, to scroll to expose the
  1763. * next or previous unit
  1764. * @see Scrollable#getScrollableUnitIncrement
  1765. * @throws IllegalArgumentException if visibleRect is <code>null<code>, or
  1766. * orientation isn't one of SwingConstants.VERTICAL,
  1767. * SwingConstants.HORIZONTAL.
  1768. *
  1769. */
  1770. public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction)
  1771. {
  1772. checkScrollableParameters(visibleRect, orientation);
  1773. if (orientation == SwingConstants.VERTICAL) {
  1774. int row = getFirstVisibleIndex();
  1775. if (row == -1) {
  1776. return 0;
  1777. }
  1778. else {
  1779. /* Scroll Down */
  1780. if (direction > 0) {
  1781. Rectangle r = getCellBounds(row, row);
  1782. return (r == null) ? 0 : r.height - (visibleRect.y - r.y);
  1783. }
  1784. /* Scroll Up */
  1785. else {
  1786. Rectangle r = getCellBounds(row, row);
  1787. /* The first row is completely visible and it's row 0.
  1788. * We're done.
  1789. */
  1790. if ((r.y == visibleRect.y) && (row == 0)) {
  1791. return 0;
  1792. }
  1793. /* The first row is completely visible, return the
  1794. * height of the previous row or 0 if the first row
  1795. * is the top row of the list.
  1796. */
  1797. else if (r.y == visibleRect.y) {
  1798. Point loc = r.getLocation();
  1799. loc.y--;
  1800. int prevIndex = locationToIndex(loc);
  1801. Rectangle prevR = getCellBounds(prevIndex, prevIndex);
  1802. if (prevR == null || prevR.y >= r.y) {
  1803. return 0;
  1804. }
  1805. return prevR.height;
  1806. }
  1807. /* The first row is partially visible, return the
  1808. * height of hidden part.
  1809. */
  1810. else {
  1811. return visibleRect.y - r.y;
  1812. }
  1813. }
  1814. }
  1815. } else if (orientation == SwingConstants.HORIZONTAL &&
  1816. getLayoutOrientation() != JList.VERTICAL) {
  1817. int index = locationToIndex(visibleRect.getLocation());
  1818. if (index != -1) {
  1819. Rectangle cellBounds = getCellBounds(index, index);
  1820. if (cellBounds != null) {
  1821. if (cellBounds.x != visibleRect.x) {
  1822. if (direction < 0) {
  1823. return Math.abs(cellBounds.x - visibleRect.x);
  1824. }
  1825. return cellBounds.width + cellBounds.x - visibleRect.x;
  1826. }
  1827. return cellBounds.width;
  1828. }
  1829. }
  1830. }
  1831. Font f = getFont();
  1832. return (f != null) ? f.getSize() : 1;
  1833. }
  1834. /**
  1835. * Returns the distance to scroll to expose the next or previous block.
  1836. * For vertical scrolling we are using the follows rules:
  1837. * <ul>
  1838. * <li>if scrolling down (<code>direction</code> is greater than 0),
  1839. * the last visible element should become the first completely
  1840. * visible element
  1841. * <li>if scrolling up, the first visible element should become the last
  1842. * completely visible element
  1843. * <li>visibleRect.height if the list is empty
  1844. * </ul>
  1845. * <p>
  1846. * For horizontal scrolling if the list is layed out horizontally
  1847. * (the orientation is <code>VERTICAL_WRAP</code> or
  1848. * <code>HORIZONTAL_WRAP</code>):
  1849. * <ul>
  1850. * </ul>
  1851. * <li>if scrolling right (<code>direction</code> is greater than 0),
  1852. * the last visible element should become the first completely
  1853. * visible element
  1854. * <li>if scrolling left, the first visible element should become the last
  1855. * completely visible element
  1856. * <li>visibleRect.width if the list is empty
  1857. * <p>
  1858. * Return visibleRect.width if the list is layed out vertically.
  1859. * <p>
  1860. * Note that the value of <code>visibleRect</code> must be the equal to
  1861. * <code>this.getVisibleRect()</code>.
  1862. *
  1863. * @param visibleRect the visible rectangle
  1864. * @param orientation HORIZONTAL or VERTICAL
  1865. * @param direction if <= 0, then scroll UP; if > 0, then scroll DOWN
  1866. * @return the block increment amount.
  1867. * @see Scrollable#getScrollableUnitIncrement
  1868. * @throws IllegalArgumentException if visibleRect is <code>null</code>, or
  1869. * orientation isn't one of SwingConstants.VERTICAL,
  1870. * SwingConstants.HORIZONTAL.
  1871. *
  1872. */
  1873. public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
  1874. checkScrollableParameters(visibleRect, orientation);
  1875. if (orientation == SwingConstants.VERTICAL) {
  1876. int inc = visibleRect.height;
  1877. /* Scroll Down */
  1878. if (direction > 0) {
  1879. // last cell is the lowest left cell
  1880. int last = locationToIndex(new Point(visibleRect.x, visibleRect.y+visibleRect.height-1));
  1881. if (last != -1) {
  1882. Rectangle lastRect = getCellBounds(last,last);
  1883. if (lastRect != null) {
  1884. inc = lastRect.y - visibleRect.y;
  1885. if ( (inc == 0) && (last < getModel().getSize()-1) ) {
  1886. inc = lastRect.height;
  1887. }
  1888. }
  1889. }
  1890. }
  1891. /* Scroll Up */
  1892. else {
  1893. int newFirst = locationToIndex(new Point(visibleRect.x, visibleRect.y-visibleRect.height));
  1894. int first = getFirstVisibleIndex();
  1895. if (newFirst != -1) {
  1896. if (first == -1) {
  1897. first = locationToIndex(visibleRect.getLocation());
  1898. }
  1899. Rectangle newFirstRect = getCellBounds(newFirst,newFirst);
  1900. Rectangle firstRect = getCellBounds(first,first);
  1901. if ((newFirstRect != null) && (firstRect!=null)) {
  1902. while ( (newFirstRect.y + visibleRect.height <
  1903. firstRect.y + firstRect.height) &&
  1904. (newFirstRect.y < firstRect.y) ) {
  1905. newFirst++;
  1906. newFirstRect = getCellBounds(newFirst,newFirst);
  1907. }
  1908. inc = visibleRect.y - newFirstRect.y;
  1909. if ( (inc <= 0) && (newFirstRect.y > 0)) {
  1910. newFirst--;
  1911. newFirstRect = getCellBounds(newFirst,newFirst);
  1912. if (newFirstRect != null) {
  1913. inc = visibleRect.y - newFirstRect.y;
  1914. }
  1915. }
  1916. }
  1917. }
  1918. }
  1919. return inc;
  1920. }
  1921. else if (orientation == SwingConstants.HORIZONTAL &&
  1922. getLayoutOrientation() != JList.VERTICAL) {
  1923. int inc = visibleRect.width;
  1924. /* Scroll Right */
  1925. if (direction > 0) {
  1926. // last cell is an upper right cell
  1927. int last = locationToIndex(new Point(visibleRect.x + visibleRect.width - 1,
  1928. visibleRect.y));
  1929. if (last != -1) {
  1930. Rectangle lastRect = getCellBounds(last,last);
  1931. if (lastRect != null) {
  1932. inc = lastRect.x - visibleRect.x;
  1933. if (inc < 0) {
  1934. inc += lastRect.width;
  1935. } else if ( (inc == 0) && (last < getModel().getSize()-1) ) {
  1936. inc = lastRect.width;
  1937. }
  1938. }
  1939. }
  1940. }
  1941. /* Scroll Left */
  1942. else {
  1943. // first cell is a cell at the upper left corner of the visibleRect
  1944. // shifted left by the visibleRect.width
  1945. int first = locationToIndex(new Point(visibleRect.x - visibleRect.width,
  1946. visibleRect.y));
  1947. if (first != -1) {
  1948. Rectangle firstRect = getCellBounds(first,first);
  1949. if (firstRect != null) {
  1950. if (firstRect.x < visibleRect.x - visibleRect.width) {
  1951. if (firstRect.x + firstRect.width >= visibleRect.x) {
  1952. inc = visibleRect.x - firstRect.x;
  1953. } else {
  1954. inc = visibleRect.x - firstRect.x - firstRect.width;
  1955. }
  1956. } else {
  1957. inc = visibleRect.x - firstRect.x;
  1958. }
  1959. }
  1960. }
  1961. }
  1962. return inc;
  1963. }
  1964. return visibleRect.width;
  1965. }
  1966. /**
  1967. * Returns true if this <code>JList</code> is displayed in a
  1968. * <code>JViewport</code> and the viewport is wider than
  1969. * <code>JList</code>'s preferred width; or if the
  1970. * layout orientation is <code>HORIZONTAL_WRAP</code> and the
  1971. * visible row count is <= 0; otherwise returns
  1972. * false.
  1973. * If false, then don't track the viewport's width. This allows horizontal
  1974. * scrolling if the <code>JViewport</code> is itself embedded in a
  1975. * <code>JScrollPane</code>.
  1976. *
  1977. * @return true if viewport is wider than the <code>JList</code>'s
  1978. * preferred width, otherwise false
  1979. * @see Scrollable#getScrollableTracksViewportWidth
  1980. */
  1981. public boolean getScrollableTracksViewportWidth() {
  1982. if (getLayoutOrientation() == HORIZONTAL_WRAP &&
  1983. getVisibleRowCount() <= 0) {
  1984. return true;
  1985. }
  1986. if (getParent() instanceof JViewport) {
  1987. return (((JViewport)getParent()).getWidth() > getPreferredSize().width);
  1988. }
  1989. return false;
  1990. }
  1991. /**
  1992. * Returns true if this <code>JList</code> is displayed in a
  1993. * <code>JViewport</code> and the viewport is taller than
  1994. * <code>JList</code>'s preferred height, or if the layout orientation is
  1995. * <code>VERTICAL_WRAP</code> and the number of visible rows is <= 0;
  1996. * otherwise returns false.
  1997. * If false, then don't track the viewport's height. This allows vertical
  1998. * scrolling if the <code>JViewport</code> is itself embedded in a
  1999. * <code>JScrollPane</code>.
  2000. *
  2001. * @return true if viewport is taller than <code>Jlist</code>'s
  2002. * preferred height, otherwise false
  2003. * @see Scrollable#getScrollableTracksViewportHeight
  2004. */
  2005. public boolean getScrollableTracksViewportHeight() {
  2006. if (getLayoutOrientation() == VERTICAL_WRAP &&
  2007. getVisibleRowCount() <= 0) {
  2008. return true;
  2009. }
  2010. if (getParent() instanceof JViewport) {
  2011. return (((JViewport)getParent()).getHeight() > getPreferredSize().height);
  2012. }
  2013. return false;
  2014. }
  2015. /*
  2016. * See readObject and writeObject in JComponent for more
  2017. * information about serialization in Swing.
  2018. */
  2019. private void writeObject(ObjectOutputStream s) throws IOException {
  2020. s.defaultWriteObject();
  2021. if (getUIClassID().equals(uiClassID)) {
  2022. byte count = JComponent.getWriteObjCounter(this);
  2023. JComponent.setWriteObjCounter(this, --count);
  2024. if (count == 0 && ui != null) {
  2025. ui.installUI(this);
  2026. }
  2027. }
  2028. }
  2029. /**
  2030. * Returns a string representation of this <code>JList</code>.
  2031. * This method
  2032. * is intended to be used only for debugging purposes, and the
  2033. * content and format of the returned string may vary between
  2034. * implementations. The returned string may be empty but may not
  2035. * be <code>null</code>.
  2036. *
  2037. * @return a string representation of this <code>JList</code>.
  2038. */
  2039. protected String paramString() {
  2040. String selectionForegroundString = (selectionForeground != null ?
  2041. selectionForeground.toString() :
  2042. "");
  2043. String selectionBackgroundString = (selectionBackground != null ?
  2044. selectionBackground.toString() :
  2045. "");
  2046. return super.paramString() +
  2047. ",fixedCellHeight=" + fixedCellHeight +
  2048. ",fixedCellWidth=" + fixedCellWidth +
  2049. ",horizontalScrollIncrement=" + horizontalScrollIncrement +
  2050. ",selectionBackground=" + selectionBackgroundString +
  2051. ",selectionForeground=" + selectionForegroundString +
  2052. ",visibleRowCount=" + visibleRowCount +
  2053. ",layoutOrientation=" + layoutOrientation;
  2054. }
  2055. /**
  2056. * --- Accessibility Support ---
  2057. */
  2058. /**
  2059. * Gets the AccessibleContext associated with this JList.
  2060. * For JLists, the AccessibleContext takes the form of an
  2061. * AccessibleJList.
  2062. * A new AccessibleJList instance is created if necessary.
  2063. *
  2064. * @return an AccessibleJList that serves as the
  2065. * AccessibleContext of this JList
  2066. */
  2067. public AccessibleContext getAccessibleContext() {
  2068. if (accessibleContext == null) {
  2069. accessibleContext = new AccessibleJList();
  2070. }
  2071. return accessibleContext;
  2072. }
  2073. /**
  2074. * This class implements accessibility support for the
  2075. * <code>JList</code> class. It provides an implementation of the
  2076. * Java Accessibility API appropriate to list user-interface
  2077. * elements.
  2078. * <p>
  2079. * <strong>Warning:</strong>
  2080. * Serialized objects of this class will not be compatible with
  2081. * future Swing releases. The current serialization support is
  2082. * appropriate for short term storage or RMI between applications running
  2083. * the same version of Swing. As of 1.4, support for long term storage
  2084. * of all JavaBeans<sup><font size="-2">TM</font></sup>
  2085. * has been added to the <code>java.beans</code> package.
  2086. * Please see {@link java.beans.XMLEncoder}.
  2087. */
  2088. protected class AccessibleJList extends AccessibleJComponent
  2089. implements AccessibleSelection, PropertyChangeListener,
  2090. ListSelectionListener, ListDataListener {
  2091. int leadSelectionIndex;
  2092. public AccessibleJList() {
  2093. super();
  2094. JList.this.addPropertyChangeListener(this);
  2095. JList.this.getSelectionModel().addListSelectionListener(this);
  2096. JList.this.getModel().addListDataListener(this);
  2097. leadSelectionIndex = JList.this.getLeadSelectionIndex();
  2098. }
  2099. /**
  2100. * Property Change Listener change method. Used to track changes
  2101. * to the DataModel and ListSelectionModel, in order to re-set
  2102. * listeners to those for reporting changes there via the Accessibility
  2103. * PropertyChange mechanism.
  2104. *
  2105. * @param e PropertyChangeEvent
  2106. */
  2107. public void propertyChange(PropertyChangeEvent e) {
  2108. String name = e.getPropertyName();
  2109. Object oldValue = e.getOldValue();
  2110. Object newValue = e.getNewValue();
  2111. // re-set listData listeners
  2112. if (name.compareTo("model") == 0) {
  2113. if (oldValue != null && oldValue instanceof ListModel) {
  2114. ((ListModel) oldValue).removeListDataListener(this);
  2115. }
  2116. if (newValue != null && newValue instanceof ListModel) {
  2117. ((ListModel) newValue).addListDataListener(this);
  2118. }
  2119. // re-set listSelectionModel listeners
  2120. } else if (name.compareTo("selectionModel") == 0) {
  2121. if (oldValue != null && oldValue instanceof ListSelectionModel) {
  2122. ((ListSelectionModel) oldValue).removeListSelectionListener(this);
  2123. }
  2124. if (newValue != null && newValue instanceof ListSelectionModel) {
  2125. ((ListSelectionModel) newValue).addListSelectionListener(this);
  2126. }
  2127. firePropertyChange(
  2128. AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY,
  2129. Boolean.valueOf(false), Boolean.valueOf(true));
  2130. }
  2131. }
  2132. /**
  2133. * List Selection Listener value change method. Used to fire
  2134. * the property change
  2135. *
  2136. * @param e ListSelectionEvent
  2137. *
  2138. */
  2139. public void valueChanged(ListSelectionEvent e) {
  2140. int oldLeadSelectionIndex = leadSelectionIndex;
  2141. leadSelectionIndex = JList.this.getLeadSelectionIndex();
  2142. if (oldLeadSelectionIndex != leadSelectionIndex) {
  2143. Accessible oldLS, newLS;
  2144. oldLS = (oldLeadSelectionIndex >= 0)
  2145. ? getAccessibleChild(oldLeadSelectionIndex)
  2146. : null;
  2147. newLS = (leadSelectionIndex >= 0)
  2148. ? getAccessibleChild(leadSelectionIndex)
  2149. : null;
  2150. firePropertyChange(AccessibleContext.ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY,
  2151. oldLS, newLS);
  2152. }
  2153. firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  2154. Boolean.valueOf(false), Boolean.valueOf(true));
  2155. firePropertyChange(AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY,
  2156. Boolean.valueOf(false), Boolean.valueOf(true));
  2157. // Process the State changes for Multiselectable
  2158. AccessibleStateSet s = getAccessibleStateSet();
  2159. ListSelectionModel lsm = JList.this.getSelectionModel();
  2160. if (lsm.getSelectionMode() != ListSelectionModel.SINGLE_SELECTION) {
  2161. if (!s.contains(AccessibleState.MULTISELECTABLE)) {
  2162. s.add(AccessibleState.MULTISELECTABLE);
  2163. firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
  2164. null, AccessibleState.MULTISELECTABLE);
  2165. }
  2166. } else {
  2167. if (s.contains(AccessibleState.MULTISELECTABLE)) {
  2168. s.remove(AccessibleState.MULTISELECTABLE);
  2169. firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
  2170. AccessibleState.MULTISELECTABLE, null);
  2171. }
  2172. }
  2173. }
  2174. /**
  2175. * List Data Listener interval added method. Used to fire the visible data property change
  2176. *
  2177. * @param e ListDataEvent
  2178. *
  2179. */
  2180. public void intervalAdded(ListDataEvent e) {
  2181. firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  2182. Boolean.valueOf(false), Boolean.valueOf(true));
  2183. }
  2184. /**
  2185. * List Data Listener interval removed method. Used to fire the visible data property change
  2186. *
  2187. * @param e ListDataEvent
  2188. *
  2189. */
  2190. public void intervalRemoved(ListDataEvent e) {
  2191. firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  2192. Boolean.valueOf(false), Boolean.valueOf(true));
  2193. }
  2194. /**
  2195. * List Data Listener contents changed method. Used to fire the visible data property change
  2196. *
  2197. * @param e ListDataEvent
  2198. *
  2199. */
  2200. public void contentsChanged(ListDataEvent e) {
  2201. firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  2202. Boolean.valueOf(false), Boolean.valueOf(true));
  2203. }
  2204. // AccessibleContext methods
  2205. /**
  2206. * Get the state set of this object.
  2207. *
  2208. * @return an instance of AccessibleState containing the current state
  2209. * of the object
  2210. * @see AccessibleState
  2211. */
  2212. public AccessibleStateSet getAccessibleStateSet() {
  2213. AccessibleStateSet states = super.getAccessibleStateSet();
  2214. if (selectionModel.getSelectionMode() !=
  2215. ListSelectionModel.SINGLE_SELECTION) {
  2216. states.add(AccessibleState.MULTISELECTABLE);
  2217. }
  2218. return states;
  2219. }
  2220. /**
  2221. * Get the role of this object.
  2222. *
  2223. * @return an instance of AccessibleRole describing the role of the
  2224. * object
  2225. * @see AccessibleRole
  2226. */
  2227. public AccessibleRole getAccessibleRole() {
  2228. return AccessibleRole.LIST;
  2229. }
  2230. /**
  2231. * Returns the <code>Accessible</code> child contained at
  2232. * the local coordinate <code>Point</code>, if one exists.
  2233. * Otherwise returns <code>null</code>.
  2234. *
  2235. * @return the <code>Accessible</code> at the specified
  2236. * location, if it exists
  2237. */
  2238. public Accessible getAccessibleAt(Point p) {
  2239. int i = locationToIndex(p);
  2240. if (i >= 0) {
  2241. return new AccessibleJListChild(JList.this, i);
  2242. } else {
  2243. return null;
  2244. }
  2245. }
  2246. /**
  2247. * Returns the number of accessible children in the object. If all
  2248. * of the children of this object implement Accessible, than this
  2249. * method should return the number of children of this object.
  2250. *
  2251. * @return the number of accessible children in the object.
  2252. */
  2253. public int getAccessibleChildrenCount() {
  2254. return getModel().getSize();
  2255. }
  2256. /**
  2257. * Return the nth Accessible child of the object.
  2258. *
  2259. * @param i zero-based index of child
  2260. * @return the nth Accessible child of the object
  2261. */
  2262. public Accessible getAccessibleChild(int i) {
  2263. if (i >= getModel().getSize()) {
  2264. return null;
  2265. } else {
  2266. return new AccessibleJListChild(JList.this, i);
  2267. }
  2268. }
  2269. /**
  2270. * Get the AccessibleSelection associated with this object. In the
  2271. * implementation of the Java Accessibility API for this class,
  2272. * return this object, which is responsible for implementing the
  2273. * AccessibleSelection interface on behalf of itself.
  2274. *
  2275. * @return this object
  2276. */
  2277. public AccessibleSelection getAccessibleSelection() {
  2278. return this;
  2279. }
  2280. // AccessibleSelection methods
  2281. /**
  2282. * Returns the number of items currently selected.
  2283. * If no items are selected, the return value will be 0.
  2284. *
  2285. * @return the number of items currently selected.
  2286. */
  2287. public int getAccessibleSelectionCount() {
  2288. return JList.this.getSelectedIndices().length;
  2289. }
  2290. /**
  2291. * Returns an Accessible representing the specified selected item
  2292. * in the object. If there isn't a selection, or there are
  2293. * fewer items selected than the integer passed in, the return
  2294. * value will be <code>null</code>.
  2295. *
  2296. * @param i the zero-based index of selected items
  2297. * @return an Accessible containing the selected item
  2298. */
  2299. public Accessible getAccessibleSelection(int i) {
  2300. int len = getAccessibleSelectionCount();
  2301. if (i < 0 || i >= len) {
  2302. return null;
  2303. } else {
  2304. return getAccessibleChild(JList.this.getSelectedIndices()[i]);
  2305. }
  2306. }
  2307. /**
  2308. * Returns true if the current child of this object is selected.
  2309. *
  2310. * @param i the zero-based index of the child in this Accessible
  2311. * object.
  2312. * @see AccessibleContext#getAccessibleChild
  2313. */
  2314. public boolean isAccessibleChildSelected(int i) {
  2315. return isSelectedIndex(i);
  2316. }
  2317. /**
  2318. * Adds the specified selected item in the object to the object's
  2319. * selection. If the object supports multiple selections,
  2320. * the specified item is added to any existing selection, otherwise
  2321. * it replaces any existing selection in the object. If the
  2322. * specified item is already selected, this method has no effect.
  2323. *
  2324. * @param i the zero-based index of selectable items
  2325. */
  2326. public void addAccessibleSelection(int i) {
  2327. JList.this.addSelectionInterval(i, i);
  2328. }
  2329. /**
  2330. * Removes the specified selected item in the object from the object's
  2331. * selection. If the specified item isn't currently selected, this
  2332. * method has no effect.
  2333. *
  2334. * @param i the zero-based index of selectable items
  2335. */
  2336. public void removeAccessibleSelection(int i) {
  2337. JList.this.removeSelectionInterval(i, i);
  2338. }
  2339. /**
  2340. * Clears the selection in the object, so that nothing in the
  2341. * object is selected.
  2342. */
  2343. public void clearAccessibleSelection() {
  2344. JList.this.clearSelection();
  2345. }
  2346. /**
  2347. * Causes every selected item in the object to be selected
  2348. * if the object supports multiple selections.
  2349. */
  2350. public void selectAllAccessibleSelection() {
  2351. JList.this.addSelectionInterval(0, getAccessibleChildrenCount() -1);
  2352. }
  2353. /**
  2354. * This class implements accessibility support appropriate
  2355. * for list children.
  2356. */
  2357. protected class AccessibleJListChild extends AccessibleContext
  2358. implements Accessible, AccessibleComponent {
  2359. private JList parent = null;
  2360. private int indexInParent;
  2361. private Component component = null;
  2362. private AccessibleContext accessibleContext = null;
  2363. private ListModel listModel;
  2364. private ListCellRenderer cellRenderer = null;
  2365. public AccessibleJListChild(JList parent, int indexInParent) {
  2366. this.parent = parent;
  2367. this.setAccessibleParent(parent);
  2368. this.indexInParent = indexInParent;
  2369. if (parent != null) {
  2370. listModel = parent.getModel();
  2371. cellRenderer = parent.getCellRenderer();
  2372. }
  2373. }
  2374. private Component getCurrentComponent() {
  2375. return getComponentAtIndex(indexInParent);
  2376. }
  2377. private AccessibleContext getCurrentAccessibleContext() {
  2378. Component c = getComponentAtIndex(indexInParent);
  2379. if (c instanceof Accessible) {
  2380. return ((Accessible) c).getAccessibleContext();
  2381. } else {
  2382. return null;
  2383. }
  2384. }
  2385. private Component getComponentAtIndex(int index) {
  2386. if (index < 0 || index >= listModel.getSize()) {
  2387. return null;
  2388. }
  2389. if ((parent != null)
  2390. && (listModel != null)
  2391. && cellRenderer != null) {
  2392. Object value = listModel.getElementAt(index);
  2393. boolean isSelected = parent.isSelectedIndex(index);
  2394. boolean isFocussed = parent.isFocusOwner()
  2395. && (index == parent.getLeadSelectionIndex());
  2396. return cellRenderer.getListCellRendererComponent(
  2397. parent,
  2398. value,
  2399. index,
  2400. isSelected,
  2401. isFocussed);
  2402. } else {
  2403. return null;
  2404. }
  2405. }
  2406. // Accessible Methods
  2407. /**
  2408. * Get the AccessibleContext for this object. In the
  2409. * implementation of the Java Accessibility API for this class,
  2410. * returns this object, which is its own AccessibleContext.
  2411. *
  2412. * @return this object
  2413. */
  2414. public AccessibleContext getAccessibleContext() {
  2415. return this;
  2416. }
  2417. // AccessibleContext methods
  2418. public String getAccessibleName() {
  2419. AccessibleContext ac = getCurrentAccessibleContext();
  2420. if (ac != null) {
  2421. return ac.getAccessibleName();
  2422. } else {
  2423. return null;
  2424. }
  2425. }
  2426. public void setAccessibleName(String s) {
  2427. AccessibleContext ac = getCurrentAccessibleContext();
  2428. if (ac != null) {
  2429. ac.setAccessibleName(s);
  2430. }
  2431. }
  2432. public String getAccessibleDescription() {
  2433. AccessibleContext ac = getCurrentAccessibleContext();
  2434. if (ac != null) {
  2435. return ac.getAccessibleDescription();
  2436. } else {
  2437. return null;
  2438. }
  2439. }
  2440. public void setAccessibleDescription(String s) {
  2441. AccessibleContext ac = getCurrentAccessibleContext();
  2442. if (ac != null) {
  2443. ac.setAccessibleDescription(s);
  2444. }
  2445. }
  2446. public AccessibleRole getAccessibleRole() {
  2447. AccessibleContext ac = getCurrentAccessibleContext();
  2448. if (ac != null) {
  2449. return ac.getAccessibleRole();
  2450. } else {
  2451. return null;
  2452. }
  2453. }
  2454. public AccessibleStateSet getAccessibleStateSet() {
  2455. AccessibleContext ac = getCurrentAccessibleContext();
  2456. AccessibleStateSet s;
  2457. if (ac != null) {
  2458. s = ac.getAccessibleStateSet();
  2459. } else {
  2460. s = new AccessibleStateSet();
  2461. }
  2462. s = ac.getAccessibleStateSet();
  2463. s.add(AccessibleState.SELECTABLE);
  2464. if (parent.isFocusOwner()
  2465. && (indexInParent == parent.getLeadSelectionIndex())) {
  2466. s.add(AccessibleState.ACTIVE);
  2467. }
  2468. if (parent.isSelectedIndex(indexInParent)) {
  2469. s.add(AccessibleState.SELECTED);
  2470. }
  2471. if (this.isShowing()) {
  2472. s.add(AccessibleState.SHOWING);
  2473. } else if (s.contains(AccessibleState.SHOWING)) {
  2474. s.remove(AccessibleState.SHOWING);
  2475. }
  2476. if (this.isVisible()) {
  2477. s.add(AccessibleState.VISIBLE);
  2478. } else if (s.contains(AccessibleState.VISIBLE)) {
  2479. s.remove(AccessibleState.VISIBLE);
  2480. }
  2481. s.add(AccessibleState.TRANSIENT); // cell-rendered
  2482. return s;
  2483. }
  2484. public int getAccessibleIndexInParent() {
  2485. return indexInParent;
  2486. }
  2487. public int getAccessibleChildrenCount() {
  2488. AccessibleContext ac = getCurrentAccessibleContext();
  2489. if (ac != null) {
  2490. return ac.getAccessibleChildrenCount();
  2491. } else {
  2492. return 0;
  2493. }
  2494. }
  2495. public Accessible getAccessibleChild(int i) {
  2496. AccessibleContext ac = getCurrentAccessibleContext();
  2497. if (ac != null) {
  2498. Accessible accessibleChild = ac.getAccessibleChild(i);
  2499. ac.setAccessibleParent(this);
  2500. return accessibleChild;
  2501. } else {
  2502. return null;
  2503. }
  2504. }
  2505. public Locale getLocale() {
  2506. AccessibleContext ac = getCurrentAccessibleContext();
  2507. if (ac != null) {
  2508. return ac.getLocale();
  2509. } else {
  2510. return null;
  2511. }
  2512. }
  2513. public void addPropertyChangeListener(PropertyChangeListener l) {
  2514. AccessibleContext ac = getCurrentAccessibleContext();
  2515. if (ac != null) {
  2516. ac.addPropertyChangeListener(l);
  2517. }
  2518. }
  2519. public void removePropertyChangeListener(PropertyChangeListener l) {
  2520. AccessibleContext ac = getCurrentAccessibleContext();
  2521. if (ac != null) {
  2522. ac.removePropertyChangeListener(l);
  2523. }
  2524. }
  2525. public AccessibleAction getAccessibleAction() {
  2526. return getCurrentAccessibleContext().getAccessibleAction();
  2527. }
  2528. /**
  2529. * Get the AccessibleComponent associated with this object. In the
  2530. * implementation of the Java Accessibility API for this class,
  2531. * return this object, which is responsible for implementing the
  2532. * AccessibleComponent interface on behalf of itself.
  2533. *
  2534. * @return this object
  2535. */
  2536. public AccessibleComponent getAccessibleComponent() {
  2537. return this; // to override getBounds()
  2538. }
  2539. public AccessibleSelection getAccessibleSelection() {
  2540. return getCurrentAccessibleContext().getAccessibleSelection();
  2541. }
  2542. public AccessibleText getAccessibleText() {
  2543. return getCurrentAccessibleContext().getAccessibleText();
  2544. }
  2545. public AccessibleValue getAccessibleValue() {
  2546. return getCurrentAccessibleContext().getAccessibleValue();
  2547. }
  2548. // AccessibleComponent methods
  2549. public Color getBackground() {
  2550. AccessibleContext ac = getCurrentAccessibleContext();
  2551. if (ac instanceof AccessibleComponent) {
  2552. return ((AccessibleComponent) ac).getBackground();
  2553. } else {
  2554. Component c = getCurrentComponent();
  2555. if (c != null) {
  2556. return c.getBackground();
  2557. } else {
  2558. return null;
  2559. }
  2560. }
  2561. }
  2562. public void setBackground(Color c) {
  2563. AccessibleContext ac = getCurrentAccessibleContext();
  2564. if (ac instanceof AccessibleComponent) {
  2565. ((AccessibleComponent) ac).setBackground(c);
  2566. } else {
  2567. Component cp = getCurrentComponent();
  2568. if (cp != null) {
  2569. cp.setBackground(c);
  2570. }
  2571. }
  2572. }
  2573. public Color getForeground() {
  2574. AccessibleContext ac = getCurrentAccessibleContext();
  2575. if (ac instanceof AccessibleComponent) {
  2576. return ((AccessibleComponent) ac).getForeground();
  2577. } else {
  2578. Component c = getCurrentComponent();
  2579. if (c != null) {
  2580. return c.getForeground();
  2581. } else {
  2582. return null;
  2583. }
  2584. }
  2585. }
  2586. public void setForeground(Color c) {
  2587. AccessibleContext ac = getCurrentAccessibleContext();
  2588. if (ac instanceof AccessibleComponent) {
  2589. ((AccessibleComponent) ac).setForeground(c);
  2590. } else {
  2591. Component cp = getCurrentComponent();
  2592. if (cp != null) {
  2593. cp.setForeground(c);
  2594. }
  2595. }
  2596. }
  2597. public Cursor getCursor() {
  2598. AccessibleContext ac = getCurrentAccessibleContext();
  2599. if (ac instanceof AccessibleComponent) {
  2600. return ((AccessibleComponent) ac).getCursor();
  2601. } else {
  2602. Component c = getCurrentComponent();
  2603. if (c != null) {
  2604. return c.getCursor();
  2605. } else {
  2606. Accessible ap = getAccessibleParent();
  2607. if (ap instanceof AccessibleComponent) {
  2608. return ((AccessibleComponent) ap).getCursor();
  2609. } else {
  2610. return null;
  2611. }
  2612. }
  2613. }
  2614. }
  2615. public void setCursor(Cursor c) {
  2616. AccessibleContext ac = getCurrentAccessibleContext();
  2617. if (ac instanceof AccessibleComponent) {
  2618. ((AccessibleComponent) ac).setCursor(c);
  2619. } else {
  2620. Component cp = getCurrentComponent();
  2621. if (cp != null) {
  2622. cp.setCursor(c);
  2623. }
  2624. }
  2625. }
  2626. public Font getFont() {
  2627. AccessibleContext ac = getCurrentAccessibleContext();
  2628. if (ac instanceof AccessibleComponent) {
  2629. return ((AccessibleComponent) ac).getFont();
  2630. } else {
  2631. Component c = getCurrentComponent();
  2632. if (c != null) {
  2633. return c.getFont();
  2634. } else {
  2635. return null;
  2636. }
  2637. }
  2638. }
  2639. public void setFont(Font f) {
  2640. AccessibleContext ac = getCurrentAccessibleContext();
  2641. if (ac instanceof AccessibleComponent) {
  2642. ((AccessibleComponent) ac).setFont(f);
  2643. } else {
  2644. Component c = getCurrentComponent();
  2645. if (c != null) {
  2646. c.setFont(f);
  2647. }
  2648. }
  2649. }
  2650. public FontMetrics getFontMetrics(Font f) {
  2651. AccessibleContext ac = getCurrentAccessibleContext();
  2652. if (ac instanceof AccessibleComponent) {
  2653. return ((AccessibleComponent) ac).getFontMetrics(f);
  2654. } else {
  2655. Component c = getCurrentComponent();
  2656. if (c != null) {
  2657. return c.getFontMetrics(f);
  2658. } else {
  2659. return null;
  2660. }
  2661. }
  2662. }
  2663. public boolean isEnabled() {
  2664. AccessibleContext ac = getCurrentAccessibleContext();
  2665. if (ac instanceof AccessibleComponent) {
  2666. return ((AccessibleComponent) ac).isEnabled();
  2667. } else {
  2668. Component c = getCurrentComponent();
  2669. if (c != null) {
  2670. return c.isEnabled();
  2671. } else {
  2672. return false;
  2673. }
  2674. }
  2675. }
  2676. public void setEnabled(boolean b) {
  2677. AccessibleContext ac = getCurrentAccessibleContext();
  2678. if (ac instanceof AccessibleComponent) {
  2679. ((AccessibleComponent) ac).setEnabled(b);
  2680. } else {
  2681. Component c = getCurrentComponent();
  2682. if (c != null) {
  2683. c.setEnabled(b);
  2684. }
  2685. }
  2686. }
  2687. public boolean isVisible() {
  2688. int fi = parent.getFirstVisibleIndex();
  2689. int li = parent.getLastVisibleIndex();
  2690. // The UI incorrectly returns a -1 for the last
  2691. // visible index if the list is smaller than the
  2692. // viewport size.
  2693. if (li == -1) {
  2694. li = parent.getModel().getSize() - 1;
  2695. }
  2696. return ((indexInParent >= fi)
  2697. && (indexInParent <= li));
  2698. }
  2699. public void setVisible(boolean b) {
  2700. }
  2701. public boolean isShowing() {
  2702. return (parent.isShowing() && isVisible());
  2703. }
  2704. public boolean contains(Point p) {
  2705. AccessibleContext ac = getCurrentAccessibleContext();
  2706. if (ac instanceof AccessibleComponent) {
  2707. Rectangle r = ((AccessibleComponent) ac).getBounds();
  2708. return r.contains(p);
  2709. } else {
  2710. Component c = getCurrentComponent();
  2711. if (c != null) {
  2712. Rectangle r = c.getBounds();
  2713. return r.contains(p);
  2714. } else {
  2715. return getBounds().contains(p);
  2716. }
  2717. }
  2718. }
  2719. public Point getLocationOnScreen() {
  2720. if (parent != null) {
  2721. Point listLocation = parent.getLocationOnScreen();
  2722. Point componentLocation = parent.indexToLocation(indexInParent);
  2723. if (componentLocation != null) {
  2724. componentLocation.translate(listLocation.x, listLocation.y);
  2725. return componentLocation;
  2726. } else {
  2727. return null;
  2728. }
  2729. } else {
  2730. return null;
  2731. }
  2732. }
  2733. public Point getLocation() {
  2734. if (parent != null) {
  2735. return parent.indexToLocation(indexInParent);
  2736. } else {
  2737. return null;
  2738. }
  2739. }
  2740. public void setLocation(Point p) {
  2741. if ((parent != null) && (parent.contains(p))) {
  2742. ensureIndexIsVisible(indexInParent);
  2743. }
  2744. }
  2745. public Rectangle getBounds() {
  2746. if (parent != null) {
  2747. return parent.getCellBounds(indexInParent,indexInParent);
  2748. } else {
  2749. return null;
  2750. }
  2751. }
  2752. public void setBounds(Rectangle r) {
  2753. AccessibleContext ac = getCurrentAccessibleContext();
  2754. if (ac instanceof AccessibleComponent) {
  2755. ((AccessibleComponent) ac).setBounds(r);
  2756. }
  2757. }
  2758. public Dimension getSize() {
  2759. Rectangle cellBounds = this.getBounds();
  2760. if (cellBounds != null) {
  2761. return cellBounds.getSize();
  2762. } else {
  2763. return null;
  2764. }
  2765. }
  2766. public void setSize (Dimension d) {
  2767. AccessibleContext ac = getCurrentAccessibleContext();
  2768. if (ac instanceof AccessibleComponent) {
  2769. ((AccessibleComponent) ac).setSize(d);
  2770. } else {
  2771. Component c = getCurrentComponent();
  2772. if (c != null) {
  2773. c.setSize(d);
  2774. }
  2775. }
  2776. }
  2777. public Accessible getAccessibleAt(Point p) {
  2778. AccessibleContext ac = getCurrentAccessibleContext();
  2779. if (ac instanceof AccessibleComponent) {
  2780. return ((AccessibleComponent) ac).getAccessibleAt(p);
  2781. } else {
  2782. return null;
  2783. }
  2784. }
  2785. public boolean isFocusTraversable() {
  2786. AccessibleContext ac = getCurrentAccessibleContext();
  2787. if (ac instanceof AccessibleComponent) {
  2788. return ((AccessibleComponent) ac).isFocusTraversable();
  2789. } else {
  2790. Component c = getCurrentComponent();
  2791. if (c != null) {
  2792. return c.isFocusTraversable();
  2793. } else {
  2794. return false;
  2795. }
  2796. }
  2797. }
  2798. public void requestFocus() {
  2799. AccessibleContext ac = getCurrentAccessibleContext();
  2800. if (ac instanceof AccessibleComponent) {
  2801. ((AccessibleComponent) ac).requestFocus();
  2802. } else {
  2803. Component c = getCurrentComponent();
  2804. if (c != null) {
  2805. c.requestFocus();
  2806. }
  2807. }
  2808. }
  2809. public void addFocusListener(FocusListener l) {
  2810. AccessibleContext ac = getCurrentAccessibleContext();
  2811. if (ac instanceof AccessibleComponent) {
  2812. ((AccessibleComponent) ac).addFocusListener(l);
  2813. } else {
  2814. Component c = getCurrentComponent();
  2815. if (c != null) {
  2816. c.addFocusListener(l);
  2817. }
  2818. }
  2819. }
  2820. public void removeFocusListener(FocusListener l) {
  2821. AccessibleContext ac = getCurrentAccessibleContext();
  2822. if (ac instanceof AccessibleComponent) {
  2823. ((AccessibleComponent) ac).removeFocusListener(l);
  2824. } else {
  2825. Component c = getCurrentComponent();
  2826. if (c != null) {
  2827. c.removeFocusListener(l);
  2828. }
  2829. }
  2830. }
  2831. // TIGER - 4733624
  2832. /**
  2833. * Returns an AccessibleIcon
  2834. *
  2835. * @return the AccessibleIcon for the element renderer.
  2836. */
  2837. public AccessibleIcon [] getAccessibleIcon() {
  2838. AccessibleContext ac = getCurrentAccessibleContext();
  2839. if (ac != null) {
  2840. return ac.getAccessibleIcon();
  2841. } else {
  2842. return null;
  2843. }
  2844. }
  2845. } // inner class AccessibleJListChild
  2846. } // inner class AccessibleJList
  2847. }