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