1 /* List.java -- A listbox widget
2 Copyright (C) 1999, 2002, 2004 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
41 import java
.awt
.event
.ActionEvent
;
42 import java
.awt
.event
.ActionListener
;
43 import java
.awt
.event
.ItemEvent
;
44 import java
.awt
.event
.ItemListener
;
45 import java
.awt
.peer
.ListPeer
;
46 import java
.util
.EventListener
;
47 import java
.util
.Vector
;
49 import javax
.accessibility
.Accessible
;
50 import javax
.accessibility
.AccessibleContext
;
51 import javax
.accessibility
.AccessibleRole
;
52 import javax
.accessibility
.AccessibleSelection
;
53 import javax
.accessibility
.AccessibleState
;
54 import javax
.accessibility
.AccessibleStateSet
;
57 * Class that implements a listbox widget
59 * @author Aaron M. Renn (arenn@urbanophile.com)
61 public class List
extends Component
62 implements ItemSelectable
, Accessible
69 // Serialization constant
70 private static final long serialVersionUID
= -3304312411574666869L;
72 /*************************************************************************/
78 // FIXME: Need read/writeObject
81 * @serial The items in the list.
83 private Vector items
= new Vector();
86 * @serial Indicates whether or not multiple items can be selected
89 private boolean multipleMode
;
92 * @serial The number of rows in the list. This is set on creation
93 * only and cannot be modified.
98 * @serial An array of the item indices that are selected.
100 private int[] selected
;
103 * @serial An index value used by <code>makeVisible()</code> and
104 * <code>getVisibleIndex</code>.
106 private int visibleIndex
;
108 // The list of ItemListeners for this object.
109 private ItemListener item_listeners
;
111 // The list of ActionListeners for this object.
112 private ActionListener action_listeners
;
115 /*************************************************************************/
122 * Initializes a new instance of <code>List</code> with no visible lines
123 * and multi-select disabled.
125 * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true.
133 /*************************************************************************/
136 * Initializes a new instance of <code>List</code> with the specified
137 * number of visible lines and multi-select disabled.
139 * @param rows The number of visible rows in the list.
141 * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true.
149 /*************************************************************************/
152 * Initializes a new instance of <code>List</code> with the specified
153 * number of lines and the specified multi-select setting.
155 * @param rows The number of visible rows in the list.
156 * @param multipleMode <code>true</code> if multiple lines can be selected
157 * simultaneously, <code>false</code> otherwise.
159 * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true.
162 List(int rows
, boolean multipleMode
)
165 this.multipleMode
= multipleMode
;
167 if (GraphicsEnvironment
.isHeadless())
168 throw new HeadlessException ();
171 /*************************************************************************/
178 * Returns the number of items in this list.
180 * @return The number of items in this list.
185 return countItems ();
188 /*************************************************************************/
191 * Returns the number of items in this list.
193 * @return The number of items in this list.
195 * @deprecated This method is deprecated in favor of
196 * <code>getItemCount()</code>
201 return items
.size ();
204 /*************************************************************************/
207 * Returns the complete list of items.
209 * @return The complete list of items in the list.
211 public synchronized String
[]
214 String
[] l_items
= new String
[getItemCount()];
216 items
.copyInto(l_items
);
220 /*************************************************************************/
223 * Returns the item at the specified index.
225 * @param index The index of the item to retrieve.
227 * @exception IndexOutOfBoundsException If the index value is not valid.
232 return((String
)items
.elementAt(index
));
235 /*************************************************************************/
238 * Returns the number of visible rows in the list.
240 * @return The number of visible rows in the list.
248 /*************************************************************************/
251 * Tests whether or not multi-select mode is enabled.
253 * @return <code>true</code> if multi-select mode is enabled,
254 * <code>false</code> otherwise.
259 return allowsMultipleSelections ();
262 /*************************************************************************/
265 * Tests whether or not multi-select mode is enabled.
267 * @return <code>true</code> if multi-select mode is enabled,
268 * <code>false</code> otherwise.
270 * @deprecated This method is deprecated in favor of
271 * <code>isMultipleMode()</code>.
274 allowsMultipleSelections()
279 /*************************************************************************/
282 * This method enables or disables multiple selection mode for this
285 * @param multipleMode <code>true</code> to enable multiple mode,
286 * <code>false</code> otherwise.
289 setMultipleMode(boolean multipleMode
)
291 setMultipleSelections (multipleMode
);
294 /*************************************************************************/
297 * This method enables or disables multiple selection mode for this
300 * @param multipleMode <code>true</code> to enable multiple mode,
301 * <code>false</code> otherwise.
306 setMultipleSelections(boolean multipleMode
)
308 this.multipleMode
= multipleMode
;
310 ListPeer peer
= (ListPeer
) getPeer ();
312 peer
.setMultipleMode (multipleMode
);
315 /*************************************************************************/
318 * Returns the minimum size of this component.
320 * @return The minimum size of this component.
325 return getMinimumSize (getRows ());
328 /*************************************************************************/
331 * Returns the minimum size of this component.
333 * @return The minimum size of this component.
335 * @deprecated This method is deprecated in favor of
336 * <code>getMinimumSize</code>.
341 return minimumSize (getRows ());
344 /*************************************************************************/
347 * Returns the minimum size of this component assuming it had the specified
350 * @param rows The number of rows to size for.
352 * @return The minimum size of this component.
355 getMinimumSize(int rows
)
357 return minimumSize (rows
);
360 /*************************************************************************/
363 * Returns the minimum size of this component assuming it had the specified
366 * @param rows The number of rows to size for.
368 * @return The minimum size of this component.
370 * @deprecated This method is deprecated in favor of
371 * <code>getMinimumSize(int)</code>>
374 minimumSize(int rows
)
376 ListPeer peer
= (ListPeer
) getPeer ();
378 return peer
.minimumSize (rows
);
380 return new Dimension (0, 0);
383 /*************************************************************************/
386 * Returns the preferred size of this component.
388 * @return The preferred size of this component.
393 return getPreferredSize (getRows ());
396 /*************************************************************************/
399 * Returns the preferred size of this component.
401 * @return The preferred size of this component.
403 * @deprecated This method is deprecated in favor of
404 * <code>getPreferredSize</code>.
409 return preferredSize (getRows ());
412 /*************************************************************************/
415 * Returns the preferred size of this component assuming it had the specified
418 * @param rows The number of rows to size for.
420 * @return The preferred size of this component.
423 getPreferredSize(int rows
)
425 return preferredSize (rows
);
428 /*************************************************************************/
431 * Returns the preferred size of this component assuming it had the specified
434 * @param rows The number of rows to size for.
436 * @return The preferred size of this component.
438 * @deprecated This method is deprecated in favor of
439 * <code>getPreferredSize(int)</code>>
442 preferredSize(int rows
)
444 ListPeer peer
= (ListPeer
) getPeer ();
446 return peer
.preferredSize (rows
);
448 return new Dimension (0, 0);
451 /*************************************************************************/
454 * This method adds the specified item to the end of the list.
456 * @param item The item to add to the list.
464 /*************************************************************************/
467 * This method adds the specified item to the end of the list.
469 * @param item The item to add to the list.
471 * @deprecated Use add() instead.
479 /*************************************************************************/
482 * Adds the specified item to the specified location in the list.
483 * If the desired index is -1 or greater than the number of rows
484 * in the list, then the item is added to the end.
486 * @param item The item to add to the list.
487 * @param index The location in the list to add the item, or -1 to add
491 add(String item
, int index
)
493 addItem (item
, index
);
496 /*************************************************************************/
499 * Adds the specified item to the specified location in the list.
500 * If the desired index is -1 or greater than the number of rows
501 * in the list, then the item is added to the end.
503 * @param item The item to add to the list.
504 * @param index The location in the list to add the item, or -1 to add
507 * @deprecated Use add() instead.
510 addItem(String item
, int index
)
512 if ((index
== -1) || (index
>= items
.size ()))
513 items
.addElement (item
);
515 items
.insertElementAt (item
, index
);
517 ListPeer peer
= (ListPeer
) getPeer ();
519 peer
.add (item
, index
);
522 /*************************************************************************/
525 * Deletes the item at the specified index.
527 * @param index The index of the item to delete.
529 * @exception IllegalArgumentException If the index is not valid
534 delItem(int index
) throws IllegalArgumentException
536 items
.removeElementAt (index
);
538 ListPeer peer
= (ListPeer
) getPeer ();
540 peer
.delItems (index
, index
);
543 /*************************************************************************/
546 * Deletes the item at the specified index.
548 * @param index The index of the item to delete.
550 * @exception IllegalArgumentException If the index is not valid
553 remove(int index
) throws IllegalArgumentException
558 /*************************************************************************/
561 * Deletes all items in the specified index range.
563 * @param start The beginning index of the range to delete.
564 * @param end The ending index of the range to delete.
566 * @exception IllegalArgumentException If the indexes are not valid
568 * @deprecated This method is deprecated for some unknown reason.
570 public synchronized void
571 delItems(int start
, int end
) throws IllegalArgumentException
573 if ((start
< 0) || (start
>= items
.size()))
574 throw new IllegalArgumentException("Bad list start index value: " + start
);
576 if ((start
< 0) || (start
>= items
.size()))
577 throw new IllegalArgumentException("Bad list start index value: " + start
);
580 throw new IllegalArgumentException("Start is greater than end!");
582 // We must run the loop in reverse direction.
583 for (int i
= end
; i
>= start
; --i
)
584 items
.removeElementAt (i
);
587 ListPeer l
= (ListPeer
) peer
;
588 l
.delItems (start
, end
);
592 /*************************************************************************/
595 * Deletes the first occurrence of the specified item from the list.
597 * @param item The item to delete.
599 * @exception IllegalArgumentException If the specified item does not exist.
601 public synchronized void
602 remove(String item
) throws IllegalArgumentException
604 int index
= items
.indexOf(item
);
606 throw new IllegalArgumentException("List element to delete not found");
611 /*************************************************************************/
614 * Deletes all of the items from the list.
616 public synchronized void
622 /*************************************************************************/
625 * Deletes all of the items from the list.
627 * @deprecated This method is deprecated in favor of <code>removeAll()</code>.
634 ListPeer peer
= (ListPeer
) getPeer ();
639 /*************************************************************************/
642 * Replaces the item at the specified index with the specified item.
644 * @param item The new item value.
645 * @param index The index of the item to replace.
647 * @exception IllegalArgumentException If the index is not valid.
649 public synchronized void
650 replaceItem(String item
, int index
) throws IllegalArgumentException
652 if ((index
< 0) || (index
>= items
.size()))
653 throw new IllegalArgumentException("Bad list index: " + index
);
655 items
.insertElementAt(item
, index
+ 1);
656 items
.removeElementAt (index
);
660 ListPeer l
= (ListPeer
) peer
;
662 /* We add first and then remove so that the selected
663 item remains the same */
664 l
.add (item
, index
+ 1);
665 l
.delItems (index
, index
);
669 /*************************************************************************/
672 * Returns the index of the currently selected item. -1 will be returned
673 * if there are no selected rows or if there are multiple selected rows.
675 * @return The index of the selected row.
677 public synchronized int
682 ListPeer l
= (ListPeer
) peer
;
683 selected
= l
.getSelectedIndexes ();
686 if (selected
== null || selected
.length
!= 1)
691 /*************************************************************************/
694 * Returns an array containing the indexes of the rows that are
695 * currently selected.
697 * @return A list of indexes of selected rows.
699 public synchronized int[]
704 ListPeer l
= (ListPeer
) peer
;
705 selected
= l
.getSelectedIndexes ();
710 /*************************************************************************/
713 * Returns the item that is currently selected, or <code>null</code> if there
714 * is no item selected. FIXME: What happens if multiple items selected?
716 * @return The selected item, or <code>null</code> if there is no
719 public synchronized String
722 int index
= getSelectedIndex();
726 return((String
)items
.elementAt(index
));
729 /*************************************************************************/
732 * Returns the list of items that are currently selected in this list.
734 * @return The list of currently selected items.
736 public synchronized String
[]
739 int[] indexes
= getSelectedIndexes();
741 return(new String
[0]);
743 String
[] retvals
= new String
[indexes
.length
];
744 if (retvals
.length
> 0)
745 for (int i
= 0 ; i
< retvals
.length
; i
++)
746 retvals
[i
] = (String
)items
.elementAt(indexes
[i
]);
751 /*************************************************************************/
754 * Returns the list of items that are currently selected in this list as
755 * an array of type <code>Object[]</code> instead of <code>String[]</code>.
757 * @return The list of currently selected items.
759 public synchronized Object
[]
762 int[] indexes
= getSelectedIndexes();
764 return(new Object
[0]);
766 Object
[] retvals
= new Object
[indexes
.length
];
767 if (retvals
.length
> 0)
768 for (int i
= 0 ; i
< retvals
.length
; i
++)
769 retvals
[i
] = items
.elementAt(indexes
[i
]);
774 /*************************************************************************/
777 * Tests whether or not the specified index is selected.
779 * @param index The index to test.
781 * @return <code>true</code> if the index is selected, <code>false</code>
785 isIndexSelected(int index
)
787 return isSelected (index
);
790 /*************************************************************************/
793 * Tests whether or not the specified index is selected.
795 * @param index The index to test.
797 * @return <code>true</code> if the index is selected, <code>false</code>
800 * @deprecated This method is deprecated in favor of
801 * <code>isIndexSelected(int)</code>.
804 isSelected(int index
)
806 int[] indexes
= getSelectedIndexes ();
808 for (int i
= 0; i
< indexes
.length
; i
++)
809 if (indexes
[i
] == index
)
815 /*************************************************************************/
818 * This method ensures that the item at the specified index is visible.
820 * @exception IllegalArgumentException If the specified index is out of
823 public synchronized void
824 makeVisible(int index
) throws IllegalArgumentException
826 if ((index
< 0) || (index
>= items
.size()))
827 throw new IllegalArgumentException("Bad list index: " + index
);
829 visibleIndex
= index
;
832 ListPeer l
= (ListPeer
) peer
;
833 l
.makeVisible (index
);
837 /*************************************************************************/
840 * Returns the index of the last item that was made visible via the
841 * <code>makeVisible()</code> method.
843 * @return The index of the last item made visible via the
844 * <code>makeVisible()</code> method.
849 return(visibleIndex
);
852 /*************************************************************************/
855 * Makes the item at the specified index selected.
857 * @param index The index of the item to select.
859 public synchronized void
862 ListPeer lp
= (ListPeer
)getPeer();
867 /*************************************************************************/
870 * Makes the item at the specified index not selected.
872 * @param index The index of the item to unselect.
874 public synchronized void
877 ListPeer lp
= (ListPeer
)getPeer();
882 /*************************************************************************/
885 * Notifies this object to create its native peer.
891 peer
= getToolkit ().createList (this);
895 /*************************************************************************/
898 * Notifies this object to destroy its native peer.
903 super.removeNotify();
906 /*************************************************************************/
909 * Adds the specified <code>ActionListener</code> to the list of
910 * registered listeners for this object.
912 * @param listener The listener to add.
914 public synchronized void
915 addActionListener(ActionListener listener
)
917 action_listeners
= AWTEventMulticaster
.add(action_listeners
, listener
);
920 /*************************************************************************/
923 * Removes the specified <code>ActionListener</code> from the list of
924 * registers listeners for this object.
926 * @param listener The listener to remove.
928 public synchronized void
929 removeActionListener(ActionListener listener
)
931 action_listeners
= AWTEventMulticaster
.remove(action_listeners
, listener
);
934 /*************************************************************************/
937 * Adds the specified <code>ItemListener</code> to the list of
938 * registered listeners for this object.
940 * @param listener The listener to add.
942 public synchronized void
943 addItemListener(ItemListener listener
)
945 item_listeners
= AWTEventMulticaster
.add(item_listeners
, listener
);
948 /*************************************************************************/
951 * Removes the specified <code>ItemListener</code> from the list of
952 * registers listeners for this object.
954 * @param listener The listener to remove.
956 public synchronized void
957 removeItemListener(ItemListener listener
)
959 item_listeners
= AWTEventMulticaster
.remove(item_listeners
, listener
);
962 /*************************************************************************/
965 * Processes the specified event for this object. If the event is an
966 * instance of <code>ActionEvent</code> then the
967 * <code>processActionEvent()</code> method is called. Similarly, if the
968 * even is an instance of <code>ItemEvent</code> then the
969 * <code>processItemEvent()</code> method is called. Otherwise the
970 * superclass method is called to process this event.
972 * @param event The event to process.
975 processEvent(AWTEvent event
)
977 if (event
instanceof ActionEvent
)
978 processActionEvent((ActionEvent
)event
);
979 else if (event
instanceof ItemEvent
)
980 processItemEvent((ItemEvent
)event
);
982 super.processEvent(event
);
985 /*************************************************************************/
988 * This method processes the specified event by dispatching it to any
989 * registered listeners. Note that this method will only get called if
990 * action events are enabled. This will happen automatically if any
991 * listeners are added, or it can be done "manually" by calling
992 * the <code>enableEvents()</code> method.
994 * @param event The event to process.
997 processActionEvent(ActionEvent event
)
999 if (action_listeners
!= null)
1000 action_listeners
.actionPerformed(event
);
1003 /*************************************************************************/
1006 * This method processes the specified event by dispatching it to any
1007 * registered listeners. Note that this method will only get called if
1008 * item events are enabled. This will happen automatically if any
1009 * listeners are added, or it can be done "manually" by calling
1010 * the <code>enableEvents()</code> method.
1012 * @param event The event to process.
1015 processItemEvent(ItemEvent event
)
1017 if (item_listeners
!= null)
1018 item_listeners
.itemStateChanged(event
);
1022 dispatchEventImpl(AWTEvent e
)
1024 if (e
.id
<= ItemEvent
.ITEM_LAST
1025 && e
.id
>= ItemEvent
.ITEM_FIRST
1026 && (item_listeners
!= null
1027 || (eventMask
& AWTEvent
.ITEM_EVENT_MASK
) != 0))
1029 else if (e
.id
<= ActionEvent
.ACTION_LAST
1030 && e
.id
>= ActionEvent
.ACTION_FIRST
1031 && (action_listeners
!= null
1032 || (eventMask
& AWTEvent
.ACTION_EVENT_MASK
) != 0))
1035 super.dispatchEventImpl(e
);
1038 /*************************************************************************/
1041 * Returns a debugging string for this object.
1043 * @return A debugging string for this object.
1048 return "multiple=" + multipleMode
+ ",rows=" + rows
+ super.paramString();
1052 * Returns an array of all the objects currently registered as FooListeners
1053 * upon this <code>List</code>. FooListeners are registered using the
1054 * addFooListener method.
1056 * @exception ClassCastException If listenerType doesn't specify a class or
1057 * interface that implements java.util.EventListener.
1059 public EventListener
[] getListeners (Class listenerType
)
1061 if (listenerType
== ActionListener
.class)
1062 return AWTEventMulticaster
.getListeners (action_listeners
, listenerType
);
1064 if (listenerType
== ItemListener
.class)
1065 return AWTEventMulticaster
.getListeners (item_listeners
, listenerType
);
1067 return super.getListeners (listenerType
);
1071 * Returns all action listeners registered to this object.
1073 public ActionListener
[] getActionListeners ()
1075 return (ActionListener
[]) getListeners (ActionListener
.class);
1079 * Returns all action listeners registered to this object.
1081 public ItemListener
[] getItemListeners ()
1083 return (ItemListener
[]) getListeners (ItemListener
.class);
1086 // Accessibility internal class
1087 protected class AccessibleAWTList
extends AccessibleAWTComponent
1088 implements AccessibleSelection
, ItemListener
, ActionListener
1090 protected class AccessibleAWTListChild
extends AccessibleAWTComponent
1091 implements Accessible
1094 private List parent
;
1096 public AccessibleAWTListChild(List parent
, int indexInParent
)
1098 this.parent
= parent
;
1099 index
= indexInParent
;
1105 * @see javax.accessibility.Accessible#getAccessibleContext()
1107 public AccessibleContext
getAccessibleContext()
1112 public AccessibleRole
getAccessibleRole()
1114 return AccessibleRole
.LIST_ITEM
;
1117 public AccessibleStateSet
getAccessibleStateSet()
1119 AccessibleStateSet states
= super.getAccessibleStateSet();
1120 if (parent
.isIndexSelected(index
))
1121 states
.add(AccessibleState
.SELECTED
);
1125 public int getAccessibleIndexInParent()
1132 public AccessibleAWTList()
1134 addItemListener(this);
1135 addActionListener(this);
1138 public AccessibleRole
getAccessibleRole()
1140 return AccessibleRole
.LIST
;
1143 public AccessibleStateSet
getAccessibleStateSet()
1145 AccessibleStateSet states
= super.getAccessibleStateSet();
1146 states
.add(AccessibleState
.SELECTABLE
);
1147 if (isMultipleMode())
1148 states
.add(AccessibleState
.MULTISELECTABLE
);
1152 public int getAccessibleChildrenCount()
1154 return getItemCount();
1157 public Accessible
getAccessibleChild(int i
)
1159 if (i
>= getItemCount())
1161 return new AccessibleAWTListChild(List
.this, i
);
1165 * @see javax.accessibility.AccessibleSelection#getAccessibleSelectionCount()
1167 public int getAccessibleSelectionCount()
1169 return getSelectedIndexes().length
;
1173 * @see javax.accessibility.AccessibleSelection#getAccessibleSelection()
1175 public AccessibleSelection
getAccessibleSelection()
1181 * @see javax.accessibility.AccessibleSelection#getAccessibleSelection(int)
1183 public Accessible
getAccessibleSelection(int i
)
1185 int[] items
= getSelectedIndexes();
1186 if (i
>= items
.length
)
1188 return new AccessibleAWTListChild(List
.this, items
[i
]);
1192 * @see javax.accessibility.AccessibleSelection#isAccessibleChildSelected(int)
1194 public boolean isAccessibleChildSelected(int i
)
1196 return isIndexSelected(i
);
1200 * @see javax.accessibility.AccessibleSelection#addAccessibleSelection(int)
1202 public void addAccessibleSelection(int i
)
1208 * @see javax.accessibility.AccessibleSelection#removeAccessibleSelection(int)
1210 public void removeAccessibleSelection(int i
)
1216 * @see javax.accessibility.AccessibleSelection#clearAccessibleSelection()
1218 public void clearAccessibleSelection()
1220 for (int i
= 0; i
< getItemCount(); i
++)
1225 * @see javax.accessibility.AccessibleSelection#selectAllAccessibleSelection()
1227 public void selectAllAccessibleSelection()
1229 if (isMultipleMode())
1230 for (int i
= 0; i
< getItemCount(); i
++)
1235 * @see java.awt.event.ItemListener#itemStateChanged(java.awt.event.ItemEvent)
1237 public void itemStateChanged(ItemEvent event
)
1242 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
1244 public void actionPerformed(ActionEvent event
)
1251 * Gets the AccessibleContext associated with this <code>List</code>.
1252 * The context is created, if necessary.
1254 * @return the associated context
1256 public AccessibleContext
getAccessibleContext()
1258 /* Create the context if this is the first request */
1259 if (accessibleContext
== null)
1260 accessibleContext
= new AccessibleAWTList();
1261 return accessibleContext
;