Index: javax/swing/JList.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/JList.java,v
retrieving revision 1.31
diff -u -r1.31 JList.java
--- javax/swing/JList.java 2 Sep 2005 16:06:38 -0000 1.31
+++ javax/swing/JList.java 16 Sep 2005 09:32:47 -0000
@@ -41,13 +41,25 @@
import java.awt.Color;
import java.awt.Component;
import java.awt.ComponentOrientation;
+import java.awt.Cursor;
import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.FontMetrics;
import java.awt.Point;
import java.awt.Rectangle;
+import java.awt.event.FocusListener;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.util.Locale;
import java.util.Vector;
import javax.accessibility.Accessible;
+import javax.accessibility.AccessibleComponent;
import javax.accessibility.AccessibleContext;
+import javax.accessibility.AccessibleRole;
+import javax.accessibility.AccessibleSelection;
+import javax.accessibility.AccessibleState;
+import javax.accessibility.AccessibleStateSet;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import javax.swing.event.ListSelectionEvent;
@@ -108,6 +120,728 @@
public class JList extends JComponent implements Accessible, Scrollable
{
+
+ /**
+ * Provides accessibility support for JList
.
+ */
+ protected class AccessibleJList extends AccessibleJComponent
+ implements AccessibleSelection, PropertyChangeListener,
+ ListSelectionListener, ListDataListener
+ {
+
+ /**
+ * Provides accessibility support for list elements in JList
s.
+ */
+ protected class AccessibleJListChild extends AccessibleContext
+ implements Accessible, AccessibleComponent
+ {
+
+ /**
+ * The parent list.
+ */
+ JList parent;
+
+ /**
+ * The index in the list for that child.
+ */
+ int listIndex;
+
+ /**
+ * The cursor for this list child.
+ */
+ // TODO: Testcases show that this class somehow stores state about the
+ // cursor. I cannot make up though how that could affect
+ // the actual list.
+ Cursor cursor = Cursor.getDefaultCursor();
+
+ /**
+ * Creates a new instance of AccessibleJListChild
.
+ *
+ * @param list the list of which this is an accessible child
+ * @param index the list index for this child
+ */
+ public AccessibleJListChild(JList list, int index)
+ {
+ parent = list;
+ listIndex = index;
+ }
+
+ /**
+ * Returns the accessible context of this object. Returns
+ * this
since AccessibleJListChild
s are their
+ * own accessible contexts.
+ *
+ * @return the accessible context of this object, this
+ */
+ public AccessibleContext getAccessibleContext()
+ {
+ return this;
+ }
+
+ /**
+ * Returns the background color for this list child. This returns the
+ * background of the JList
itself since the background
+ * cannot be set on list children individually
+ *
+ * @return the background color for this list child
+ */
+ public Color getBackground()
+ {
+ return parent.getBackground();
+ }
+
+ /**
+ * Calling this method has no effect, since the background color cannot be
+ * set on list children individually.
+ *
+ * @param color not used here.
+ */
+ public void setBackground(Color color)
+ {
+ // Calling this method has no effect, since the background color cannot
+ // be set on list children individually.
+ }
+
+ /**
+ * Returns the foreground color for this list child. This returns the
+ * background of the JList
itself since the foreground
+ * cannot be set on list children individually.
+ *
+ * @return the background color for this list child
+ */
+ public Color getForeground()
+ {
+ return parent.getForeground();
+ }
+
+ /**
+ * Calling this method has no effect, since the foreground color cannot be
+ * set on list children individually.
+ *
+ * @param color not used here.
+ */
+ public void setForeground(Color color)
+ {
+ // Calling this method has no effect, since the foreground color cannot
+ // be set on list children individually.
+ }
+
+ /**
+ * Returns the cursor for this list child.
+ *
+ * @return the cursor for this list child
+ */
+ public Cursor getCursor()
+ {
+ // TODO: Testcases show that this method returns the cursor that has
+ // been set by setCursor. I cannot make up though how that could affect
+ // the actual list.
+ return cursor;
+ }
+
+ /**
+ * Sets the cursor for this list child.
+ */
+ public void setCursor(Cursor cursor)
+ {
+ this.cursor = cursor;
+ // TODO: Testcases show that this method returns the cursor that has
+ // been set by setCursor. I cannot make up though how that could affect
+ // the actual list.
+ }
+
+ /**
+ * Returns the font of the JList
since it is not possible to
+ * set fonts for list children individually.
+ *
+ * @return the font of the JList
+ */
+ public Font getFont()
+ {
+ return parent.getFont();
+ }
+
+ /**
+ * Does nothing since it is not possible to set the font on list children
+ * individually.
+ *
+ * @param font not used here
+ */
+ public void setFont(Font font)
+ {
+ // Does nothing since it is not possible to set the font on list
+ // children individually.
+ }
+
+ /**
+ * Returns the font metrics for the specified font. This method forwards
+ * to the parent JList
.
+ *
+ * @param font the font for which the font metrics is queried
+ *
+ * @return the font metrics for the specified font
+ */
+ public FontMetrics getFontMetrics(Font font)
+ {
+ return parent.getFontMetrics(font);
+ }
+
+ /**
+ * Returns true
if the parent JList
is enabled,
+ * false
otherwise. The list children cannot have an enabled
+ * flag set individually.
+ *
+ * @return true
if the parent JList
is enabled,
+ * false
otherwise
+ */
+ public boolean isEnabled()
+ {
+ return parent.isEnabled();
+ }
+
+ /**
+ * Does nothing since the enabled flag cannot be set for list children
+ * individually.
+ *
+ * @param b not used here
+ */
+ public void setEnabled(boolean b)
+ {
+ // Does nothing since the enabled flag cannot be set for list children
+ // individually.
+ }
+
+ /**
+ * Returns true
if this list child is visible,
+ * false
otherwise. The value of this property depends
+ * on address@hidden JList#getFirstVisibleIndex()} and
+ * address@hidden JList#getLastVisibleIndex()}.
+ *
+ * @return true
if this list child is visible,
+ * false
otherwise
+ */
+ public boolean isVisible()
+ {
+ return listIndex >= parent.getFirstVisibleIndex()
+ && listIndex <= parent.getLastVisibleIndex();
+ }
+
+ /**
+ * The value of the visible property cannot be modified, so this method
+ * does nothing.
+ *
+ * @param b not used here
+ */
+ public void setVisible(boolean b)
+ {
+ // The value of the visible property cannot be modified, so this method
+ // does nothing.
+ }
+
+ /**
+ * Returns true
if this list child is currently showing on
+ * screen and false
otherwise. The list child is showing if
+ * it is visible and if it's parent JList is currently showing.
+ *
+ * @return true
if this list child is currently showing on
+ * screen and false
otherwise
+ */
+ public boolean isShowing()
+ {
+ return isVisible() && parent.isShowing();
+ }
+
+ /**
+ * Returns true
if this list child covers the screen location
+ * point
(relative to the JList
coordinate
+ * system, false
otherwise.
+ *
+ * @return true
if this list child covers the screen location
+ * point
, false
otherwise
+ */
+ public boolean contains(Point point)
+ {
+ return getBounds().contains(point);
+ }
+
+ /**
+ * Returns the absolute screen location of this list child.
+ *
+ * @return the absolute screen location of this list child
+ */
+ public Point getLocationOnScreen()
+ {
+ Point loc = getLocation();
+ SwingUtilities.convertPointToScreen(loc, parent);
+ return loc;
+ }
+
+ /**
+ * Returns the screen location of this list child relative to it's parent.
+ *
+ * @return the location of this list child relative to it's parent
+ *
+ * @see JList#indexToLocation(int)
+ */
+ public Point getLocation()
+ {
+ return parent.indexToLocation(listIndex);
+ }
+
+ /**
+ * Does nothing since the screen location cannot be set on list children
+ * explictitly.
+ *
+ * @param point not used here
+ */
+ public void setLocation(Point point)
+ {
+ // Does nothing since the screen location cannot be set on list children
+ // explictitly.
+ }
+
+ /**
+ * Returns the bounds of this list child.
+ *
+ * @return the bounds of this list child
+ *
+ * @see JList#getCellBounds(int, int)
+ */
+ public Rectangle getBounds()
+ {
+ return parent.getCellBounds(listIndex, listIndex);
+ }
+
+ /**
+ * Does nothing since the bounds cannot be set on list children
+ * individually.
+ *
+ * @param rectangle not used here
+ */
+ public void setBounds(Rectangle rectangle)
+ {
+ // Does nothing since the bounds cannot be set on list children
+ // individually.
+ }
+
+ /**
+ * Returns the size of this list child.
+ *
+ * @return the size of this list child
+ */
+ public Dimension getSize()
+ {
+ Rectangle b = getBounds();
+ return b.getSize();
+ }
+
+ /**
+ * Does nothing since the size cannot be set on list children
+ * individually.
+ *
+ * @param dimension not used here
+ */
+ public void setSize(Dimension dimension)
+ {
+ // Does nothing since the size cannot be set on list children
+ // individually.
+ }
+
+ /**
+ * Returns null
because list children do not have children
+ * themselves
+ *
+ * @return null
+ */
+ public Accessible getAccessibleAt(Point point)
+ {
+ return null;
+ }
+
+ /**
+ * Returns true
since list children are focus traversable.
+ *
+ * @return true
+ */
+ public boolean isFocusTraversable()
+ {
+ // TODO: Is this 100% ok?
+ return true;
+ }
+
+ /**
+ * Requests focus on the parent list. List children cannot request focus
+ * individually.
+ */
+ public void requestFocus()
+ {
+ // TODO: Is this 100% ok?
+ parent.requestFocus();
+ }
+
+ /**
+ * Adds a focus listener to the parent list. List children do not have
+ * their own focus management.
+ *
+ * @param listener the focus listener to add
+ */
+ public void addFocusListener(FocusListener listener)
+ {
+ // TODO: Is this 100% ok?
+ parent.addFocusListener(listener);
+ }
+
+ /**
+ * Removes a focus listener from the parent list. List children do not
+ * have their own focus management.
+ *
+ * @param listener the focus listener to remove
+ */
+ public void removeFocusListener(FocusListener listener)
+ {
+ // TODO: Is this 100%
+ parent.removeFocusListener(listener);
+ }
+
+ /**
+ * Returns the accessible role of this list item, which is
+ * address@hidden AccessibleRole#LABEL}.
+ *
+ * @return address@hidden AccessibleRole#LABEL}
+ */
+ public AccessibleRole getAccessibleRole()
+ {
+ return AccessibleRole.LABEL;
+ }
+
+ /**
+ * Returns the accessible state set of this list item.
+ *
+ * @return the accessible state set of this list item
+ */
+ public AccessibleStateSet getAccessibleStateSet()
+ {
+ AccessibleStateSet states = new AccessibleStateSet();
+ if (isVisible())
+ states.add(AccessibleState.VISIBLE);
+ if (isShowing())
+ states.add(AccessibleState.SHOWING);
+ if (isFocusTraversable())
+ states.add(AccessibleState.FOCUSABLE);
+ // TODO: How should the active state be handled? The API docs
+ // suggest that this state is set on the activated list child,
+ // that is the one that is drawn with a box. However, I don't know how
+ // to implement this.
+
+ // TODO: We set the selectable state here because list children are
+ // selectable. Is there a way to disable single children?
+ if (parent.isEnabled())
+ states.add(AccessibleState.SELECTABLE);
+
+ if (parent.isSelectedIndex(listIndex))
+ states.add(AccessibleState.SELECTED);
+
+ // TODO: Handle more states here?
+ return states;
+ }
+
+ /**
+ * Returns the index of this list child within it's parent list.
+ *
+ * @return the index of this list child within it's parent list
+ */
+ public int getAccessibleIndexInParent()
+ {
+ return listIndex;
+ }
+
+ /**
+ * Returns 0
since list children don't have children
+ * themselves.
+ *
+ * @return 0
+ */
+ public int getAccessibleChildrenCount()
+ {
+ return 0;
+ }
+
+ /**
+ * Returns null
since list children don't have children
+ * themselves.
+ *
+ * @return null
+ */
+ public Accessible getAccessibleChild(int i)
+ {
+ return null;
+ }
+
+ /**
+ * Returns the locale of this component. This call is forwarded to the
+ * parent list since list children don't have a separate locale setting.
+ *
+ * @return the locale of this component
+ */
+ public Locale getLocale()
+ {
+ return parent.getLocale();
+ }
+
+ /**
+ * This method does
+ * nothing, list children are transient accessible objects which means
+ * that they don't fire property change events.
+ *
+ * @param l not used here
+ */
+ public void addPropertyChangeListener(PropertyChangeListener l)
+ {
+ // Do nothing here.
+ }
+
+ /**
+ * This method does
+ * nothing, list children are transient accessible objects which means
+ * that they don't fire property change events.
+ *
+ * @param l not used here
+ */
+ public void removePropertyChangeListener(PropertyChangeListener l)
+ {
+ // Do nothing here.
+ }
+
+ // TODO: Implement the remaining methods of this class.
+ }
+
+ /**
+ * Returns the number of selected accessible children.
+ *
+ * @return the number of selected accessible children
+ */
+ public int getAccessibleSelectionCount()
+ {
+ return getSelectedIndices().length;
+ }
+
+ /**
+ * Returns the n-th selected accessible child.
+ *
+ * @param n the index of the selected child to return
+ *
+ * @return the n-th selected accessible child
+ */
+ public Accessible getAccessibleSelection(int n)
+ {
+ return new AccessibleJListChild(JList.this, getSelectedIndices()[n]);
+ }
+
+ /**
+ * Returns true
if the n-th child is selected,
+ * false
otherwise.
+ *
+ * @param n the index of the child of which the selected state is queried
+ *
+ * @return true
if the n-th child is selected,
+ * false
otherwise
+ */
+ public boolean isAccessibleChildSelected(int n)
+ {
+ return isSelectedIndex(n);
+ }
+
+ /**
+ * Adds the accessible item with the specified index to the selected items.
+ * If multiple selections are supported, the item is added to the selection,
+ * otherwise the item replaces the current selection.
+ *
+ * @param i the index of the item to add to the selection
+ */
+ public void addAccessibleSelection(int i)
+ {
+ addSelectionInterval(i, i);
+ }
+
+ /**
+ * Removes the accessible item with the specified index to the selection.
+ *
+ * @param i the index of the item to be removed from the selection
+ */
+ public void removeAccessibleSelection(int i)
+ {
+ removeSelectionInterval(i, i);
+ }
+
+ /**
+ * Remove all selection items from the selection.
+ */
+ public void clearAccessibleSelection()
+ {
+ clearSelection();
+ }
+
+ /**
+ * Selects all items if multiple selections are supported.
+ * Otherwise do nothing.
+ */
+ public void selectAllAccessibleSelection()
+ {
+ addSelectionInterval(0, getModel().getSize());
+ }
+
+ /**
+ * Receices notification when the list selection is changed. This method
+ * fires two property change events, the first with
+ * address@hidden AccessibleContext#ACCESSIBLE_VISIBLE_DATA_PROPERTY} and the second
+ * with address@hidden AccessibleContext#ACCESSIBLE_SELECTION_PROPERTY}.
+ *
+ * @param event the list selection event
+ */
+ public void valueChanged(ListSelectionEvent event)
+ {
+ firePropertyChange(ACCESSIBLE_VISIBLE_DATA_PROPERTY, Boolean.FALSE,
+ Boolean.TRUE);
+ firePropertyChange(ACCESSIBLE_SELECTION_PROPERTY, Boolean.FALSE,
+ Boolean.TRUE);
+ }
+
+ /**
+ * Receives notification when items have changed in the
+ * JList
. This method fires a property change event with
+ * address@hidden AccessibleContext#ACCESSIBLE_VISIBLE_DATA_PROPERTY}.
+ *
+ * @param event the list data event
+ */
+ public void contentsChanged(ListDataEvent event)
+ {
+ firePropertyChange(ACCESSIBLE_VISIBLE_DATA_PROPERTY, Boolean.FALSE,
+ Boolean.TRUE);
+ }
+
+ /**
+ * Receives notification when items are inserted into the
+ * JList
. This method fires a property change event with
+ * address@hidden AccessibleContext#ACCESSIBLE_VISIBLE_DATA_PROPERTY}.
+ *
+ * @param event the list data event
+ */
+ public void intervalAdded(ListDataEvent event)
+ {
+ firePropertyChange(ACCESSIBLE_VISIBLE_DATA_PROPERTY, Boolean.FALSE,
+ Boolean.TRUE);
+ }
+
+ /**
+ * Receives notification when items are removed from the
+ * JList
. This method fires a property change event with
+ * address@hidden AccessibleContext#ACCESSIBLE_VISIBLE_DATA_PROPERTY}.
+ *
+ * @param event the list data event
+ */
+ public void intervalRemoved(ListDataEvent event)
+ {
+ firePropertyChange(ACCESSIBLE_VISIBLE_DATA_PROPERTY, Boolean.FALSE,
+ Boolean.TRUE);
+ }
+
+
+ /**
+ * Receives notification about changes of the JList
's
+ * properties. This is used to re-register this object as listener to
+ * the data model and selection model when the data model or selection model
+ * changes.
+ *
+ * @param e the property change event
+ */
+ public void propertyChange(PropertyChangeEvent e)
+ {
+ String propertyName = e.getPropertyName();
+ if (propertyName.equals("model"))
+ {
+ ListModel oldModel = (ListModel) e.getOldValue();
+ oldModel.removeListDataListener(this);
+ ListModel newModel = (ListModel) e.getNewValue();
+ newModel.addListDataListener(this);
+ }
+ else if (propertyName.equals("selectionModel"))
+ {
+ ListSelectionModel oldModel = (ListSelectionModel) e.getOldValue();
+ oldModel.removeListSelectionListener(this);
+ ListSelectionModel newModel = (ListSelectionModel) e.getNewValue();
+ oldModel.addListSelectionListener(this);
+ }
+ }
+
+ /**
+ * Return the state set of the JList
.
+ *
+ * @return the state set of the JList
+ */
+ public AccessibleStateSet getAccessibleStateSet()
+ {
+ // TODO: Figure out if there is possibly more state that must be
+ // handled here.
+ AccessibleStateSet s = super.getAccessibleStateSet();
+ if (getSelectionMode() != ListSelectionModel.SINGLE_SELECTION)
+ s.add(AccessibleState.MULTISELECTABLE);
+ return s;
+ }
+
+ /**
+ * Returns the accessible role for JList
,
+ * address@hidden AccessibleRole#LIST}.
+ *
+ * @return the accessible role for JList
+ */
+ public AccessibleRole getAccessibleRole()
+ {
+ return AccessibleRole.LIST;
+ }
+
+ /**
+ * Returns the accessible child at the visual location p
+ * (relative to the upper left corner of the JList
). If there
+ * is no child at that location, this returns null
.
+ *
+ * @param p the screen location for which to return the accessible child
+ *
+ * @return the accessible child at the specified location, or
+ * null
if there is no child at that location
+ */
+ public Accessible getAccessibleAt(Point p)
+ {
+ int childIndex = locationToIndex(p);
+ return getAccessibleChild(childIndex);
+ }
+
+ /**
+ * Returns the number of accessible children in the JList
.
+ *
+ * @return the number of accessible children in the JList
+ */
+ public int getAccessibleChildrenCount()
+ {
+ return getModel().getSize();
+ }
+
+ /**
+ * Returns the n-th accessible child of this JList
. This will
+ * be an instance of address@hidden AccessibleJListChild}. If there is no child
+ * at that index, null
is returned.
+ *
+ * @param n the index of the child to return
+ *
+ * @return the n-th accessible child of this JList
+ */
+ public Accessible getAccessibleChild(int n)
+ {
+ if (getModel().getSize() <= n)
+ return null;
+ return new AccessibleJListChild(JList.this, n);
+ }
+ }
+
private static final long serialVersionUID = 4406629526391098046L;
/**