This is the mail archive of the java-patches@gcc.gnu.org mailing list for the Java project.
| Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
|---|---|---|
| Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |
| Other format: | [Raw text] | |
I just committed this to java-gui-branch. enables somewhat-working JList, JListModel, JListSelectionModel, etc.
* javax/swing/AbstractButton.java: Add "final" qualifiers. * javax/swing/JList.java: Reimplement. * javax/swing/DefaultListSelectionModel.java: Reimplement. * javax/swing/plaf/basic/BasicListUI.java: Reimplement. * javax/swing/plaf/basic/BasicLookAndFeel.java: Add "purple" values. * javax/swing/ListModel.java: Javadoc. * javax/swing/ListSelectionModel.java: Add missing methods. * javax/swing/AbstractListModel.java: Javadoc and corrections. * javax/swing/DefaultListModel.java: Javadoc and corrections. * javax/swing/ListModel.java: Javadoc and corrections. * javax/swing/DefaultListCellRenderer.java: Minor tidying.
--- javax/swing/AbstractButton.java 12 Feb 2004 00:17:23 -0000 1.5
+++ javax/swing/AbstractButton.java 25 Feb 2004 23:56:22 -0000
@@ -233,61 +233,61 @@
PropertyChangeListener actionPropertyChangeListener;
/** Fired in a PropertyChangeEvent when the "borderPainted" property changes. */
- public static String BORDER_PAINTED_CHANGED_PROPERTY = "borderPainted";
+ public static final String BORDER_PAINTED_CHANGED_PROPERTY = "borderPainted";
/** Fired in a PropertyChangeEvent when the "contentAreaFilled" property changes. */
- public static String CONTENT_AREA_FILLED_CHANGED_PROPERTY = "contentAreaFilled";
+ public static final String CONTENT_AREA_FILLED_CHANGED_PROPERTY = "contentAreaFilled";
/** Fired in a PropertyChangeEvent when the "disabledIcon" property changes. */
- public static String DISABLED_ICON_CHANGED_PROPERTY = "disabledIcon";
+ public static final String DISABLED_ICON_CHANGED_PROPERTY = "disabledIcon";
/** Fired in a PropertyChangeEvent when the "disabledSelectedIcon" property changes. */
- public static String DISABLED_SELECTED_ICON_CHANGED_PROPERTY = "disabledSelectedIcon";
+ public static final String DISABLED_SELECTED_ICON_CHANGED_PROPERTY = "disabledSelectedIcon";
/** Fired in a PropertyChangeEvent when the "focusPainted" property changes. */
- public static String FOCUS_PAINTED_CHANGED_PROPERTY = "focusPainted";
+ public static final String FOCUS_PAINTED_CHANGED_PROPERTY = "focusPainted";
/** Fired in a PropertyChangeEvent when the "horizontalAlignment" property changes. */
- public static String HORIZONTAL_ALIGNMENT_CHANGED_PROPERTY = "horizontalAlignment";
+ public static final String HORIZONTAL_ALIGNMENT_CHANGED_PROPERTY = "horizontalAlignment";
/** Fired in a PropertyChangeEvent when the "horizontalTextPosition" property changes. */
- public static String HORIZONTAL_TEXT_POSITION_CHANGED_PROPERTY = "horizontalTextPosition";
+ public static final String HORIZONTAL_TEXT_POSITION_CHANGED_PROPERTY = "horizontalTextPosition";
/** Fired in a PropertyChangeEvent when the "icon" property changes. */
- public static String ICON_CHANGED_PROPERTY = "icon";
+ public static final String ICON_CHANGED_PROPERTY = "icon";
/** Fired in a PropertyChangeEvent when the "margin" property changes. */
- public static String MARGIN_CHANGED_PROPERTY = "margin";
+ public static final String MARGIN_CHANGED_PROPERTY = "margin";
/** Fired in a PropertyChangeEvent when the "mnemonic" property changes. */
- public static String MNEMONIC_CHANGED_PROPERTY = "mnemonic";
+ public static final String MNEMONIC_CHANGED_PROPERTY = "mnemonic";
/** Fired in a PropertyChangeEvent when the "model" property changes. */
- public static String MODEL_CHANGED_PROPERTY = "model";
+ public static final String MODEL_CHANGED_PROPERTY = "model";
/** Fired in a PropertyChangeEvent when the "pressedIcon" property changes. */
- public static String PRESSED_ICON_CHANGED_PROPERTY = "pressedIcon";
+ public static final String PRESSED_ICON_CHANGED_PROPERTY = "pressedIcon";
/** Fired in a PropertyChangeEvent when the "rolloverEnabled" property changes. */
- public static String ROLLOVER_ENABLED_CHANGED_PROPERTY = "rolloverEnabled";
+ public static final String ROLLOVER_ENABLED_CHANGED_PROPERTY = "rolloverEnabled";
/** Fired in a PropertyChangeEvent when the "rolloverIcon" property changes. */
- public static String ROLLOVER_ICON_CHANGED_PROPERTY = "rolloverIcon";
+ public static final String ROLLOVER_ICON_CHANGED_PROPERTY = "rolloverIcon";
/** Fired in a PropertyChangeEvent when the "rolloverSelectedIcon" property changes. */
- public static String ROLLOVER_SELECTED_ICON_CHANGED_PROPERTY = "rolloverSelectedIcon";
+ public static final String ROLLOVER_SELECTED_ICON_CHANGED_PROPERTY = "rolloverSelectedIcon";
/** Fired in a PropertyChangeEvent when the "selectedIcon" property changes. */
- public static String SELECTED_ICON_CHANGED_PROPERTY = "selectedIcon";
+ public static final String SELECTED_ICON_CHANGED_PROPERTY = "selectedIcon";
/** Fired in a PropertyChangeEvent when the "text" property changes. */
- public static String TEXT_CHANGED_PROPERTY = "text";
+ public static final String TEXT_CHANGED_PROPERTY = "text";
/** Fired in a PropertyChangeEvent when the "verticalAlignment" property changes. */
- public static String VERTICAL_ALIGNMENT_CHANGED_PROPERTY = "verticalAlignment";
+ public static final String VERTICAL_ALIGNMENT_CHANGED_PROPERTY = "verticalAlignment";
/** Fired in a PropertyChangeEvent when the "verticalTextPosition" property changes. */
- public static String VERTICAL_TEXT_POSITION_CHANGED_PROPERTY = "verticalTextPosition";
+ public static final String VERTICAL_TEXT_POSITION_CHANGED_PROPERTY = "verticalTextPosition";
/**
* A Java Accessibility extension of the AbstractButton.
@@ -1612,7 +1612,7 @@
*
* @return The current rollover selected icon
*/
- Icon getRolloverSelectedIcon()
+ public Icon getRolloverSelectedIcon()
{
return rollover_selected_icon;
}
@@ -1648,8 +1648,8 @@
*
* @return The current selected icon
*/
- Icon getSelectedIcon()
+ public Icon getSelectedIcon()
{
return selected_icon;
}
--- javax/swing/JList.java 12 Feb 2004 00:17:23 -0000 1.4
+++ javax/swing/JList.java 25 Feb 2004 23:56:23 -0000
@@ -35,10 +35,10 @@
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
-
package javax.swing;
import java.awt.Color;
+import java.awt.Component;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.util.Vector;
@@ -46,92 +46,527 @@
import javax.accessibility.AccessibleContext;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
+import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.plaf.ListUI;
+
+/**
+ * <p>This class is a facade over three separate objects: {@link
+ * javax.swing.ListModel}, {@link javax.swing.ListSelectionModel} and
+ * {@link javax.swing.plaf.ListUI}. The facade represents a unified "list"
+ * concept, with independently replacable (possibly client-provided) models
+ * for its contents and its current selection. In addition, each element in
+ * the list is rendered via a strategy class {@link
+ * javax.swing.ListCellRenderer}.</p>
+ *
+ * <p>Lists have many properties, some of which are stored in this class
+ * while others are delegated to the list's model or selection. The
+ * following properties are available:</p>
+ *
+ * <table>
+ * <tr><th>Property </th><th>Stored in</th><th>Bound?</th></tr>
+ * <tr><td>accessibleContext </td><td>list </td><td>no </td></tr>
+ * <tr><td>anchorSelectionIndex </td><td>selection</td><td>no </td></tr>
+ * <tr><td>cellRenderer </td><td>list </td><td>yes </td></tr>
+ * <tr><td>dragEnabled </td><td>list </td><td>no </td></tr>
+ * <tr><td>firstVisibleIndex </td><td>list </td><td>no </td></tr>
+ * <tr><td>fixedCellHeight </td><td>list </td><td>yes </td></tr>
+ * <tr><td>fixedCellWidth </td><td>list </td><td>yes </td></tr>
+ * <tr><td>lastVisibleIndex </td><td>list </td><td>no </td></tr>
+ * <tr><td>layoutOrientation </td><td>list </td><td>yes </td></tr>
+ * <tr><td>leadSelectionIndex </td><td>selection</td><td>no </td></tr>
+ * <tr><td>maxSelectionIndex </td><td>selection</td><td>no </td></tr>
+ * <tr><td>minSelectionIndex </td><td>selection</td><td>no </td></tr>
+ * <tr><td>model </td><td>list </td><td>yes </td></tr>
+ * <tr><td>opaque </td><td>list </td><td>no </td></tr>
+ * <tr><td>preferredScrollableViewportSize</td><td>list </td><td>no </td></tr>
+ * <tr><td>prototypeCellValue </td><td>list </td><td>yes </td></tr>
+ * <tr><td>scrollableTracksViewportHeight </td><td>list </td><td>no </td></tr>
+ * <tr><td>scrollableTracksViewportWidth </td><td>list </td><td>no </td></tr>
+ * <tr><td>selectedIndex </td><td>selection</td><td>no </td></tr>
+ * <tr><td>selectedIndices </td><td>selection</td><td>no </td></tr>
+ * <tr><td>selectedValue </td><td>model </td><td>no </td></tr>
+ * <tr><td>selectedValues </td><td>model </td><td>no </td></tr>
+ * <tr><td>selectionBackground </td><td>list </td><td>yes </td></tr>
+ * <tr><td>selectionEmpty </td><td>selection</td><td>no </td></tr>
+ * <tr><td>selectionForeground </td><td>list </td><td>yes </td></tr>
+ * <tr><td>selectionMode </td><td>selection</td><td>no </td></tr>
+ * <tr><td>selectionModel </td><td>list </td><td>yes </td></tr>
+ * <tr><td>UI </td><td>list </td><td>yes </td></tr>
+ * <tr><td>UIClassID </td><td>list </td><td>no </td></tr>
+ * <tr><td>valueIsAdjusting </td><td>list </td><td>no </td></tr>
+ * <tr><td>visibleRowCount </td><td>list </td><td>no </td></tr>
+ * </table>
+ *
+ * @author Graydon Hoare (graydon&064;redhat.com)
+ */
+
public class JList extends JComponent implements Accessible, Scrollable
{
private static final long serialVersionUID = 4406629526391098046L;
- Color select_back, select_fore;
- ListCellRenderer render;
- int visibles = 8;
+ /**
+ * Constant value used in "layoutOrientation" property. This value means
+ * that cells are laid out in multiple columns "newspaper style",
+ * filling horizontally first, then vertically.
+ */
+ public static int HORIZONTAL_WRAP = 1;
+
+ /**
+ * Constant value used in "layoutOrientation" property. This value means
+ * that cells are laid out in a single vertical column. This is the default.
+ */
+ public static int VERTICAL = 2;
+
+ /**
+ * Constant value used in "layoutOrientation" property. This value means
+ * that cells are laid out in multiple columns "newspaper style", filling
+ * vertically first, then horizontally.
+ */
+ public static int VERTICAL_WRAP = 3;
+
+ /** Fired in a PropertyChangeEvent when the "cellRenderer" property changes. */
+ public static final String CELL_RENDERER_PROPERTY_CHANGED = "cellRenderer";
+
+ /** Fired in a PropertyChangeEvent when the "fixedCellHeight" property changes. */
+ public static final String FIXED_CELL_HEIGHT_PROPERTY_CHANGED = "fixedCellHeight";
+
+ /** Fired in a PropertyChangeEvent when the "fixedCellWidth" property changes. */
+ public static final String FIXED_CELL_WIDTH_PROPERTY_CHANGED = "fixedCellWidth";
+
+ /** Fired in a PropertyChangeEvent when the "layoutOrientation" property changes. */
+ public static final String LAYOUT_ORIENTATION_PROPERTY_CHANGED = "layoutOrientation";
+
+ /** Fired in a PropertyChangeEvent when the "model" property changes. */
+ public static final String MODEL_PROPERTY_CHANGED = "model";
+
+ /** Fired in a PropertyChangeEvent when the "prototypeCellValue" property changes. */
+ public static final String PROTOTYPE_CELL_VALUE_PROPERTY_CHANGED = "prototypeCellValue";
+
+ /** Fired in a PropertyChangeEvent when the "selectionBackground" property changes. */
+ public static final String SELECTION_BACKGROUND_PROPERTY_CHANGED = "selectionBackground";
+
+ /** Fired in a PropertyChangeEvent when the "selectionForeground" property changes. */
+ public static final String SELECTION_FOREGROUND_PROPERTY_CHANGED = "selectionForeground";
+
+ /** Fired in a PropertyChangeEvent when the "selectionModel" property changes. */
+ public static final String SELECTION_MODEL_PROPERTY_CHANGED = "selectionModel";
+
+
+ /**
+ * This property indicates whether "drag and drop" functions are enabled
+ * on the list.
+ */
+ boolean dragEnabled;
+
+ /** This property provides a strategy for rendering cells in the list. */
+ ListCellRenderer cellRenderer;
+
+ /**
+ * This property indicates an fixed width to assign to all cells in the
+ * list. If its value is <code>-1</code>, no width has been
+ * assigned. This value can be set explicitly, or implicitly by setting
+ * the {@link #prototypeCellValue} property.
+ */
+ int fixedCellWidth;
+
+ /**
+ * This property indicates an fixed height to assign to all cells in the
+ * list. If its value is <code>-1</code>, no height has been
+ * assigned. This value can be set explicitly, or implicitly by setting
+ * the {@link #prototypeCellValue} property.
+ */
+ int fixedCellHeight;
+
+ /**
+ * This property holds the current layout orientation of the list, which
+ * is one of the integer constants {@link #VERTICAL}, {@link
+ * #VERTICAL_WRAP}, or {@link #HORIZONTAL_WRAP}.
+ */
+
+ int layoutOrientation;
+ /** This property holds the data elements displayed by the list. */
ListModel model;
- ListSelectionModel sel_model;
+ /**
+ * <p>This property holds a reference to a "prototype" data value --
+ * typically a String -- which is used to calculate the {@link
+ * #fixedCellWidth} and {@link #fixedCellHeight} properties, using the
+ * {@link #cellRenderer} property to acquire a component to render the
+ * prototype.</p>
+ *
+ * <p>It is important that you <em>not</em> set this value to a
+ * component. It has to be a <em>data value</em> such as the objects you
+ * would find in the list's model. Setting it to a component will have
+ * undefined (and undesirable) affects. </p>
+ */
+ Object prototypeCellValue;
+
+ /**
+ * This property specifies a foreground color for the selected cells in
+ * the list. When {@link ListCellRenderer.getListCellRendererComponent}
+ * is called with a selected cell object, the component returned will
+ * have its "foreground" set to this color.
+ */
+ Color selectionBackground;
+
+ /**
+ * This property specifies a background color for the selected cells in
+ * the list. When {@link ListCellRenderer.getListCellRendererComponent}
+ * is called with a selected cell object, the component returned will
+ * have its "background" property set to this color.
+ */
+ Color selectionForeground;
+
+ /**
+ * This property holds a description of which data elements in the {@link
+ * #model} property should be considered "selected", when displaying and
+ * interacting with the list.
+ */
+ ListSelectionModel selectionModel;
+
+
+ /**
+ * This property indicates that the list's selection is currently
+ * "adjusting" -- perhaps due to a user actively dragging the mouse over
+ * multiple list elements -- and is therefore likely to change again in
+ * the near future. A {@link ListSelectionListener} might choose to delay
+ * updating its view of the list's selection until this property is
+ * false, meaning that the adjustment has completed.
+ */
+ boolean valueIsAdjusting;
+
+ /**
+ * This property indicates a <em>preference</em> for the number of rows
+ * displayed in the list, and will scale the
+ * {@link #preferredScrollableViewportSize} property accordingly. The actual
+ * number of displayed rows, when the list is placed in a real {@link
+ * Viewport} or other component, may be greater or less than this number.
+ */
+ int visibleRowCount;
+
+
+
+ /**
+ * Fire a {@link ListSelectionEvent} to all the registered ListSelectionListeners.
+ */
+ void fireSelectionValueChanged(int firstIndex, int lastIndex, boolean isAdjusting)
+ {
+ ListSelectionEvent evt = new ListSelectionEvent(this, firstIndex, lastIndex, isAdjusting);
+ ListSelectionListener listeners[] = getListSelectionListeners();
+ for (int i = 0; i < listeners.length; ++i)
+ {
+ listeners[i].valueChanged(evt);
+ }
+ }
+
+
+ /**
+ * This private listener propagates {@link ListSelectionEvent} events
+ * from the list's "selectionModel" property to the list's {@link
+ * ListSelectionListener} listeners. It also listens to {@link
+ * ListDataEvent} events from the list's {@link #model} property. If this
+ * class receives either type of event, it triggers repainting of the
+ * list.
+ */
+ private class ListListener
+ implements ListSelectionListener, ListDataListener
+ {
+ // ListDataListener events
+ public void contentsChanged(ListDataEvent event)
+ {
+ JList.this.repaint();
+ }
+ public void intervalAdded(ListDataEvent event)
+ {
+ JList.this.repaint();
+ }
+ public void intervalRemoved(ListDataEvent event)
+ {
+ JList.this.repaint();
+ }
+ // ListSelectionListener events
+ public void valueChanged(ListSelectionEvent event)
+ {
+ JList.this.fireSelectionValueChanged(event.firstIndex,
+ event.lastIndex,
+ event.isAdjusting);
+ JList.this.repaint();
+ }
+ };
+
+ /**
+ * Shared ListListener instance, subscribed to both the current {@link
+ * #model} and {@link #selectionModel} properties of the list.
+ */
+ ListListener listListener;
+
+
+ /**
+ * Creates a new JList object.
+ */
public JList()
{
init();
}
+ /**
+ * Creates a new JList object.
+ *
+ * @param listData Initial data to populate the list with
+ */
public JList(Object[] listData)
{
init();
setListData(listData);
}
-
+ /**
+ * Creates a new JList object.
+ *
+ * @param listData Initial data to populate the list with
+ */
public JList(Vector listData)
{
init();
setListData(listData);
}
-
+ /**
+ * Creates a new JList object.
+ *
+ * @param listData Initial data to populate the list with
+ */
public JList(ListModel listData)
{
init();
setModel(listData);
}
+
void init()
{
- render = new DefaultCellRenderer();
+ dragEnabled = false;
+ fixedCellHeight = -1;
+ fixedCellWidth = -1;
+ layoutOrientation = VERTICAL;
+ opaque = true;
+ valueIsAdjusting = false;
+ visibleRowCount = 8;
- sel_model = new DefaultListSelectionModel();
- setModel(new DefaultListModel());
+ cellRenderer = new DefaultListCellRenderer();
+ listListener = new ListListener();
- select_back = new Color(0,0,255);
- select_fore = new Color(255,255,255);
+ setModel(new DefaultListModel());
+ setSelectionModel(new DefaultListSelectionModel());
updateUI();
}
+ /**
+ * Gets the value of the {@link #fixedCellHeight} property. This property
+ * may be <code>-1</code> to indicate that no cell height has been
+ * set. This property is also set implicitly when the
+ * {@link #prototypeCellValue} property is set.
+ *
+ * @return The current value of the property
+ *
+ * @see #fixedCellHeight
+ * @see #setFixedCellHeight
+ * @see #setPrototypeCellValue
+ */
+ public int getFixedCellHeight()
+ {
+ return fixedCellHeight;
+ }
+
+ /**
+ * Sets the value of the {@link #fixedCellHeight} property. This property
+ * may be <code>-1</code> to indicate that no cell height has been
+ * set. This property is also set implicitly when the {@link
+ * #prototypeCellValue} property is set, but setting it explicitly
+ * overrides the height computed from {@link #prototypeCellValue}.
+ *
+ * @see #getFixedCellHeight
+ * @see #getPrototypeCellValue
+ */
+ public void setFixedCellHeight(int h)
+ {
+ int old = fixedCellHeight;
+ fixedCellHeight = h;
+ firePropertyChange(FIXED_CELL_WIDTH_PROPERTY_CHANGED, old, h);
+ }
+
+
+ /**
+ * Gets the value of the {@link #fixedCellWidth} property. This property
+ * may be <code>-1</code> to indicate that no cell width has been
+ * set. This property is also set implicitly when the {@link
+ * #prototypeCellValue} property is set.
+ *
+ * @return The current value of the property
+ *
+ * @see #setFixedCellWidth
+ * @see #setPrototypeCellValue
+ */
+ public int getFixedCellWidth()
+ {
+ return fixedCellWidth;
+ }
+
+ /**
+ * Sets the value of the {@link #fixedCellWidth} property. This property
+ * may be <code>-1</code> to indicate that no cell width has been
+ * set. This property is also set implicitly when the {@link
+ * #prototypeCellValue} property is set, but setting it explicitly
+ * overrides the width computed from {@link #prototypeCellValue}.
+ *
+ * @see #getFixedCellWidth
+ * @see #getPrototypeCellValue
+ */
+ public void setFixedCellWidth(int h)
+ {
+ int old = fixedCellHeight;
+ fixedCellHeight = h;
+ firePropertyChange(FIXED_CELL_HEIGHT_PROPERTY_CHANGED, old, h);
+ }
+
+
+ /**
+ * Gets the value of the {@link #visibleRowCount} property.
+ *
+ * @return the current value of the property.
+ */
public int getVisibleRowCount()
- { return visibles; }
- public void setVisibleRowCount(int visibleRowCount)
{
- visibles = visibleRowCount;
- invalidate();
+ return visibleRowCount;
+ }
+
+ /**
+ * Sets the value of the {@link #visibleRowCount} property.
+ *
+ * @param visibleRowCount The new property value
+ */
+ public void setVisibleRowCount(int vc)
+ {
+ visibleRowCount = vc;
+ revalidate();
repaint();
}
+ /**
+ * Adds a {@link ListSelectionListener} to the listener list for this
+ * list. The listener will be called back with a {@link
+ * ListSelectionEvent} any time the list's {@link #selectionModel}
+ * property changes. The source of such events will be the JList,
+ * not the selection model.
+ *
+ * @param listener The new listener to add
+ */
public void addListSelectionListener (ListSelectionListener listener)
{
- sel_model.addListSelectionListener (listener);
+ listenerList.add (ListSelectionListener.class, listener);
}
+ /**
+ * Removes a {@link ListSelectionListener} from the listener list for
+ * this list. The listener will no longer be called when the list's
+ * {@link #selectionModel} changes.
+ *
+ * @param listener The listener to remove
+ */
public void removeListSelectionListener (ListSelectionListener listener)
{
- sel_model.removeListSelectionListener (listener);
+ listenerList.remove(ListSelectionListener.class, listener);
}
/**
+ * Returns an array of all ListSelectionListeners subscribed to this
+ * list.
+ *
+ * @return The current subscribed listeners
+ *
* @since 1.4
*/
public ListSelectionListener[] getListSelectionListeners()
{
- throw new Error ("not implemented");
+ return (ListSelectionListener[]) getListeners(ListSelectionListener.class);
+ }
+
+ /**
+ * Sets the list's "selectionMode" property, which simply mirrors the
+ * same property on the list's {@link #selectionModel} property. This
+ * property should be one of the integer constants
+ * <code>SINGLE_SELECTION</code>, <code>SINGLE_INTERVAL_SELECTION</code>,
+ * or <code>MULTIPLE_INTERVAL_SELECTION</code> from the {@link
+ * ListSelectionModel} interface.
+ *
+ * @param a The new selection mode
+ */
+ public void setSelectionMode(int a)
+ {
+ selectionModel.setSelectionMode(a);
}
- void setSelectionMode(int a)
- { sel_model.setSelectionMode(a); }
- void setSelectedIndex(int a)
- { sel_model.setSelectionInterval(a,a); }
- int getSelectedIndex()
- { return sel_model.getMinSelectionIndex(); }
- Object getSelectedValue()
+ /**
+ * Adds the interval <code>[a,a]</code> to the set of selections managed
+ * by this list's {@link #selectionModel} property. Depending on the
+ * selection mode, this may cause existing selections to become invalid,
+ * or may simply expand the set of selections.
+ *
+ * @param a A number in the half-open range <code>[0, x)</code> where
+ * <code>x = getModel.getSize()</code>, indicating the index of an
+ * element in the list to select.
+ *
+ * @see #setSelectionMode
+ * @see #selectionModel
+ */
+ public void setSelectedIndex(int a)
+ {
+ selectionModel.setSelectionInterval(a, a);
+ }
+
+ /**
+ * Returns the minimum index of an element in the list which is currently
+ * selected.
+ *
+ * @return A number in the half-open range <code>[0, x)</code> where
+ * <code>x = getModel.getSize()</code>, indicating the minimum index of
+ * an element in the list for which the element is selected, or
+ * <code>-1</code> if no elements are selected
+ */
+ public int getSelectedIndex()
+ {
+ return selectionModel.getMinSelectionIndex();
+ }
+
+ /**
+ * Indicates whether the list element at a given index value is
+ * currently selected.
+ *
+ * @param a The index to check
+ * @return <code>true</code> if <code>a</code> is the index of a selected
+ * list element
+ */
+ public boolean isSelectedIndex(int a)
+ {
+ return selectionModel.isSelectedIndex(a);
+ }
+
+ /**
+ * Returns the first value in the list's {@link #model} property which is
+ * selected, according to the list's {@link #selectionModel} property.
+ * This is equivalent to calling
+ * <code>getModel()getElementAt(getSelectedIndex())</code>, with a check
+ * for the special index value of <code>-1</code> which returns null
+ * <code>null</code>.
+ *
+ * @return The first selected element, or <code>null</code> if no element
+ * is selected.
+ */
+ public Object getSelectedValue()
{
int index = getSelectedIndex();
if (index == -1)
@@ -139,116 +574,360 @@
return getModel().getElementAt(index);
}
- Color getSelectionBackground()
- { return select_back; }
- Color getSelectionForeground()
- { return select_fore; }
+ /**
+ * Gets the value of the {@link #selectionBackground} property.
+ *
+ * @return The current value of the property
+ */
+ public Color getSelectionBackground()
+ {
+ return selectionBackground;
+ }
+
+ /**
+ * Sets the value of the {@link #selectionBackground} property.
+ *
+ * @param c The new value of the property
+ */
+ public void setSelectionBackground(Color c)
+ {
+ Color old = selectionBackground;
+ selectionBackground = c;
+ firePropertyChange(SELECTION_BACKGROUND_PROPERTY_CHANGED, old, c);
+ repaint();
+ }
+ /**
+ * Gets the value of the {@link #selectionForeground} property.
+ *
+ * @return The current value of the property
+ */
+ public Color getSelectionForeground()
+ {
+ return selectionForeground;
+ }
+
+ /**
+ * Sets the value of the {@link #selectionForeground} property.
+ *
+ * @param c The new value of the property
+ */
+ public void setSelectionForeground(Color c)
+ {
+ Color old = selectionForeground;
+ selectionForeground = c;
+ firePropertyChange(SELECTION_FOREGROUND_PROPERTY_CHANGED, old, c);
+ }
+ /**
+ * Sets the {@link #model} property of the list to a new anonymous
+ * {@link AbstractListModel} subclass which accesses the provided Object
+ * array directly.
+ *
+ * @param listData The object array to build a new list model on
+ * @see #setModel
+ */
public void setListData(final Object[] listData)
{
- class AL extends AbstractListModel
+ setModel(new AbstractListModel()
{
- public int getSize() { return listData.length; }
- public Object getElementAt(int i) { return listData[i]; }
- };
+ public int getSize()
+ {
+ return listData.length;
+ }
- setModel (new AL());
+ public Object getElementAt(int i)
+ {
+ return listData[i];
+ }
+ });
}
+ /**
+ * Sets the {@link #model} property of the list to a new anonymous {@link
+ * AbstractListModel} subclass which accesses the provided vector
+ * directly.
+ *
+ * @param listData The object array to build a new list model on
+ * @see #setModel
+ */
public void setListData(final Vector listData)
{
- class AL extends AbstractListModel
+ setModel(new AbstractListModel()
{
- public int getSize() { return listData.size(); }
- public Object getElementAt(int i) { return listData.elementAt(i); }
- };
-
- setModel (new AL());
+ public int getSize()
+ {
+ return listData.size();
}
+ public Object getElementAt(int i)
+ {
+ return listData.elementAt(i);
+ }
+ });
+ }
+ /**
+ * Gets the value of the {@link #cellRenderer} property.
+ *
+ * @return The current value of the property
+ */
public ListCellRenderer getCellRenderer()
- { return render; }
- public void setCellRenderer(ListCellRenderer cellRenderer)
{
- render = cellRenderer;
- invalidate();
- repaint();
+ return cellRenderer;
}
- public void setModel(ListModel model)
- {
- ListDataListener l = new ListDataListener()
+ /**
+ * Sets the value of the {@link #celLRenderer} property.
+ *
+ * @param cellRenderer The new property value
+ */
+ public void setCellRenderer(ListCellRenderer cr)
{
- public void intervalAdded(ListDataEvent e) {
- repaint();
- }
- public void intervalRemoved(ListDataEvent e) {
+ ListCellRenderer old = cellRenderer;
+ cellRenderer = cr;
+ firePropertyChange(CELL_RENDERER_PROPERTY_CHANGED, old, cr);
+ revalidate();
repaint();
}
- public void contentsChanged(ListDataEvent e) {
- repaint();
+
+ /**
+ * Gets the value of the {@link #model} property.
+ *
+ * @return The current value of the property
+ */
+ public ListModel getModel()
+ {
+ return model;
}
- };
- this.model = model;
- model.addListDataListener(l);
+ /**
+ * Sets the value of the {@link #model} property. The list's {@link
+ * #listListener} is unsubscribed from the existing model, if it exists,
+ * and re-subscribed to the new model.
+ *
+ * @param model The new property value
+ */
+ public void setModel(ListModel m)
+ {
+ ListModel old = model;
+ if (old != null)
+ old.removeListDataListener(listListener);
+ model = m;
+ if (model != null)
+ model.addListDataListener(listListener);
+ firePropertyChange(MODEL_PROPERTY_CHANGED, old, m);
}
- public ListModel getModel()
- { return model; }
+ public ListSelectionModel getSelectionModel()
+ {
+ return selectionModel;
+ }
+ /**
+ * Sets the value of the {@link #selectionModel} property. The list's
+ * {@link #listListener} is unsubscribed from the existing selection
+ * model, if it exists, and re-subscribed to the new selection model.
+ *
+ * @param l The new property value
+ */
+ public void setSelectionModel(ListSelectionModel l)
+ {
+ ListSelectionModel old = selectionModel;
+ if (old != null)
+ old.removeListSelectionListener(listListener);
+ selectionModel = l;
+ if (selectionModel != null)
+ selectionModel.addListSelectionListener(listListener);
+ firePropertyChange(SELECTION_MODEL_PROPERTY_CHANGED, old, l);
+ }
+
+ /**
+ * Gets the value of the UI property.
+ *
+ * @return The current property value
+ */
public ListUI getUI()
- { return (ListUI) ui; }
+ {
+ return (ListUI) ui;
+ }
+
+ /**
+ * Sets the value of the UI property.
+ *
+ * @param ui The new property value
+ */
public void setUI(ListUI ui)
- { super.setUI(ui); }
+ {
+ super.setUI(ui);
+ }
+ /**
+ * Calls {@link #setUI} with the {@link ListUI} subclass
+ * returned from calling {@link UIManager#getUI}.
+ */
public void updateUI()
{
setUI((ListUI)UIManager.getUI(this));
}
+ /**
+ * Return the class identifier for the list's UI property. This should
+ * be the constant string <code>"ListUI"</code>, and map to an
+ * appropriate UI class in the {@link UIManager}.
+ *
+ * @return The class identifier
+ */
public String getUIClassID()
{
return "ListUI";
}
+ /**
+ * Returns the current value of the {@link #prototypeCellValue}
+ * property. This property holds a reference to a "prototype" data value
+ * -- typically a String -- which is used to calculate the {@link
+ * #fixedCellWidth} and {@link #fixedCellHeight} properties, using the
+ * {@link #cellRenderer} property to acquire a component to render the
+ * prototype.
+ *
+ * @return The current prototype cell value
+ * @see #setPrototypeCellValue
+ */
+ public Object getPrototypeCellValue()
+ {
+ return prototypeCellValue;
+ }
+
+ /**
+ * <p>Set the {@link #prototypeCellValue} property. This property holds a
+ * reference to a "prototype" data value -- typically a String -- which
+ * is used to calculate the {@link #fixedCellWidth} and {@link
+ * #fixedCellHeight} properties, using the {@link #cellRenderer} property
+ * to acquire a component to render the prototype.</p>
+ *
+ * <p>It is important that you <em>not</em> set this value to a
+ * component. It has to be a <em>data value</em> such as the objects you
+ * would find in the list's model. Setting it to a component will have
+ * undefined (and undesirable) affects. </p>
+ *
+ * @param obj The new prototype cell value
+ * @see #getPrototypeCellValue
+ */
+ public void setPrototypeCellValue(Object obj)
+ {
+ Object old = prototypeCellValue;
+ Component comp = getCellRenderer()
+ .getListCellRendererComponent(this, obj, 0, false, false);
+ Dimension d = comp.getPreferredSize();
+ fixedCellWidth = d.width;
+ fixedCellHeight = d.height;
+ prototypeCellValue = obj;
+ firePropertyChange(PROTOTYPE_CELL_VALUE_PROPERTY_CHANGED, old, obj);
+ }
+
public AccessibleContext getAccessibleContext()
{
return null;
}
+ /**
+ * Returns a size indicating how much space this list would like to
+ * consume, when contained in a scrollable viewport. This is part of the
+ * {@link Scrollable} interface, which interacts with {@link
+ * ScrollPaneLayout} and {@link Viewport} to define scrollable objects.
+ *
+ * @return The preferred size, or <code>null</code>
+ */
public Dimension getPreferredScrollableViewportSize()
{
return null;
}
+ /**
+ * <p>Return the number of pixels the list must scroll in order to move a
+ * "unit" of the list into the provided visible rectangle. When the
+ * provided direction is positive, the call describes a "downwards"
+ * scroll, which will be exposing a cell at a <em>greater</em> index in
+ * the list than those elements currently showing. Then the provided
+ * direction is negative, the call describes an "upwards" scroll, which
+ * will be exposing a cell at a <em>lesser</em> index in the list than
+ * those elements currently showing.</p>
+ *
+ * <p>If the provided orientation is <code>HORIZONTAL</code>, the above
+ * comments refer to "rightwards" for positive direction, and "leftwards"
+ * for negative.</p>
+ *
+ *
+ * @param visibleRect The rectangle to scroll an element into
+ * @param orientation One of the numeric consants <code>VERTICAL</code>
+ * or <code>HORIZONTAL</code>
+ * @param direction An integer indicating the scroll direction: positive means
+ * forwards (down, right), negative means backwards (up, left)
+ *
+ * @return The scrollable unit increment, in pixels
+ */
public int getScrollableUnitIncrement(Rectangle visibleRect,
- int orientation,
- int direction)
+ int orientation, int direction)
{
return 1;
}
+ /**
+ * <p>Return the number of pixels the list must scroll in order to move a
+ * "block" of the list into the provided visible rectangle. When the
+ * provided direction is positive, the call describes a "downwards"
+ * scroll, which will be exposing a cell at a <em>greater</em> index in
+ * the list than those elements currently showing. Then the provided
+ * direction is negative, the call describes an "upwards" scroll, which
+ * will be exposing a cell at a <em>lesser</em> index in the list than
+ * those elements currently showing.</p>
+ *
+ * <p>If the provided orientation is <code>HORIZONTAL</code>, the above
+ * comments refer to "rightwards" for positive direction, and "leftwards"
+ * for negative.</p>
+ *
+ *
+ * @param visibleRect The rectangle to scroll an element into
+ * @param orientation One of the numeric consants <code>VERTICAL</code>
+ * or <code>HORIZONTAL</code>
+ * @param direction An integer indicating the scroll direction: positive means
+ * forwards (down, right), negative means backwards (up, left)
+ *
+ * @return The scrollable unit increment, in pixels
+ */
public int getScrollableBlockIncrement(Rectangle visibleRect,
- int orientation,
- int direction)
+ int orientation, int direction)
{
return 1;
}
+ /**
+ * Gets the value of the {@link #scrollableTracksViewportWidth} property.
+ *
+ * @return <code>true</code> if the viewport is larger (horizontally)
+ * than the list and the list should be expanded to fit the viewport;
+ * <code>false</code> if the viewport is smaller than the list and the
+ * list should scroll (horizontally) within the viewport
+ */
public boolean getScrollableTracksViewportWidth()
{
return false;
}
+ /**
+ * Gets the value of the {@link #scrollableTracksViewportWidth} property.
+ *
+ * @return <code>true</code> if the viewport is larger (vertically)
+ * than the list and the list should be expanded to fit the viewport;
+ * <code>false</code> if the viewport is smaller than the list and the
+ * list should scroll (vertically) within the viewport
+ */
public boolean getScrollableTracksViewportHeight()
{
return false;
}
-
}
--- javax/swing/DefaultListSelectionModel.java 27 Jan 2004 18:55:11 -0000 1.4
+++ javax/swing/DefaultListSelectionModel.java 25 Feb 2004 23:56:23 -0000
@@ -35,141 +35,506 @@
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
-
package javax.swing;
import java.io.Serializable;
import java.util.EventListener;
-import java.util.Vector;
+import java.util.BitSet;
import javax.swing.event.EventListenerList;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
-public class DefaultListSelectionModel implements Cloneable, ListSelectionModel, Serializable
+
+/**
+ * <p>This class provides a default implementation of {@link
+ * ListSelectioModel}, which is used by {@link javax.swing.JList} and
+ * similar classes to manage the selection status of a number of data
+ * elements. </p>
+ *
+ * <p>The class is organized <em>abstractly</em> as a set of intervals of
+ * integers. Each interval indicates an inclusive range of indices in a
+ * list -- held by some other object and unknown to this class -- which is
+ * considered "selected". There are various accessors for querying and
+ * modifying the set of intervals, with simplified forms accepting a single
+ * index, representing an interval with only one element. </p>
+ */
+public class DefaultListSelectionModel implements Cloneable,
+ ListSelectionModel,
+ Serializable
{
+
+ /** The list of ListSelectionListeners subscribed to this selection model. */
protected EventListenerList listenerList = new EventListenerList();
- int mode = SINGLE_SELECTION;
- Vector sel = new Vector();
+ /**
+ * The current list selection mode. Must be one of the numeric constants
+ * <code>SINGLE_SELECTION</code>, <code>SINGLE_INTERVAL_SELECTION</code>
+ * or <code>MULTIPLE_INTERVAL_SELECTION</code> from {@link
+ * ListSelectionModel}. The default value is
+ * <code>MULTIPLE_INTERVAL_SELECTION</code>.
+ */
+ int selectionMode = MULTIPLE_INTERVAL_SELECTION;
- class Range
- {
- int i0, i1;
- Range(int a, int b)
- {
- if (a > b)
+ /**
+ * The index of the "lead" of the most recent selection. The lead is the
+ * second argument in any call to {@link #setSelectionInterval}, {@link
+ * #addSelectionInterval} or {@link #removeSelectionInterval}. Generally
+ * the lead refers to the most recent position a user dragged their mouse
+ * over.
+ */
+ int leadSelectionIndex = -1;
+
+
+ /**
+ * The index of the "anchor" of the most recent selection. The anchor is
+ * the first argument in any call to {@link #setSelectionInterval},
+ * {@link #addSelectionInterval} or {@link
+ * #removeSelectionInterval}. Generally the anchor refers to the first
+ * recent position a user clicks when they begin to drag their mouse over
+ * a list.
+ *
+ * @see #getAnchorSelectionIndex
+ * @see #setAnchorSelectionIndex
+ */
+ int anchorSelectionIndex = -1;
+
+
+ /**
+ * controls the range of indices provided in any {@link
+ * ListSelectionEvent} fired by the selectionModel. Let
+ * <code>[A,L]</code> be the range of indices between {@link
+ * anchorSelectionIndex} and {@link leadSelectionIndex} inclusive, and
+ * let <code>[i0,i1]</code> be the range of indices changed in a given
+ * call which generates a {@link ListSelectionEvent}. Then when this
+ * property is <code>true</code>, the {@link ListSelectionEvent} contains
+ * the range <code>[A,L] union [i0,i1]</code>; when <code>false</code> it
+ * will contain only <code>[i0,i1]</code>. The default is
+ * <code>true</code>.
+ *
+ * @see #isLeadAnchorNotificationEnabled
+ * @see #setLeadAnchorNotificationEnabled
+ */
+ boolean leadAnchorNotificationEnabled = true;
+
+
+ /**
+ * Whether the selection is currently "adjusting". Any {@link
+ * ListSelectionEvent} events constructed in response to changes in this
+ * list selection model will have their {@link
+ * ListSelectionEvent#isAdjusting} field set to this value.
+ *
+ * @see #getValueIsAdjusting
+ * @see #setValueIsAdjusting
+ */
+ boolean valueIsAdjusting = false;
+
+
+ /**
+ * The current set of "intervals", represented simply by a {@link
+ * java.util.BitSet}. A set bit indicates a selected index, whereas a
+ * cleared bit indicates a non-selected index.
+ */
+ BitSet sel = new BitSet();
+
+
+ /**
+ * Gets the value of the {@link #selectionMode} property.
+ *
+ * @return The current value of the property
+ */
+ public int getSelectionMode()
{
- i0 = b;
- i1 = a;
+ return selectionMode;
}
- else
+
+ /**
+ * Sets the value of the {@link #selectionMode} property.
+ *
+ * @param a The new value of the property
+ */
+ public void setSelectionMode(int a)
{
- i0 = a;
- i1 = b;
- }
+ selectionMode = a;
}
+
+ /**
+ * Gets the value of the {@link #anchorSelectionIndex} property.
+ *
+ * @return The current property value
+ *
+ * @see #setAnchorSelectionIndex
+ */
+ public int getAnchorSelectionIndex()
+ {
+ return anchorSelectionIndex;
}
+ /**
+ * Sets the value of the {@link #anchorSelectionIndex} property.
+ *
+ * @param anchorIndex The new property value
+ *
+ * @see #getAnchorSelectionIndex
+ */
+ public void setAnchorSelectionIndex(int anchorIndex)
+ {
+ anchorSelectionIndex = anchorIndex;
+ }
- public int getMinSelectionIndex()
+ /**
+ * Gets the value of the {@link #leadSelectionIndex} property.
+ *
+ * @return The current property value
+ *
+ * @see #setLeadSelectionIndex
+ */
+ public int getLeadSelectionIndex()
{
- if (isSelectionEmpty())
- return -1;
+ return leadSelectionIndex;
+ }
- boolean first = true;
- int min = -1;
- for (int i=0;i<sel.size();i++)
+ /**
+ * <p>Sets the value of the {@link #anchorSelectionIndex} property. As a
+ * side effect, alters the selection status of two ranges of indices. Let
+ * <code>OL</code> be the old lead selection index, <code>NL</code> be
+ * the new lead selection index, and <code>A</code> be the anchor
+ * selection index. Then if <code>A</code> is a valid selection index,
+ * one of two things happens depending on the seleciton status of
+ * <code>A</code>:</p>
+ *
+ * <ul>
+ *
+ * <li><code>isSelectedIndex(A) == true</code>: set <code>[A,OL]</code>
+ * to <em>deselected</em>, then set <code>[A,NL]</code> to
+ * <em>selected</em>.</li>
+ *
+ * <li><code>isSelectedIndex(A) == false</code>: set <code>[A,OL]</code>
+ * to <em>selected</em>, then set <code>[A,NL]</code> to
+ * <em>deselected</em>.</li>
+ *
+ * </ul>
+ *
+ * <p>This method generates at most a single {@link ListSelectionEvent}
+ * despite changing multiple ranges. The range of values provided to the
+ * {@link ListSelectionEvent} includes only the minimum range of values
+ * which changed selection status between the beginning and end of the
+ * method.</p>
+ *
+ * @param anchorIndex The new property value
+ *
+ * @see #getAnchorSelectionIndex
+ */
+ public void setLeadSelectionIndex(int leadIndex)
{
- Range r = (Range) sel.get(i);
+ int oldLeadIndex = leadSelectionIndex;
+ leadSelectionIndex = leadIndex;
+
+ if (anchorSelectionIndex == -1)
+ return;
+
+ int R1 = Math.min(anchorSelectionIndex, oldLeadIndex);
+ int R2 = Math.max(anchorSelectionIndex, oldLeadIndex);
+ int S1 = Math.min(anchorSelectionIndex, leadIndex);
+ int S2 = Math.max(anchorSelectionIndex, leadIndex);
- if (first)
+ int lo = Math.min(R1, S1);
+ int hi = Math.max(R2, S2);
+
+ BitSet oldRange = sel.get(lo, hi+1);
+
+ if (isSelectedIndex(anchorSelectionIndex))
{
- min = r.i0;
- first = false;
+ sel.clear(R1, R2+1);
+ sel.set(S1, S2+1);
}
else
{
- if (r.i0 > min)
- {
- min = r.i0;
- }
+ sel.set(R1, R2+1);
+ sel.clear(S1, S2+1);
}
+
+ BitSet newRange = sel.get(lo, hi+1);
+ newRange.xor(oldRange);
+
+ int beg = sel.nextSetBit(0), end = -1;
+ for(int i=beg; i >= 0; i=sel.nextSetBit(i+1))
+ {
+ end = i;
}
- return min;
+ fireSelectionValueChanged(beg, end, valueIsAdjusting);
}
- public int getMaxSelectionIndex()
+ /**
+ * Gets the value of the {@link #leadAnchorNotificationEnabled} property.
+ *
+ * @return The current property value
+ *
+ * @see #setLeadAnchorNotificationEnabled
+ */
+ public boolean isLeadAnchorNotificationEnabled()
{
- if (isSelectionEmpty())
- return -1;
+ return leadAnchorNotificationEnabled;
+ }
- boolean first = true;
- int max = -1;
- for (int i=1;i<sel.size();i++)
+ /**
+ * Sets the value of the {@link #leadAnchorNotificationEnabled} property.
+ *
+ * @param flag The new property value
+ *
+ * @see #getLeadAnchorNotificationEnabled
+ */
+ public void setLeadAnchorNotificationEnabled(boolean l)
{
- Range r = (Range) sel.get(i);
+ leadAnchorNotificationEnabled = l;
+ }
+
- if (first)
+ /**
+ * Gets the value of the {@link #valueIsAdjusting} property.
+ *
+ * @return The current property value
+ *
+ * @see #setValueIsAdjusting
+ */
+ public boolean getValueIsAdjusting()
{
- max = r.i1;
+ return valueIsAdjusting;
}
- else
- {
- if (r.i1 > max)
+
+ /**
+ * Sets the value of the {@link #valueIsAdjusting} property.
+ *
+ * @param v The new property value
+ *
+ * @see #getValueIsAdjusting
+ */
+ public void setValueIsAdjusting(boolean v)
{
- max = r.i1;
- }
- }
+ valueIsAdjusting = v;
}
- return max;
+
+ /**
+ * Determines whether the selection is empty.
+ *
+ * @return <code>true</code> if the selection is empty, otherwise
+ * <code>false</code>
+ */
+ public boolean isSelectionEmpty()
+ {
+ return sel.isEmpty();
}
- public boolean isSelectedIndex(int a)
+
+ /**
+ * Gets the smallest index which is currently a member of a selection
+ * interval.
+ *
+ * @return The least integer <code>i</code> such that <code>i >=
+ * 0</code> and <code>i</code> is a member of a selected interval, or
+ * <code>-1</code> if there are no selected intervals
+ *
+ * @see #getMaxSelectionIndex
+ */
+ public int getMinSelectionIndex()
{
- for (int i=0;i<sel.size();i++)
+ if (isSelectionEmpty())
+ return -1;
+
+ return sel.nextSetBit(0);
+ }
+
+ /**
+ * Gets the largest index which is currently a member of a selection
+ * interval.
+ *
+ * @return The greatest integer <code>i</code> such that <code>i >=
+ * 0</code> and <code>i</code> is a member of a selected interval, or
+ * <code>-1</code> if there are no selected intervals
+ *
+ * @see #getMinSelectionIndex
+ */
+ public int getMaxSelectionIndex()
{
- Range r = (Range) sel.get(i);
- if (r.i0 <= a &&
- r.i1 >= a)
+ if (isSelectionEmpty())
+ return -1;
+
+ int mx = -1;
+ for(int i=sel.nextSetBit(0); i >= 0; i=sel.nextSetBit(i+1))
{
- return true;
+ mx = i;
}
+ return mx;
}
- return false;
+
+ /**
+ * Determines whether a particular index is a member of a selection
+ * interval.
+ *
+ * @param a The index to search for
+ *
+ * @return <code>true</code> if the index is a member of a selection interval,
+ * otherwise <code>false</code>
+ */
+ public boolean isSelectedIndex(int a)
+ {
+ return sel.get(a);
}
+ /**
+ * If the {@link #selectionMode} property is equal to
+ * <code>SINGLE_SELECTION</code> or
+ * <code>SINGLE_INTERVAL_SELECTION</code>, equivalent to calling
+ * <code>setSelectionInterval(index1, index2)</code>; otherwise adds the
+ * range <code>[index0, index1]</code> to the selection interval set.
+ *
+ * @param index0 The beginning of the range of indices to select
+ * @param index1 The end of the range of indices to select
+ *
+ * @see #setSelectionInterval
+ * @see #removeSelectionInterval
+ */
+ public void addSelectionInterval(int index0, int index1)
+ {
+ if (selectionMode == SINGLE_SELECTION
+ || selectionMode == SINGLE_INTERVAL_SELECTION)
+ sel.clear();
+
+ if (selectionMode == SINGLE_SELECTION)
+ index0 = index1;
- public int getSelectionMode()
- { return mode; }
- public void setSelectionMode(int a)
- { mode = a; }
+ int lo = Math.min(index0, index1);
+ int hi = Math.max(index0, index1);
- boolean isSelectionEmpty()
+ sel.set(lo, hi+1);
+ fireSelectionValueChanged(lo, hi, valueIsAdjusting);
+ }
+
+
+ /**
+ * Deselects all indices in the inclusive range
+ * <code>[index0,index1]</code>.
+ *
+ * @param index0 The beginning of the range of indices to deselect
+ * @param index1 The end of the range of indices to deselect
+ *
+ * @see #addSelectionInterval
+ * @see #setSelectionInterval
+ */
+ public void removeSelectionInterval(int index0,
+ int index1)
{
- return sel.size() == 0;
+ int lo = Math.min(index0, index1);
+ int hi = Math.max(index0, index1);
+ sel.clear(lo, hi+1);
+ fireSelectionValueChanged(lo, hi, valueIsAdjusting);
}
+ /**
+ * Removes all intervals in the selection set.
+ */
public void clearSelection()
{
- sel.removeAllElements();
+ int sz = sel.size();
+ sel.clear();
+ fireSelectionValueChanged(0, sz, valueIsAdjusting);
}
+ /**
+ * Clears the current selection and marks a given interval as
+ * "selected". If the current selection mode is
+ * <code>SINGLE_SELECTION</code> only the index <code>index2</code> is
+ * selected.
+ *
+ * @param index0 The low end of the new selection
+ * @param index1 The high end of the new selection
+ */
public void setSelectionInterval(int index0, int index1)
{
- if (mode == SINGLE_SELECTION)
+ sel.clear();
+ if (selectionMode == SINGLE_SELECTION)
+ index0 = index1;
+
+ int lo = Math.min(index0, index1);
+ int hi = Math.max(index0, index1);
+ sel.set(lo, hi+1);
+ fireSelectionValueChanged(lo, hi, valueIsAdjusting);
+ }
+
+ /**
+ * Inserts a number of indices either before or after a particular
+ * position in the set of indices. Renumbers all indices after the
+ * inserted range. The new indices in the inserted range are not
+ * selected. This method is typically called to synchronize the selection
+ * model with an inserted range of elements in a {@link ListModel}.
+ *
+ * @param index The position to insert indices at
+ * @param length The number of indices to insert
+ * @param before Indicates whether to insert the indices before the index
+ * or after it
+ */
+ public void insertIndexInterval(int index,
+ int length,
+ boolean before)
+ {
+ if (!before)
+ {
+ index++;
+ length--;
+ }
+ BitSet tmp = sel.get(index, sel.size());
+ sel.clear(index, sel.size());
+ int n = tmp.size();
+ for (int i = 0; i < n; ++i)
+ sel.set(index + length + i, tmp.get(i));
+ }
+
+ /**
+ * Removes a range from the set of indices. Renumbers all indices after
+ * the removed range. This method is typically called to synchronize the
+ * selection model with a deleted range of elements in a {@link
+ * ListModel}.
+ *
+ * @param index0 The first index to remove (inclusive)
+ * @param index1 The last index to remove (inclusive)
+ */
+ public void removeIndexInterval(int index0,
+ int index1)
{
- sel.removeAllElements();
+ int lo = Math.min(index0, index1);
+ int hi = Math.max(index0, index1);
+
+ BitSet tmp = sel.get(hi, sel.size());
+ sel.clear(lo, sel.size());
+ int n = tmp.size();
+ for (int i = 0; i < n; ++i)
+ sel.set(lo + i, tmp.get(i));
}
- sel.addElement(new Range(index0, index1));
+ /**
+ * Fires a {@link ListSelectionEvent} to all the listeners of type {@link
+ * ListSelectionListener} registered with this selection model.
+ *
+ * @param firstIndex The low index of the changed range
+ * @param lastIndex The high index of the changed range
+ * @param isAdjusting Whether this change is part of a seqence of adjustments
+ * made to the selection, such as during interactive scrolling
+ */
+ public void fireSelectionValueChanged(int firstIndex, int lastIndex,
+ boolean isAdjusting)
+ {
+ ListSelectionEvent evt = new ListSelectionEvent(this, firstIndex,
+ lastIndex, isAdjusting);
+ ListSelectionListener[] listeners = getListSelectionListeners();
+ for (int i = 0; i < listeners.length; ++i)
+ listeners[i].valueChanged(evt);
}
/**
* Adds a listener.
*
- * @param listener the listener to add
+ * @param listener The listener to add
*
* @see removeListSelectionListener
* @see getListSelectionListeners
@@ -182,7 +547,7 @@
/**
* Removes a registered listener.
*
- * @param listener the listener to remove
+ * @param listener The listener to remove
*
* @see addListSelectionListener
* @see getListSelectionListeners
@@ -195,11 +560,12 @@
/**
* Returns an array of all registerers listeners.
*
- * @return the array
+ * @param listenerType The type of listener to retrieve
*
- * @since 1.3
+ * @return The array
*
* @see getListSelectionListener
+ * @since 1.3
*/
public EventListener[] getListeners (Class listenerType)
{
@@ -211,12 +577,11 @@
*
* @return the array
*
- * @since 1.4
- *
* @see addListSelectionListener
* @see removeListSelectionListener
* @see getListeners
+ * @since 1.4
*/
public ListSelectionListener[] getListSelectionListeners()
{
--- javax/swing/ListModel.java 10 Jan 2004 21:07:43 -0000 1.2
+++ javax/swing/ListModel.java 25 Feb 2004 23:56:23 -0000
@@ -36,14 +36,46 @@
exception statement from your version. */
package javax.swing;
-
import javax.swing.event.ListDataListener;
+/**
+ * This is an interface to general list-like data, typically used as the
+ * model object of a {@link JList} component.
+ *
+ * @author Graydon Hoare (graydon&064;redhat.com)
+ */
public interface ListModel
{
+ /**
+ * Return the number of data elements in the list.
+ *
+ * @return The number of data elements in the list
+ */
int getSize();
+
+ /**
+ * Retrieves a data element at a specified index.
+ *
+ * @param index The index of the element to retrieve
+ *
+ * @return The data element at the specified index
+ */
Object getElementAt(int index);
+
+ /**
+ * Add a listener object to this model. The listener will be called
+ * any time the set of elements in the model is changed.
+ *
+ * @param l The listener to add
+ */
void addListDataListener(ListDataListener l);
+
+ /**
+ * Add a listener object to this model. The listener will no longer be
+ * called when the set of elements in the model is changed.
+ *
+ * @param l The listener to remove
+ */
void removeListDataListener(ListDataListener l);
}
--- javax/swing/ListSelectionModel.java 12 Oct 2003 13:20:49 -0000 1.3
+++ javax/swing/ListSelectionModel.java 25 Feb 2004 23:56:23 -0000
@@ -44,7 +44,7 @@
{
int SINGLE_SELECTION = 0;
int SINGLE_INTERVAL_SELECTION = 1;
- int MULTIPLE_INTERVAL_SELECTION = 1;
+ int MULTIPLE_INTERVAL_SELECTION = 2;
void setSelectionMode(int a);
int getSelectionMode();
@@ -53,12 +53,29 @@
int getMinSelectionIndex();
int getMaxSelectionIndex();
+
boolean isSelectedIndex(int a);
+ boolean isSelectionEmpty();
void setSelectionInterval(int index0, int index1);
+ void addSelectionInterval(int index0,
+ int index1);
+ void removeSelectionInterval(int index0,
+ int index1);
+ void insertIndexInterval(int index,
+ int length,
+ boolean before);
+ void removeIndexInterval(int index0,
+ int index1);
+
+ int getAnchorSelectionIndex();
+ void setAnchorSelectionIndex(int index);
+ int getLeadSelectionIndex();
+ void setLeadSelectionIndex(int index);
-
+ void setValueIsAdjusting(boolean valueIsAdjusting);
+ boolean getValueIsAdjusting();
void addListSelectionListener(ListSelectionListener listener);
void removeListSelectionListener(ListSelectionListener listener);
--- javax/swing/AbstractListModel.java 11 Jun 2003 13:20:39 -0000 1.5
+++ javax/swing/AbstractListModel.java 25 Feb 2004 23:56:23 -0000
@@ -40,35 +40,34 @@
import java.io.Serializable;
import java.util.EventListener;
import javax.swing.event.EventListenerList;
-import javax.swing.event.ListDataListener;
import javax.swing.event.ListDataEvent;
+import javax.swing.event.ListDataListener;
+
/**
* AbstractListModel
- * A2uthor Ronald Veldema
+ *
+ * @author Ronald Veldema
* @author Andrew Selkirk
* @version 1.0
*/
-public abstract class AbstractListModel
- implements ListModel, Serializable
+public abstract class AbstractListModel implements ListModel, Serializable
{
static final long serialVersionUID = -3285184064379168730L;
- /**
- * listenerList
- */
- protected EventListenerList listenerList = new EventListenerList ();
+ /** List of ListDataListeners called for each change to the list. */
+ protected EventListenerList listenerList;
- /**
- * Constructor AbstractListModel
- */
public AbstractListModel ()
{
+ listenerList = new EventListenerList();
}
/**
- * addListDataListener
- * @param listener TODO
+ * Add a listener object to this model. The listener will be called
+ * any time the set of elements in the model is changed.
+ *
+ * @param listener The listener to add
*/
public void addListDataListener(ListDataListener listener)
{
@@ -76,8 +75,10 @@
}
/**
- * removeListDataListener
- * @param listener TODO
+ * Add a listener object to this model. The listener will no longer be
+ * called when the set of elements in the model is changed.
+ *
+ * @param listener The listener to remove
*/
public void removeListDataListener(ListDataListener listener)
{
@@ -85,12 +86,18 @@
}
/**
- * fireContentsChanged
- * @param source TODO
- * @param startIndex TODO
- * @param endIndex TODO
+ * Call {@link ListDataListener#contentsChanged} on each element of the
+ * {@link listenerList} which is a {@link ListDataListener}. The event
+ * fired has type {@ListDataEvent.CONTENTS_CHANGED} and represents a
+ * change to the data elements in the range [startIndex, endIndex]
+ * inclusive.
+ *
+ * @param source The source of the change, typically <code>this</code>
+ * @param startIndex The index of the first element which changed
+ * @param endIndex The index of the last element which changed
*/
- protected void fireContentsChanged(Object source, int startIndex, int endIndex)
+ protected void fireContentsChanged(Object source, int startIndex,
+ int endIndex)
{
// Variables
ListDataEvent event;
@@ -114,10 +121,15 @@
}
/**
- * fireIntervalAdded
- * @param source TODO
- * @param startIndex TODO
- * @param endIndex TODO
+ * Call {@link ListDataListener#intervalAdded} on each element of the
+ * {@link listenerList} which is a {@link ListDataListener}. The event
+ * fired has type {@ListDataEvent.INTERVAL_ADDED} and represents an
+ * addition of the data elements in the range [startIndex, endIndex]
+ * inclusive.
+ *
+ * @param source The source of the change, typically <code>this</code>
+ * @param startIndex The index of the first new element
+ * @param endIndex The index of the last new element
*/
protected void fireIntervalAdded (Object source, int startIndex, int endIndex)
{
@@ -128,8 +140,8 @@
int index;
// Create Event
- event = new ListDataEvent (source, ListDataEvent.INTERVAL_ADDED, startIndex,
- endIndex);
+ event = new ListDataEvent(source, ListDataEvent.INTERVAL_ADDED,
+ startIndex, endIndex);
// Get Listeners
listeners = getListDataListeners ();
@@ -143,10 +155,15 @@
}
/**
- * fireIntervalRemoved
- * @param source TODO
- * @param startIndex TODO
- * @param endIndex TODO
+ * Call {@link ListDataListener#intervalRemoved} on each element of the
+ * {@link listenerList} which is a {@link ListDataListener}. The event
+ * fired has type {@ListDataEvent.INTERVAL_REMOVED} and represents a
+ * removal of the data elements in the range [startIndex, endIndex]
+ * inclusive.
+ *
+ * @param source The source of the change, typically <code>this</code>
+ * @param startIndex The index of the first element removed
+ * @param endIndex The index of the last element removed
*/
protected void fireIntervalRemoved (Object source, int startIndex,
int endIndex)
@@ -173,9 +190,13 @@
}
/**
- * getListeners
- * @param listenerType TODO
- * @returns EventListener[]
+ * Return the subset of {@link EventListener} objects found in this
+ * object's {@link listenerList} which are elements of the specified
+ * type.
+ *
+ * @param listenerType The type of listeners to select
+ *
+ * @return The set of listeners of the specified type
*/
public EventListener[] getListeners (Class listenerType)
{
@@ -183,8 +204,10 @@
}
/**
- * getListDataListeners
+ * A synonym for <code>getListeners(ListDataListener.class)</code>.
+ *
+ * @return The set of ListDataListeners found in the {@link listenerList}
*/
public ListDataListener[] getListDataListeners ()
{
--- javax/swing/DefaultListModel.java 5 Feb 2004 18:48:53 -0000 1.3
+++ javax/swing/DefaultListModel.java 25 Feb 2004 23:56:23 -0000
@@ -35,501 +35,475 @@
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
-
package javax.swing;
-import java.util.ArrayList;
import java.util.Enumeration;
import java.util.NoSuchElementException;
import java.util.Vector;
/**
- * DefaultListModel
+ * This is a default subclass of the {@link AbstractListModel}, used by
+ * {@link javax.swing.JList} and similar objects as the model of a list of
+ * values. The implementation is based on an underlying {@link
+ * java.util.Vector}.
+ *
* @author Andrew Selkirk
- * @version 1.0
+ * @author Graydon Hoare (graydon&064;redhat.com)
*/
+
public class DefaultListModel extends AbstractListModel
{
private static final long serialVersionUID = 2315945659722172272L;
- //-------------------------------------------------------------
- // Variables --------------------------------------------------
- //-------------------------------------------------------------
-
- /**
- * elements. Note: Sun obviously implemented the storage as a
- * Vector according to the similar API on this class. I choose
- * instead to implement the model with a proper collection object.
- * Is this a good choice? Probably not (ya..I know there are
- * sync issues by doing this)
- */
- private ArrayList elements = new ArrayList();
-
-
- //-------------------------------------------------------------
- // Initialization ---------------------------------------------
- //-------------------------------------------------------------
-
/**
- * Constructor DefaultListModel
+ * The vector of elements in this list model.
*/
- public DefaultListModel() {
- // TODO
- } // DefaultListModel()
-
-
- //-------------------------------------------------------------
- // Methods ----------------------------------------------------
- //-------------------------------------------------------------
+ private Vector elements = new Vector();
/**
- * elementAt
- * @param index TODO
- * @returns Object
+ * Gets an element of the list at the provided index.
+ *
+ * @param index The index of the element to get
+ *
+ * @return The object at the given index
+ *
+ * @throws ArrayIndexOutOfBoundsException If the provided index is
+ * outside the bounds of the list <code>[0, size())</code>
*/
- public Object elementAt(int index) {
- return elements.get(index);
- } // elementAt()
+ public Object elementAt(int index)
+ {
+ return elements.elementAt(index);
+ }
/**
- * toString
- * @returns String
+ * Convert the list to a string representation.
+ *
+ * @return A string representation of the list
*/
- public String toString() {
+ public String toString()
+ {
return elements.toString();
- } // toString()
+ }
/**
- * indexOf
- * @param element TODO
- * @returns int
+ * Gets the first index of a particular element in the list.
+ *
+ * @param element The element to search for
+ *
+ * @return The first index in the list at which an object
+ * <code>obj</code> exists such that <code>obj.equals(element)</code> is
+ * <code>true</code>; if no such object exists, the method returns
+ * <code>-1</code>
*/
- public int indexOf(Object element) {
+ public int indexOf(Object element)
+ {
return elements.indexOf(element);
- } // indexOf()
+ }
/**
- * indexOf
- * @param element TODO
- * @param startIndex TODO
- * @returns int
+ * Gets the first index of a particular element in a list which occurs
+ * <em>at or after</em> a particular index.
+ *
+ * @param element The element to search for
+ * @param startIndex The index to begin searching at
+ *
+ * @return The first index in the list, greater than or equal to
+ * <code>startIndex</code>, at which an object <code>obj</code> exists
+ * such that <code>obj.equals(element)</code> is <code>true</code>; if no
+ * such object exists, the method returns <code>-1</code>
*/
- public int indexOf(Object element, int startIndex) {
-
- // Variables
- int index;
- Object test;
-
- // Process Elements
- for (index = startIndex; index < elements.size(); index++) {
- test = elements.get(index);
- if (test.equals(element) == true) {
- return index;
- } // if
- } // for
- return -1;
-
- } // indexOf()
+ public int indexOf(Object element, int startIndex)
+ {
+ return elements.indexOf(element, startIndex);
+ }
/**
- * lastIndexOf
- * @param element TODO
- * @returns int
+ * Gets the last index of a particular element in the list.
+ *
+ * @param element The element to search for
+ *
+ * @return The last index in the list at which an object
+ * <code>obj</code> exists such that <code>obj.equals(element)</code> is
+ * <code>true</code>; if no such object exists, the method returns
+ * <code>-1</code>
*/
- public int lastIndexOf(Object element) {
+ public int lastIndexOf(Object element)
+ {
return elements.lastIndexOf(element);
- } // lastIndexOf()
+ }
/**
- * lastIndexOf
- * @param element TODO
- * @param endIndex TODO
- * @returns int
+ * Gets the last index of a particular element in a list which occurs
+ * <em>at or before</em> a particular index.
+ *
+ * @param element The element to search for
+ * @param endIndex The index to finish searching at
+ *
+ * @return The last index in the list, less than to or equal to
+ * <code>endIndexIndex</code>, at which an object <code>obj</code> exists
+ * such that <code>obj.equals(element)</code> is <code>true</code>; if no
+ * such object exists, the method returns <code>-1</code>
*/
- public int lastIndexOf(Object element, int endIndex) {
-
- // Variables
- int index;
- Object test;
-
- // Process Elements
- for (index = endIndex; index >= 0; index--) {
- test = elements.get(index);
- if (test.equals(element) == true) {
- return index;
- } // if
- } // for
- return -1;
-
- } // lastIndexOf()
+ public int lastIndexOf(Object element, int endIndex)
+ {
+ return elements.lastIndexOf(element, endIndex);
+ }
/**
- * get
- * @param index TODO
- * @returns Object
+ * Gets the list element at a particular index.
+ *
+ * @param index The index to get the list value at
+ *
+ * @return The list value at the provided index
+ *
+ * @throws ArrayIndexOutOfBoundsException If the provided index is
+ * outside the bounds of the list <code>[0, size())</code>
*/
- public Object get(int index) {
+ public Object get(int index)
+ {
return elements.get(index);
- } // get()
+ }
/**
- * set
- * @param index TODO
- * @param element TODO
- * @returns Object
+ * Sets the list element at a particular index.
+ *
+ * @param index The list index at which to set a value
+ * @param element The value to set at the specified index
+ *
+ * @return The value previously held at the specified index
+ *
+ * @throws ArrayIndexOutOfBoundsException If the provided index is
+ * outside the bounds of the list <code>[0, size())</code>
*/
- public Object set(int index, Object element) {
-
- // Variables
+ public Object set(int index, Object element)
+ {
Object result;
-
- // Process Action
result = elements.set(index, element);
-
- // Send event
fireContentsChanged(this, index, index);
-
return result;
-
- } // set()
+ }
/**
- * add
- * @param index TODO
- * @param element TODO
+ * Inserts an element at a particular index in the list. Each element at
+ * index <code>i >= index</code> is shifted to position <code>i+1</code>.
+ * If <code>index</code> is equal to <code>size()</code>, this is
+ * equivalent to appending an element to the array. Any
+ * <code>index</code> greater than <code>size()</code> is illegal.
+ *
+ * @param index The index to insert the element at
+ * @param element The element to insert at the index
+ *
+ * @throws ArrayIndexOutOfBoundsException If the provided index is
+ * outside the bounds <code>[0, size()]</code>
*/
- public void add(int index, Object element) {
-
- // Process Action
+ public void add(int index, Object element)
+ {
elements.add(index, element);
-
- // Send event
fireContentsChanged(this, index, index);
-
- } // add()
+ }
/**
- * addElement
- * @param element TODO
+ * Inserts an element at the end of the list. This is equivalent to
+ * calling <code>list.add(list.size(), element)</code>.
+ *
+ * @param element The element to add to the list
*/
- public void addElement(Object element) {
-
- // Process Action
+ public void addElement(Object element)
+ {
elements.add(element);
-
- // Send event
fireIntervalAdded(this, elements.size(), elements.size());
-
- } // addElement()
+ }
/**
- * size
- * @returns int
+ * Gets the number of elements in the list.
+ *
+ * @return The number of elements in the list
*/
- public int size() {
+ public int size()
+ {
return elements.size();
- } // size()
+ }
/**
- * toArray
- * @returns Object[]
+ * Gets an array containing the elements of the list.
+ *
+ * @return An array of the objects in the list, in the order they occur
+ * in the list
*/
- public Object[] toArray() {
+ public Object[] toArray()
+ {
return elements.toArray();
- } // toArray()
+ }
/**
- * contains
- * @param element TODO
- * @returns boolean
+ * Determines whether a particular element is a member of the list.
+ *
+ * @param element The element to search for
+ *
+ * @return <code>true</code> if <code>element</code> is a member of the
+ * list, otherwise <code>false</code>
*/
- public boolean contains(Object element) {
+ public boolean contains(Object element)
+ {
return elements.contains(element);
- } // contains()
+ }
/**
- * copyInto
- * @param array TODO
+ * Copies the list into a provided array. The provided array must be at
+ * least as large as the list.
+ *
+ * @param array The array to copy the list into
+ *
+ * @throws IndexOutOfBoundsException if the array is too small to hold the
+ * elements of the list
*/
- public void copyInto(Object[] array) {
-
- // Variables
- int index;
- int size;
- Object[] srcArray;
-
- // Initialize
- size = size();
- srcArray = toArray();
-
- // Process Elements
- for (index = 0; index < size; index++) {
- array[index] = srcArray[index];
- } // for
-
- } // copyInto()
+ public void copyInto(Object[] array)
+ {
+ elements.copyInto(array);
+ }
/**
- * clear
+ * Erases all the elements of the list, setting the list's size to 0.
*/
- public void clear() {
-
- // Process Action
+ public void clear()
+ {
elements.clear();
-
- // Send event
fireIntervalRemoved(this, 0, elements.size());
-
- } // clear()
+ }
/**
- * remove
- * @param index TODO
- * @returns Object
+ * Removes the element at a particular index from the list.
+ *
+ * @param index The index of the element to remove
+ *
+ * @return The value at the index, which has been removed from the list
+ *
+ * @throws ArrayIndexOutOfBoundsException If the provided index is
+ * outside the bounds of the list <code>[0, size())</code>
*/
- public Object remove(int index) {
-
- // Variables
+ public Object remove(int index)
+ {
Object result;
-
- // Process Action
result = elements.remove(index);
-
- // Send event
fireIntervalRemoved(this, index, index);
-
return result;
-
- } // remove()
+ }
/**
- * isEmpty
- * @returns boolean
+ * Determines whether the list is empty.
+ *
+ * @return <code>true</code> if the list is empty, otherwise
+ * <code>false</code>
*/
- public boolean isEmpty() {
+ public boolean isEmpty()
+ {
return elements.isEmpty();
- } // isEmpty()
+ }
/**
- * elements
- * @returns Enumeration
+ * Returns an {@link java.util.Enumeration} over the elements of the list.
+ *
+ * @return A new enumeration which iterates over the list
*/
- public Enumeration elements() {
-
- // TODO
- // Note: This is a pathetic implementation. If Vector
- // was used for storage, this wouldn't be an issue. I'll
- // have to implement an Enumeration inner class sometime.
-
- // Variables
- Vector vector;
-
- // Get Enumeration
- vector = new Vector(elements);
- return vector.elements();
-
- } // elements()
+ public Enumeration elements()
+ {
+ return elements.elements();
+ }
/**
- * trimToSize
+ * Sets the capacity of the list to be equal to its size. The list's capacity
+ * is the number of elements it can hold before it needs to be reallocated.
+ * The list's size is the number of elements it currently holds.
*/
- public void trimToSize() {
+ public void trimToSize()
+ {
elements.trimToSize();
- } // trimToSize()
+ }
/**
- * ensureCapacity
- * @param size TODO
+ * Ensures that the list's capacity is at least equal to
+ * <code>size</code>. The list's capacity is the number of elements it
+ * can hold before it needs to be reallocated.
+ *
+ * @param size The capacity to ensure the list can hold
*/
- public void ensureCapacity(int size) {
+ public void ensureCapacity(int size)
+ {
elements.ensureCapacity(size);
- } // ensureCapacity()
+ }
/**
- * setSize
- * @param size TODO
+ * Sets the size of the list to a particular value. If the specified size
+ * is greater than the current size, the values at the excess list
+ * indices are set to <code>null</code>. If the specified size is less
+ * than the current size, the excess elements are removed from the list.
+ *
+ * @param size The new size to set the list to
*/
- public void setSize(int size) {
- elements.ensureCapacity(size);
- } // setSize()
+ public void setSize(int size)
+ {
+ elements.setSize(size);
+ }
/**
- * capacity
- * @returns int
+ * Gets the capacity of the list. The list's capacity is the number of
+ * elements it can hold before it needs to be reallocated.
+ *
+ * @return The capacity of the list
*/
- public int capacity() {
- return elements.size();
- } // capacity()
+ public int capacity()
+ {
+ return elements.capacity();
+ }
/**
- * firstElement
- * @returns Object
+ * Gets the first element in the list.
+ *
+ * @return The first element in the list
*/
- public Object firstElement() {
-
- // Variables
- Object element;
-
- try {
- element = elements.get(0);
- return element;
- } catch (IndexOutOfBoundsException e) {
- throw new NoSuchElementException();
- } // try
-
- } // firstElement()
+ public Object firstElement()
+ {
+ return elements.firstElement();
+ }
/**
- * lastElement
- * @returns Object
+ * Gets the last element in the list.
+ *
+ * @return The last element in the list
*/
- public Object lastElement() {
-
- // Variables
- Object element;
-
- try {
- element = elements.get(elements.size() - 1);
- return element;
- } catch (ArrayIndexOutOfBoundsException e) {
- throw new NoSuchElementException();
- } // try
-
- } // lastElement()
+ public Object lastElement()
+ {
+ return elements.lastElement();
+ }
/**
- * setElementAt
- * @param element TODO
- * @param index TODO
+ * Sets the list element at a particular index.
+ *
+ * @param element The value to set at the specified index
+ * @param index The list index at which to set a value
+ *
+ * @throws ArrayIndexOutOfBoundsException If the provided index is
+ * outside the bounds of the list <code>[0, size())</code>
*/
- public void setElementAt(Object element, int index) {
-
- // Process Action
- elements.set(index, element);
-
- // Send event
+ public void setElementAt(Object element, int index)
+ {
+ elements.setElementAt(element, index);
fireContentsChanged(this, index, index);
-
- } // setElementAt()
+ }
/**
- * removeElementAt
- * @param index TODO
+ * Removes the element at a particular index from the list.
+ *
+ * @param index The index of the element to remove
+ *
+ * @throws ArrayIndexOutOfBoundsException If the provided index is
+ * outside the bounds of the list <code>[0, size())</code>
*/
- public void removeElementAt(int index) {
-
- // Process Action
+ public void removeElementAt(int index)
+ {
elements.remove(index);
-
- // Send event
fireIntervalRemoved(this, index, index);
-
- } // removeElementAt()
+ }
/**
- * insertElementAt
- * @param element TODO
- * @param index TODO
+ * Inserts an element at a particular index in the list. Each element at
+ * index <code>i >= index</code> is shifted to position <code>i+1</code>.
+ * If <code>index</code> is equal to <code>size()</code>, this is
+ * equivalent to appending an element to the array. Any
+ * <code>index</code> greater than <code>size()</code> is illegal.
+ *
+ * @param element The element to insert at the index
+ * @param index The index to insert the element at
+ *
+ * @throws ArrayIndexOutOfBoundsException If the provided index is
+ * outside the bounds <code>[0, size()]</code>
*/
- public void insertElementAt(Object element, int index) {
-
- // Process Action
- elements.add(index, element);
-
- // Send event
- fireIntervalRemoved(this, index, index);
-
- } // insertElementAt()
+ public void insertElementAt(Object element, int index)
+ {
+ elements.insertElementAt(element, index);
+ fireIntervalAdded(this, index, index);
+ }
/**
- * removeElement
- * @param element TODO
- * @returns boolean
+ * Removes the first occurrence of a particular element in the list. If the
+ * element does not exist in the list, nothing happens.
+ *
+ * @param element The element to remove
+ *
+ * @return <code>true</code> if the element existed in the list (and was
+ * removed), <code>false</code> otherwise
*/
- public boolean removeElement(Object element) {
-
- // Variables
+ public boolean removeElement(Object element)
+ {
int index;
-
index = elements.indexOf(element);
- if (index != -1) {
+ if (index != -1)
+ {
elements.remove(index);
-
- // Send event
fireIntervalRemoved(this, index, index);
-
return true;
-
- } // if
-
+ }
return false;
-
- } // removeElement()
+ }
/**
- * removeAllElements
+ * Remove all elements in the list.
*/
- public void removeAllElements() {
-
- // Variables
+ public void removeAllElements()
+ {
int size;
-
size = size();
-
- if (size > 0) {
-
- // Process Action
+ if (size > 0)
+ {
elements.clear();
-
- // Send event
fireIntervalRemoved(this, 0, size - 1);
-
- } // if
-
- } // removeAllElements()
+ }
+ }
/**
- * removeRange
- * @param startIndex TODO
- * @param endIndex TODO
+ * Remove all elements between <code>startIndex</code> and
+ * <code>endIndex</code> inclusive.
+ *
+ * @param startIndex The first index in the range to remove
+ * @param endIndex The last index in the range to remove
+ *
+ * @throws ArrayIndexOutOfBoundsException if either index is outside the
+ * valid range of indices for this list <code>[0, size())</code>
+ * @throws IllegalArgumentException if <code>startIndex > endIndex</code>
*/
- public void removeRange(int startIndex, int endIndex) {
-
- // Variables
+ public void removeRange(int startIndex, int endIndex)
+ {
int index;
-
- // Check Indices
- if (startIndex > endIndex) {
+ if (startIndex > endIndex)
throw new IllegalArgumentException();
- } // if
-
- // Process Elements
- for (index = endIndex; index >= startIndex; index--) {
+ for (index = endIndex; index >= startIndex; index--)
elements.remove(index);
- } // for
-
- // Send event
fireIntervalRemoved(this, startIndex, endIndex);
-
- } // removeRange()
+ }
/**
- * getSize
- * @returns int
+ * Gets the size of the list.
+ *
+ * @return The number of elements currently in the list
*/
- public int getSize() {
+ public int getSize()
+ {
return elements.size();
- } // getSize()
+ }
/**
- * getElementAt
- * @param index TODO
- * @returns Object
+ * Gets the list element at a particular index.
+ *
+ * @param index The index to get the list value at
+ *
+ * @return The list value at the provided index
+ *
+ * @throws ArrayIndexOutOfBoundsException If the provided index is
+ * outside the bounds of the list <code>[0, size())</code>
*/
- public Object getElementAt(int index) {
+ public Object getElementAt(int index)
+ {
return elements.get(index);
- } // getElementAt()
-
-
-} // DefaultListModel
+ }
+}
--- javax/swing/DefaultListCellRenderer.java 9 Jan 2004 10:18:47 -0000 1.3
+++ javax/swing/DefaultListCellRenderer.java 25 Feb 2004 23:56:23 -0000
@@ -42,214 +42,76 @@
import java.io.Serializable;
import javax.swing.border.Border;
+
/**
* DefaultListCellRenderer
+ *
* @author Andrew Selkirk
* @version 1.0
*/
-public class DefaultListCellRenderer extends JLabel
- implements ListCellRenderer, Serializable
+public class DefaultListCellRenderer
+ extends JLabel implements ListCellRenderer, Serializable
{
static final long serialVersionUID = 7708947179685189462L;
- //-------------------------------------------------------------
- // Classes ----------------------------------------------------
- //-------------------------------------------------------------
-
- /**
- * UIResource
- */
public static class UIResource extends DefaultListCellRenderer
- implements javax.swing.plaf.UIResource {
-
- //-------------------------------------------------------------
- // Initialization ---------------------------------------------
- //-------------------------------------------------------------
-
- /**
- * Constructor UIResource
- */
- public UIResource() {
- // TODO
- } // UIResource()
-
-
- } // UIResource
-
-
- //-------------------------------------------------------------
- // Variables --------------------------------------------------
- //-------------------------------------------------------------
+ implements javax.swing.plaf.UIResource
+ {
+ public UIResource()
+ {
+ }
+ }
- /**
- * noFocusBorder
- */
+ /** noFocusBorder */
protected static Border noFocusBorder = null; // TODO
-
- //-------------------------------------------------------------
- // Initialization ---------------------------------------------
- //-------------------------------------------------------------
-
- /**
- * Constructor DefaultListCellRenderer
- */
- public DefaultListCellRenderer() {
- // TODO
- } // DefaultListCellRenderer()
-
-
- //-------------------------------------------------------------
- // Methods ----------------------------------------------------
- //-------------------------------------------------------------
-
/**
* getListCellRendererComponent
+ *
* @param list TODO
* @param value TODO
* @param index TODO
* @param isSelected TODO
* @param cellHasFocus TODO
- * @returns Component
- */
- public Component getListCellRendererComponent(JList list,
- Object value, int index, boolean isSelected, boolean cellHasFocus) {
- return null; // TODO
- } // getListCellRendererComponent()
-
- /**
- * validate
- */
- public void validate() {
- // TODO
- } // validate()
-
- /**
- * revalidate
- */
- public void revalidate() {
- // TODO
- } // revalidate()
-
- /**
- * repaint
- * @param tm TODO
- * @param x TODO
- * @param y TODO
- * @param w TODO
- * @param h TODO
- */
- public void repaint(long tm, int x, int y, int w, int h) {
- // TODO
- } // repaint()
-
- /**
- * repaint
- * @param rect TODO
- */
- public void repaint(Rectangle rect) {
- // TODO
- } // repaint()
-
- /**
- * firePropertyChange
- * @param propertyName TODO
- * @param oldValue TODO
- * @param newValue TODO
- */
- protected void firePropertyChange(String propertyName,
- Object oldValue, Object newValue) {
- // TODO
- } // firePropertyChange()
-
- /**
- * firePropertyChange
- * @param propertyName TODO
- * @param oldValue TODO
- * @param newValue TODO
- */
- public void firePropertyChange(String propertyName,
- byte oldValue, byte newValue) {
- // TODO
- } // firePropertyChange()
-
- /**
- * firePropertyChange
- * @param propertyName TODO
- * @param oldValue TODO
- * @param newValue TODO
- */
- public void firePropertyChange(String propertyName,
- char oldValue, char newValue) {
- // TODO
- } // firePropertyChange()
-
- /**
- * firePropertyChange
- * @param propertyName TODO
- * @param oldValue TODO
- * @param newValue TODO
- */
- public void firePropertyChange(String propertyName,
- short oldValue, short newValue) {
- // TODO
- } // firePropertyChange()
-
- /**
- * firePropertyChange
- * @param propertyName TODO
- * @param oldValue TODO
- * @param newValue TODO
+ *
+ * @return Component
*/
- public void firePropertyChange(String propertyName,
- int oldValue, int newValue) {
- // TODO
- } // firePropertyChange()
-
- /**
- * firePropertyChange
- * @param propertyName TODO
- * @param oldValue TODO
- * @param newValue TODO
- */
- public void firePropertyChange(String propertyName,
- long oldValue, long newValue) {
- // TODO
- } // firePropertyChange()
-
- /**
- * firePropertyChange
- * @param propertyName TODO
- * @param oldValue TODO
- * @param newValue TODO
- */
- public void firePropertyChange(String propertyName,
- float oldValue, float newValue) {
- // TODO
- } // firePropertyChange()
-
- /**
- * firePropertyChange
- * @param propertyName TODO
- * @param oldValue TODO
- * @param newValue TODO
- */
- public void firePropertyChange(String propertyName,
- double oldValue, double newValue) {
- // TODO
- } // firePropertyChange()
-
- /**
- * firePropertyChange
- * @param propertyName TODO
- * @param oldValue TODO
- * @param newValue TODO
- */
- public void firePropertyChange(String propertyName,
- boolean oldValue, boolean newValue) {
- // TODO
- } // firePropertyChange()
-
+ public Component getListCellRendererComponent(JList list, Object value,
+ int index, boolean isSelected,
+ boolean cellHasFocus)
+ {
+ String s = value.toString();
+ setText(s);
+ setOpaque(true);
-} // DefaultListCellRenderer
+ if (isSelected)
+ {
+ setBackground(list.getSelectionBackground());
+ setForeground(list.getSelectionForeground());
+ }
+ else
+ {
+ setBackground(list.getBackground());
+ setForeground(list.getForeground());
+ }
+
+ setEnabled(list.isEnabled());
+ setFont(list.getFont());
+ return this;
+ }
+
+ public void validate() {}
+ public void revalidate() {}
+ public void repaint(long tm, int x, int y, int w, int h) {}
+ public void repaint(Rectangle rect) {}
+ protected void firePropertyChange(String propertyName, Object oldValue, Object newValue){}
+ public void firePropertyChange(String propertyName, byte oldValue, byte newValue) {}
+ public void firePropertyChange(String propertyName, char oldValue, char newValue) {}
+ public void firePropertyChange(String propertyName, short oldValue, short newValue) {}
+ public void firePropertyChange(String propertyName, int oldValue, int newValue) {}
+ public void firePropertyChange(String propertyName, long oldValue, long newValue) {}
+ public void firePropertyChange(String propertyName, float oldValue, float newValue) {}
+ public void firePropertyChange(String propertyName, double oldValue, double newValue) {}
+ public void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) {}
+}
--- javax/swing/plaf/basic/BasicListUI.java 10 Jan 2004 21:59:30 -0000 1.4
+++ javax/swing/plaf/basic/BasicListUI.java 25 Feb 2004 23:56:23 -0000
@@ -35,7 +35,6 @@
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
-
package javax.swing.plaf.basic;
import java.awt.Color;
@@ -44,141 +43,664 @@
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.awt.event.MouseEvent;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
import javax.swing.JComponent;
import javax.swing.JList;
import javax.swing.ListCellRenderer;
+import javax.swing.ListModel;
+import javax.swing.ListSelectionModel;
+import javax.swing.UIDefaults;
+import javax.swing.UIManager;
+import javax.swing.event.ListDataEvent;
+import javax.swing.event.ListDataListener;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.event.MouseInputListener;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.ListUI;
+
+/**
+ * The Basic Look and Feel UI delegate for the
+ * JList.
+ */
public class BasicListUI extends ListUI
{
- int gap_between_cells;
- Color textColor, disabledTextColor, pressedBackgroundColor, normalBackgroundColor;
-
+ /**
+ * A helper class which listens for {@link FocusEvents}
+ * from the JList.
+ */
+ class FocusHandler implements FocusListener
+ {
+ /**
+ * Called when the JList acquires focus.
+ *
+ * @param e The FocusEvent representing focus acquisition
+ */
+ public void focusGained(FocusEvent e)
+ {
+ repaintCellFocus();
+ }
- public static ComponentUI createUI(final JComponent c)
+ /**
+ * Called when the JList loses focus.
+ *
+ * @param e The FocusEvent representing focus loss
+ */
+ public void focusLost(FocusEvent e)
{
- return new BasicButtonUI();
+ repaintCellFocus();
}
+ /**
+ * Helper method to repaint the focused cell's
+ * lost or acquired focus state.
+ */
+ void repaintCellFocus()
+ {
+ }
+ }
- public void installUI(final JComponent c)
+ /**
+ * A helper class which listens for {@link ListDataEvent}s generated by
+ * the {@link JList}'s {@link ListModel}.
+ *
+ * @see javax.swing.JList#model
+ */
+ class ListDataHandler implements ListDataListener
+ {
+ /**
+ * Called when a general change has happened in the model which cannot
+ * be represented in terms of a simple addition or deletion.
+ *
+ * @param e The event representing the change
+ */
+ public void contentsChanged(ListDataEvent e)
{
- super.installUI(c);
+ // System.err.println(this + ".contentsChanged(" + e + ")");
+ BasicListUI.this.damageLayout();
+ }
- textColor = new Color(0,0,0);
- disabledTextColor = new Color(130, 130, 130);
- pressedBackgroundColor = new Color(150,150,150);
- normalBackgroundColor = new Color(192,192,192);
+ /**
+ * Called when an interval of objects has been added to the model.
+ *
+ * @param e The event representing the addition
+ */
+ public void intervalAdded(ListDataEvent e)
+ {
+ // System.err.println(this + ".intervalAdded(" + e + ")");
+ BasicListUI.this.damageLayout();
}
- public Dimension getPreferredSize(JComponent c)
+ /**
+ * Called when an inteval of objects has been removed from the model.
+ *
+ * @param e The event representing the removal
+ */
+ public void intervalRemoved(ListDataEvent e)
{
- JList l = (JList) c;
+ // System.err.println(this + ".intervalRemoved(" + e + ")");
+ BasicListUI.this.damageLayout();
+ }
+ }
- System.out.println("XXXXXXXXXXXXXXXxx getPreferredSize------------> " + l);
+ /**
+ * A helper class which listens for {@link ListSelectionEvent}s
+ * from the {@link JList}'s {@link ListSelectionModel}.
+ */
+ class ListSelectionHandler implements ListSelectionListener
+ {
+ /**
+ * Called when the list selection changes.
+ *
+ * @param e The event representing the change
+ */
+ public void valueChanged(ListSelectionEvent e)
+ {
+ // System.err.println(this + ".valueChanged(" + e + ")");
+ }
+ }
+ /**
+ * A helper class which listens for {@link MouseEvent}s
+ * from the {@link JList}.
+ */
+ class MouseInputHandler implements MouseInputListener
+ {
+ /**
+ * Called when a mouse button press/release cycle completes
+ * on the {@link JList}
+ *
+ * @param event The event representing the mouse click
+ */
+ public void mouseClicked(MouseEvent event)
+ {
+ }
- int rows = l.getVisibleRowCount();
+ /**
+ * Called when a mouse button is pressed down on the
+ * {@link JList}.
+ *
+ * @param event The event representing the mouse press
+ */
+ public void mousePressed(MouseEvent event)
+ {
+ // System.err.println("got mouse click event " + event);
+ int row = BasicListUI.this.convertYToRow(event.y);
+ if (row == -1)
+ return;
- ListCellRenderer render = l.getCellRenderer();
+ // System.err.println("clicked on row " + row);
+ BasicListUI.this.list.setSelectedIndex(row);
+ }
- int width = 200;
- int height = rows * 16;
+ /**
+ * Called when a mouse button is released on
+ * the {@link JList}
+ *
+ * @param event The event representing the mouse press
+ */
+ public void mouseReleased(MouseEvent event)
+ {
+ }
- if (l.getModel().getSize() == 0)
+ /**
+ * Called when the mouse pointer enters the area bounded
+ * by the {@link JList}
+ *
+ * @param event The event representing the mouse entry
+ */
+ public void mouseEntered(MouseEvent event)
{
- return new Dimension(width, height);
}
- System.out.println("BASIC_LIST_UI ====-> " + l.getModel().getElementAt(0));
+ /**
+ * Called when the mouse pointer leaves the area bounded
+ * by the {@link JList}
+ *
+ * @param event The event representing the mouse exit
+ */
+ public void mouseExited(MouseEvent event)
+ {
+ }
- Component elt = render.getListCellRendererComponent(l,
- l.getModel().getElementAt(0),
- 0,
- false,
- false);
- Dimension a = elt.getPreferredSize();
- if (a == null)
+ /**
+ * Called when the mouse pointer moves over the area bounded
+ * by the {@link JList} while a button is held down.
+ *
+ * @param event The event representing the mouse drag
+ */
+ public void mouseDragged(MouseEvent event)
{
- return new Dimension(width, height);
}
- return new Dimension(a.width,
- a.height * rows);
+ /**
+ * Called when the mouse pointer moves over the area bounded
+ * by the {@link JList}.
+ *
+ * @param event The event representing the mouse move
+ */
+ public void mouseMoved(MouseEvent event)
+ {
+ }
}
- public void paintBackground(Graphics g,
- JComponent c)
+ /**
+ * Helper class which listens to {@link PropertyChangeEvent}s
+ * from the {@link JList}.
+ */
+ class PropertyChangeHandler implements PropertyChangeListener
+ {
+ /**
+ * Called when the {@link JList} changes one of its bound properties.
+ *
+ * @param e The event representing the property change
+ */
+ public void propertyChange(PropertyChangeEvent e)
{
- Dimension size = getPreferredSize(c);
+ // System.err.println(this + ".propertyChange(" + e + ")");
+ if (e.source == BasicListUI.this.list)
+ {
+ if (e.oldValue != null && e.oldValue instanceof ListModel)
+ ((ListModel) e.oldValue).removeListDataListener(BasicListUI.this.listDataListener);
- g.setColor(normalBackgroundColor);
- g.fillRect(0,0,size.width, size.height);
+ if (e.newValue != null && e.newValue instanceof ListModel)
+ ((ListModel) e.newValue).addListDataListener(BasicListUI.this.listDataListener);
+ }
+ BasicListUI.this.damageLayout();
+ }
}
- public void paint(Graphics g,
- JComponent c)
+ /**
+ * Creates a new BasicListUI for the component.
+ *
+ * @param c The component to create a UI for
+ *
+ * @return A new UI
+ */
+ public static ComponentUI createUI(final JComponent c)
{
- JList l = (JList) c;
+ return new BasicListUI();
+ }
- int rows = l.getVisibleRowCount();
+ /** The current focus listener. */
+ FocusHandler focusListener;
- ListCellRenderer render = l.getCellRenderer();
+ /** The data listener listening to the model. */
+ ListDataHandler listDataListener;
- System.out.println("RENDER-JLIST: " + rows + ", " + l.getModel().getSize());
+ /** The selection listener listening to the selection model. */
+ ListSelectionHandler listSelectionListener;
- paintBackground(g, c);
+ /** The mouse listener listening to the list. */
+ MouseInputHandler mouseInputListener;
+
+ /** The property change listener listening to the list. */
+ PropertyChangeHandler propertyChangeListener;
+
+ /** Saved reference to the list this UI was created for. */
+ JList list;
+
+ /** The height of a single cell in the list. */
+ int cellHeight;
+
+ /** The width of a single cell in the list. */
+ int cellWidth;
+
+ /**
+ * An array of varying heights of cells in the list, in cases where each
+ * cell might have a different height.
+ */
+ int[] cellHeights;
+
+ /**
+ * A simple counter. When nonzero, indicates that the UI class is out of
+ * date with respect to the underlying list, and must recalculate the
+ * list layout before painting or performing size calculations.
+ */
+ int updateLayoutStateNeeded;
+
+ /**
+ * Calculate the height of a particular row. If there is a fixed {@link
+ * #cellHeight}, return it; otherwise return the specific row height
+ * requested from the {@link #cellHeights} array. If the requested row
+ * is invalid, return <code>-1</code>.
+ *
+ * @param row The row to get the height of
+ *
+ * @return The height, in pixels, of the specified row
+ */
+ int getRowHeight(int row)
+ {
+ if (row < 0 || row >= cellHeights.length)
+ return -1;
+ else if (cellHeight != -1)
+ return cellHeight;
+ else
+ return cellHeights[row];
+ }
- if (l.getModel().getSize() == 0)
- return;
+ /**
+ * Calculate the bounds of a particular cell, considering the upper left
+ * corner of the list as the origin position <code>(0,0)</code>.
+ *
+ * @param l Ignored; calculates over <code>this.list</code>
+ * @param index1 The first row to include in the bounds
+ * @param index2 The last row to incude in the bounds
+ *
+ * @return A rectangle encompassing the range of rows between
+ * <code>index1</code> and <code>index2</code> inclusive
+ */
+ public Rectangle getCellBounds(JList l, int index1, int index2)
+ {
+ if (l != list || cellWidth == -1)
+ return null;
+
+ int lo = Math.min(index1, index2);
+ int hi = Math.max(index1, index2);
+ Rectangle lobounds = new Rectangle(0, convertRowToY(lo), cellWidth,
+ getRowHeight(lo));
+ Rectangle hibounds = new Rectangle(0, convertRowToY(hi), cellWidth,
+ getRowHeight(hi));
+ return lobounds.union(hibounds);
+ }
+
+ /**
+ * Calculate the Y coordinate of the upper edge of a particular row,
+ * considering the Y coordinate <code>0</code> to occur at the top of the
+ * list.
+ *
+ * @param row The row to calculate the Y coordinate of
+ *
+ * @return The Y coordinate of the specified row, or <code>-1</code> if
+ * the specified row number is invalid
+ */
+ int convertRowToY(int row)
+ {
+ int y = 0;
+ for (int i = 0; i < row; ++i)
+ {
+ int h = getRowHeight(i);
+ if (h == -1)
+ return -1;
+ y += h;
+ }
+ return y;
+ }
+
+ /**
+ * Calculate the row number containing a particular Y coordinate,
+ * considering the Y coodrinate <code>0</code> to occur at the top of the
+ * list.
+ *
+ * @param y0 The Y coordinate to calculate the row number for
+ *
+ * @return The row number containing the specified Y value, or <code>-1</code>
+ * if the specified Y coordinate is invalid
+ */
+ int convertYToRow(int y0)
+ {
+ for (int row = 0; row < cellHeights.length; ++row)
+ {
+ int h = getRowHeight(row);
+
+ // System.err.println("convertYToRow(" + y0 + ") vs. " + h);
+ if (y0 < h)
+ return row;
+ y0 -= h;
+ }
+ return -1;
+ }
- // use element 0 to figure out how big we are:
- Component elt = render.getListCellRendererComponent(l,
- l.getModel().getElementAt(0),
- 0,
- false,
+ /**
+ * Recomputes the {@link #cellHeights}, {@link #cellHeight}, and {@link
+ * #cellWidth} properties by examining the variouis properties of the
+ * {@link JList}.
+ */
+ void updateLayoutState()
+ {
+ int nrows = list.getModel().getSize();
+ cellHeight = -1;
+ cellWidth = -1;
+ if (cellHeights == null || cellHeights.length != nrows)
+ cellHeights = new int[nrows];
+ if (list.getFixedCellHeight() == -1 || list.getFixedCellWidth() == -1)
+ {
+ ListCellRenderer rend = list.getCellRenderer();
+ for (int i = 0; i < nrows; ++i)
+ {
+ Component flyweight = rend.getListCellRendererComponent(list,
+ list.getModel()
+ .getElementAt(i),
+ 0, false,
false);
- Dimension dim = elt.getPreferredSize();
+ Dimension dim = flyweight.getPreferredSize();
+ cellHeights[i] = dim.height;
+ cellWidth = Math.max(cellWidth, dim.width);
+ }
+ }
+ else
+ {
+ cellHeight = list.getFixedCellHeight();
+ cellWidth = list.getFixedCellWidth();
+ }
+ }
- Rectangle a = new Rectangle(0,
- 0,
- dim.width,
- dim.height);
+ /**
+ * Marks the current layout as damaged and requests revalidation from the
+ * JList.
+ *
+ * @see #updateLayoutStateNeeded
+ */
+ void damageLayout()
+ {
+ updateLayoutStateNeeded = 1;
+ list.revalidate();
+ }
- for (int i=0;i<l.getModel().getSize();i++)
+ /**
+ * Calls {@link #updateLayoutState} if {@link #updateLayoutStateNeeded}
+ * is nonzero, then resets {@link #updateLayoutStateNeeded} to zero.
+ */
+ void maybeUpdateLayoutState()
{
- boolean is_sel = false;
- boolean has_focus = false;
+ // System.err.println(this + ".maybeUpdateLayoutState()");
+ if (updateLayoutStateNeeded != 0)
+ {
+ updateLayoutState();
+ updateLayoutStateNeeded = 0;
+ }
+ }
- Component comp = render.getListCellRendererComponent(l,
- l.getModel().getElementAt(i),
- i,
- is_sel,
- has_focus);
+ /**
+ * Creates a new BasicListUI object.
+ */
+ public BasicListUI()
+ {
+ focusListener = new FocusHandler();
+ listDataListener = new ListDataHandler();
+ listSelectionListener = new ListSelectionHandler();
+ mouseInputListener = new MouseInputHandler();
+ propertyChangeListener = new PropertyChangeHandler();
+ updateLayoutStateNeeded = 1;
+ }
- //System.out.println("AAAAA=> " + a + ", " + comp + ", index = " + i);
+ /**
+ * Installs various default settings (mostly colors) from the {@link
+ * UIDefaults} into the {@link JList}
+ *
+ * @see #uninstallDefaults
+ */
+ void installDefaults()
+ {
+ UIDefaults defaults = UIManager.getLookAndFeelDefaults();
+ list.setForeground(defaults.getColor("List.foreground"));
+ list.setBackground(defaults.getColor("List.background"));
+ list.setSelectionForeground(defaults.getColor("List.selectionForeground"));
+ list.setSelectionBackground(defaults.getColor("List.selectionBackground"));
+ }
- comp.setBounds(a);
+ /**
+ * Resets to <code>null</code> those defaults which were installed in
+ * {@link #installDefaults}
+ */
+ void uninstallDefaults()
+ {
+ UIDefaults defaults = UIManager.getLookAndFeelDefaults();
+ list.setForeground(null);
+ list.setBackground(null);
+ list.setSelectionForeground(null);
+ list.setSelectionBackground(null);
+ }
- comp.paint(g);
+ /**
+ * Attaches all the listeners we have in the UI class to the {@link
+ * JList}, its model and its selection model.
+ *
+ * @see #uninstallListeners
+ */
+ void installListeners()
+ {
+ list.addFocusListener(focusListener);
+ list.getModel().addListDataListener(listDataListener);
+ list.addListSelectionListener(listSelectionListener);
+ list.addMouseListener(mouseInputListener);
+ list.addMouseMotionListener(mouseInputListener);
+ list.addPropertyChangeListener(propertyChangeListener);
+ }
- a.y += dim.height + gap_between_cells;
+ /**
+ * Detaches all the listeners we attached in {@link #installListeners}.
+ */
+ void uninstallListeners()
+ {
+ list.removeFocusListener(focusListener);
+ list.getModel().removeListDataListener(listDataListener);
+ list.removeListSelectionListener(listSelectionListener);
+ list.removeMouseListener(mouseInputListener);
+ list.removeMouseMotionListener(mouseInputListener);
+ list.removePropertyChangeListener(propertyChangeListener);
}
+
+ /**
+ * Installs keyboard actions for this UI in the {@link JList}.
+ */
+ void installKeyboardActions()
+ {
}
- public int locationToIndex(JList list, Point location)
+ /**
+ * Uninstalls keyboard actions for this UI in the {@link JList}.
+ */
+ void uninstallKeyboardActions()
{
- throw new Error ("Not implemented");
}
- public Point indexToLocation(JList list, int index)
+ /**
+ * Installs the various aspects of the UI in the {@link JList}. In
+ * particular, calls {@link #installDefaults}, {@link #installListeners}
+ * and {@link #installKeyboardActions}. Also saves a reference to the
+ * provided component, cast to a {@link JList}.
+ *
+ * @param c The {@link JList} to install the UI into
+ */
+ public void installUI(final JComponent c)
+ {
+ super.installUI(c);
+ list = (JList) c;
+ installDefaults();
+ installListeners();
+ installKeyboardActions();
+ // System.err.println(this + ".installUI()");
+ maybeUpdateLayoutState();
+ }
+
+ /**
+ * Uninstalls all the aspects of the UI which were installed in {@link
+ * #installUI}. When finished uninstalling, drops the saved reference to
+ * the {@link JList}.
+ *
+ * @param c Ignored; the UI is uninstalled from the {@link JList}
+ * reference saved during the call to {@link #installUI}
+ */
+ public void uninstallUI(final JComponent c)
+ {
+ uninstallKeyboardActions();
+ uninstallListeners();
+ uninstallDefaults();
+ list = null;
+ }
+
+ /**
+ * Gets the maximum size this list can assume.
+ *
+ * @param c The component to measure the size of
+ *
+ * @return A new Dimension representing the component's maximum size
+ */
+ public Dimension getMaximumSize(JComponent c)
+ {
+ return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
+ }
+
+ /**
+ * Gets the size this list would prefer to assume. This is calculated by
+ * calling {@link #getCellBounds} over the entire list.
+ *
+ * @param c Ignored; uses the saved {@link JList} reference
+ *
+ * @return DOCUMENT ME!
+ */
+ public Dimension getPreferredSize(JComponent c)
+ {
+ maybeUpdateLayoutState();
+ if (list.getModel().getSize() == 0)
+ return new Dimension(0, 0);
+ Rectangle bounds = getCellBounds(list, 0, list.getModel().getSize() - 1);
+ return bounds.getSize();
+ }
+
+ /**
+ * Paints the packground of the list using the background color
+ * of the specified component.
+ *
+ * @param g The graphics context to paint in
+ * @param c The component to paint the background of
+ */
+ public void paintBackground(Graphics g, JComponent c)
+ {
+ Dimension size = getPreferredSize(c);
+ Color save = g.getColor();
+ g.setColor(c.getBackground());
+ g.fillRect(0, 0, size.width, size.height);
+ g.setColor(save);
+ }
+
+ /**
+ * Paints a single cell in the list.
+ *
+ * @param g The graphics context to paint in
+ * @param row The row number to paint
+ * @param bounds The bounds of the cell to paint, assuming a coordinate
+ * system beginning at <code>(0,0)</code> in the upper left corner of the
+ * list
+ * @param rend A cell renderer to paint with
+ * @param data The data to provide to the cell renderer
+ * @param sel A selection model to provide to the cell renderer
+ * @param lead The lead selection index of the list
+ */
+ void paintCell(Graphics g, int row, Rectangle bounds, ListCellRenderer rend,
+ ListModel data, ListSelectionModel sel, int lead)
+ {
+ boolean is_sel = list.isSelectedIndex(row);
+ boolean has_focus = false;
+ Component comp = rend.getListCellRendererComponent(list,
+ data.getElementAt(row),
+ 0, is_sel, has_focus);
+ g.translate(bounds.x, bounds.y);
+ comp.setBounds(new Rectangle(0, 0, bounds.width, bounds.height));
+ comp.paint(g);
+ g.translate(-bounds.x, -bounds.y);
+ }
+
+ /**
+ * Paints the list by calling {@link #paintBackground} and then repeatedly
+ * calling {@link #paintCell} for each visible cell in the list.
+ *
+ * @param g The graphics context to paint with
+ * @param c Ignored; uses the saved {@link JList} reference
+ */
+ public void paint(Graphics g, JComponent c)
+ {
+ int nrows = Math.min(list.getVisibleRowCount(), list.getModel().getSize());
+ if (nrows == 0)
+ return;
+
+ maybeUpdateLayoutState();
+ ListCellRenderer render = list.getCellRenderer();
+ ListModel model = list.getModel();
+ ListSelectionModel sel = list.getSelectionModel();
+ int lead = sel.getLeadSelectionIndex();
+ paintBackground(g, list);
+
+ for (int row = 0; row < nrows; ++row)
+ {
+ Rectangle bounds = getCellBounds(list, row, row);
+ paintCell(g, row, bounds, render, model, sel, lead);
+ }
+ }
+
+ public int locationToIndex(JList list, Point location)
{
throw new Error ("Not implemented");
}
- public Rectangle getCellBounds(JList list, int index1, int index2)
+ public Point indexToLocation(JList list, int index)
{
throw new Error ("Not implemented");
}
--- javax/swing/plaf/basic/BasicLookAndFeel.java 19 Feb 2004 18:59:11 -0000 1.4.2.4
+++ javax/swing/plaf/basic/BasicLookAndFeel.java 25 Feb 2004 23:56:23 -0000
@@ -226,6 +226,13 @@
protected void initComponentDefaults(UIDefaults defaults)
{
Object[] uiDefaults;
+
+ // The JDK's default L&F happens to use these three purple shades
+ // extensively.
+ Color lightPurple = new Color(0xCC, 0xCC, 0xFF);
+ Color midPurple = new Color(0x99, 0x99, 0xCC);
+ Color darkPurple = new Color(0x66, 0x66, 0x99);
+
uiDefaults = new Object[] {
"AbstractUndoableEdit.undoText", "Undo",
@@ -275,8 +282,8 @@
"CheckBoxMenuItem.font", new FontUIResource("Dialog", Font.PLAIN, 12),
"CheckBoxMenuItem.foreground", new ColorUIResource(Color.black),
"CheckBoxMenuItem.margin", new InsetsUIResource(2, 2, 2, 2),
- "CheckBoxMenuItem.selectionBackground", new ColorUIResource(0, 0, 128),
- "CheckBoxMenuItem.selectionForeground", new ColorUIResource(Color.white),
+ "CheckBoxMenuItem.selectionBackground", new ColorUIResource(lightPurple),
+ "CheckBoxMenuItem.selectionForeground", new ColorUIResource(Color.black),
"ColorChooser.background", new ColorUIResource(Color.lightGray),
"ColorChooser.cancelText", "Cancel",
"ColorChooser.font", new FontUIResource("Dialog", Font.PLAIN, 12),
@@ -316,8 +323,8 @@
"ComboBox.disabledForeground", new ColorUIResource(Color.gray),
"ComboBox.font", new FontUIResource("SansSerif", Font.PLAIN, 12),
"ComboBox.foreground", new ColorUIResource(Color.black),
- "ComboBox.selectionBackground", new ColorUIResource(0, 0, 128),
- "ComboBox.selectionForeground", new ColorUIResource(Color.white),
+ "ComboBox.selectionBackground", new ColorUIResource(lightPurple),
+ "ComboBox.selectionForeground", new ColorUIResource(Color.black),
"Desktop.ancestorInputMap", new UIDefaults.LazyInputMap(new Object[] {
"KP_LEFT", "left",
"KP_RIGHT", "right",
@@ -412,8 +419,8 @@
"FocusManagerClassName", "TODO",
"FormView.resetButtonText", "Reset",
"FormView.submitButtonText", "Submit Query",
- "InternalFrame.activeTitleBackground", new ColorUIResource(0, 0, 128),
- "InternalFrame.activeTitleForeground", new ColorUIResource(Color.white),
+ "InternalFrame.activeTitleBackground", new ColorUIResource(lightPurple),
+ "InternalFrame.activeTitleForeground", new ColorUIResource(Color.black),
"InternalFrame.border", new BorderUIResource.CompoundBorderUIResource(null,
null),
"InternalFrame.closeIcon", BasicIconFactory.createEmptyFrameIcon(),
@@ -458,8 +465,8 @@
"KP_DOWN", "selectNextRow"
}),
"List.foreground", new ColorUIResource(Color.black),
- "List.selectionBackground", new ColorUIResource(0, 0, 128),
- "List.selectionForeground", new ColorUIResource(Color.white),
+ "List.selectionBackground", new ColorUIResource(0xCC, 0xCC, 0xFF),
+ "List.selectionForeground", new ColorUIResource(Color.black),
"Menu.acceleratorFont", new FontUIResource("Dialog", Font.PLAIN, 12),
"Menu.acceleratorForeground", new ColorUIResource(Color.black),
"Menu.acceleratorSelectionForeground", new ColorUIResource(Color.white),
@@ -485,8 +492,8 @@
"ENTER", "return",
"SPACE", "return"
},
- "Menutext.selectionBackground", new ColorUIResource(0, 0, 128),
- "Menu.selectionForeground", new ColorUIResource(Color.white),
+ "Menutext.selectionBackground", new ColorUIResource(lightPurple),
+ "Menu.selectionForeground", new ColorUIResource(Color.black),
"MenuBar.background", new ColorUIResource(Color.lightGray),
"MenuBar.border", new BasicBorders.MenuBarBorder(null, null),
"MenuBar.font", new FontUIResource("Dialog", Font.PLAIN, 12),
@@ -506,8 +513,8 @@
"MenuItem.font", new FontUIResource("Dialog", Font.PLAIN, 12),
"MenuItem.foreground", new ColorUIResource(Color.black),
"MenuItem.margin", new InsetsUIResource(2, 2, 2, 2),
- "MenuItem.selectionBackground", new ColorUIResource(0, 0, 128),
- "MenuItem.selectionForeground", new ColorUIResource(Color.white),
+ "MenuItem.selectionBackground", new ColorUIResource(lightPurple),
+ "MenuItem.selectionForeground", new ColorUIResource(Color.black),
"OptionPane.background", new ColorUIResource(Color.lightGray),
"OptionPane.border", new BorderUIResource.EmptyBorderUIResource(0, 0, 0, 0),
"OptionPane.buttonAreaBorder", new BorderUIResource.EmptyBorderUIResource(0, 0, 0, 0),
@@ -547,8 +554,8 @@
0),
"notify-field-accept")},
"PasswordField.margin", new InsetsUIResource(0, 0, 0, 0),
- "PasswordField.selectionBackground", new ColorUIResource(0, 0, 128),
- "PasswordField.selectionForeground", new ColorUIResource(Color.white),
+ "PasswordField.selectionBackground", new ColorUIResource(lightPurple),
+ "PasswordField.selectionForeground", new ColorUIResource(Color.black),
"PopupMenu.background", new ColorUIResource(Color.lightGray),
"PopupMenu.border", new BorderUIResource.BevelBorderUIResource(0),
"PopupMenu.font", new FontUIResource("Dialog", Font.PLAIN, 12),
@@ -558,8 +565,8 @@
"ProgressBar.cellLength", new Integer(1),
"ProgressBar.cellSpacing", new Integer(0),
"ProgressBar.font", new FontUIResource("Dialog", Font.PLAIN, 12),
- "ProgressBar.foreground", new ColorUIResource(0, 0, 128),
- "ProgressBar.selectionBackground", new ColorUIResource(0, 0, 128),
+ "ProgressBar.foreground", new ColorUIResource(midPurple),
+ "ProgressBar.selectionBackground", new ColorUIResource(lightPurple),
"ProgressBar.selectionForeground", new ColorUIResource(Color.lightGray),
"ProgressBar.repaintInterval", new Integer(250),
"ProgressBar.cycleTime", new Integer(6000),
@@ -592,8 +599,8 @@
"RadioButtonMenuItem.font", new FontUIResource("Dialog", Font.PLAIN, 12),
"RadioButtonMenuItem.foreground", new ColorUIResource(Color.black),
"RadioButtonMenuItem.margin", new InsetsUIResource(2, 2, 2, 2),
- "RadioButtonMenuItem.selectionBackground", new ColorUIResource(0, 0, 128),
- "RadioButtonMenuItem.selectionForeground", new ColorUIResource(Color.white),
+ "RadioButtonMenuItem.selectionBackground", new ColorUIResource(lightPurple),
+ "RadioButtonMenuIt