001/* List.java -- A listbox widget
002   Copyright (C) 1999, 2002, 2004, 2006,  Free Software Foundation, Inc.
003
004This file is part of GNU Classpath.
005
006GNU Classpath is free software; you can redistribute it and/or modify
007it under the terms of the GNU General Public License as published by
008the Free Software Foundation; either version 2, or (at your option)
009any later version.
010
011GNU Classpath is distributed in the hope that it will be useful, but
012WITHOUT ANY WARRANTY; without even the implied warranty of
013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014General Public License for more details.
015
016You should have received a copy of the GNU General Public License
017along with GNU Classpath; see the file COPYING.  If not, write to the
018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
01902110-1301 USA.
020
021Linking this library statically or dynamically with other modules is
022making a combined work based on this library.  Thus, the terms and
023conditions of the GNU General Public License cover the whole
024combination.
025
026As a special exception, the copyright holders of this library give you
027permission to link this library with independent modules to produce an
028executable, regardless of the license terms of these independent
029modules, and to copy and distribute the resulting executable under
030terms of your choice, provided that you also meet, for each linked
031independent module, the terms and conditions of the license of that
032module.  An independent module is a module which is not derived from
033or based on this library.  If you modify this library, you may extend
034this exception to your version of the library, but you are not
035obligated to do so.  If you do not wish to do so, delete this
036exception statement from your version. */
037
038
039package java.awt;
040
041import java.awt.event.ActionEvent;
042import java.awt.event.ActionListener;
043import java.awt.event.ItemEvent;
044import java.awt.event.ItemListener;
045import java.awt.peer.ListPeer;
046import java.util.EventListener;
047import java.util.Vector;
048
049import javax.accessibility.Accessible;
050import javax.accessibility.AccessibleContext;
051import javax.accessibility.AccessibleRole;
052import javax.accessibility.AccessibleSelection;
053import javax.accessibility.AccessibleState;
054import javax.accessibility.AccessibleStateSet;
055
056/**
057 * Class that implements a listbox widget
058 *
059 * @author Aaron M. Renn (arenn@urbanophile.com)
060 */
061public class List extends Component
062  implements ItemSelectable, Accessible
063{
064
065  /**
066   * The number used to generate the name returned by getName.
067   */
068  private static transient long next_list_number;  
069
070  // Serialization constant
071  private static final long serialVersionUID = -3304312411574666869L;
072
073  // FIXME: Need read/writeObject
074
075  /**
076    * @serial The items in the list.
077    */
078  private Vector items = new Vector();
079
080  /**
081   * @serial Indicates whether or not multiple items can be selected
082   * simultaneously.
083   */
084  private boolean multipleMode;
085
086  /**
087   * @serial The number of rows in the list.  This is set on creation
088   * only and cannot be modified.
089   */
090  private int rows;
091
092  /**
093   * @serial An array of the item indices that are selected.
094   */
095  private int[] selected;
096
097  /**
098   * @serial An index value used by <code>makeVisible()</code> and
099   * <code>getVisibleIndex</code>.
100   */
101  private int visibleIndex = -1;
102
103  // The list of ItemListeners for this object.
104  private ItemListener item_listeners;
105
106  // The list of ActionListeners for this object.
107  private ActionListener action_listeners;
108
109  /**
110   * Initializes a new instance of <code>List</code> with no visible lines
111   * and multi-select disabled.
112   *
113   * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true.
114   * @since 1.1
115   */
116  public List()
117  {
118    this(4, false);
119  }
120
121  /**
122   * Initializes a new instance of <code>List</code> with the specified
123   * number of visible lines and multi-select disabled.
124   *
125   * @param rows The number of visible rows in the list.
126   *
127   * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true.
128   */
129  public List(int rows)
130  {
131    this(rows, false);
132  }
133
134  /**
135   * Initializes a new instance of <code>List</code> with the specified
136   * number of lines and the specified multi-select setting.
137   *
138   * @param rows The number of visible rows in the list.
139   * @param multipleMode <code>true</code> if multiple lines can be selected
140   * simultaneously, <code>false</code> otherwise.
141   *
142   * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true.
143   */
144  public List(int rows, boolean multipleMode)
145  {
146    if (rows == 0)
147      this.rows = 4;
148    else
149      this.rows = rows;
150  
151    this.multipleMode = multipleMode;
152    selected = new int[0];
153
154    if (GraphicsEnvironment.isHeadless())
155      throw new HeadlessException();
156  
157  }
158
159  /**
160   * Returns the number of items in this list.
161   *
162   * @return The number of items in this list.
163   * 
164   * @since 1.1
165   */
166  public int getItemCount()
167  {
168    return countItems();
169  }
170
171  /**
172   * Returns the number of items in this list.
173   *
174   * @return The number of items in this list.
175   *
176   * @deprecated This method is deprecated in favor of
177   * <code>getItemCount()</code>
178   */
179  public int countItems()
180  {
181    return items.size();
182  }
183
184  /**
185   * Returns the complete list of items.
186   *
187   * @return The complete list of items in the list.
188   * 
189   * @since 1.1
190   */
191  public synchronized String[] getItems()
192  {
193    String[] l_items = new String[getItemCount()];
194 
195    items.copyInto(l_items);
196    return(l_items);
197  }
198
199  /**
200   * Returns the item at the specified index.
201   *
202   * @param index The index of the item to retrieve.
203   *
204   * @exception IndexOutOfBoundsException If the index value is not valid.
205   */
206  public String getItem(int index)
207  {
208    return((String) items.elementAt(index));
209  }
210
211  /**
212   * Returns the number of visible rows in the list.
213   *
214   * @return The number of visible rows in the list.
215   */
216  public int getRows()
217  {
218    return(rows);
219  }
220
221  /**
222   * Tests whether or not multi-select mode is enabled.
223   *
224   * @return <code>true</code> if multi-select mode is enabled,
225   * <code>false</code> otherwise.
226   * 
227   * @since 1.1
228   */
229  public boolean isMultipleMode()
230  {
231    return allowsMultipleSelections ();
232  }
233
234  /**
235   * Tests whether or not multi-select mode is enabled.
236   *
237   * @return <code>true</code> if multi-select mode is enabled,
238   * <code>false</code> otherwise.
239   *
240   * @deprecated This method is deprecated in favor of 
241   * <code>isMultipleMode()</code>.
242   */
243  public boolean allowsMultipleSelections()
244  {
245    return multipleMode;
246  }
247
248  /**
249   * This method enables or disables multiple selection mode for this
250   * list.
251   *
252   * @param multipleMode <code>true</code> to enable multiple mode,
253   * <code>false</code> otherwise.
254   * 
255   * @since 1.1
256   */
257  public void setMultipleMode(boolean multipleMode)
258  {
259    setMultipleSelections (multipleMode);
260  }
261
262  /**
263   * This method enables or disables multiple selection mode for this
264   * list.
265   *
266   * @param multipleMode <code>true</code> to enable multiple mode,
267   * <code>false</code> otherwise.
268   *
269   * @deprecated
270   */
271  public void setMultipleSelections(boolean multipleMode)
272  {  
273    this.multipleMode = multipleMode;
274
275    ListPeer peer = (ListPeer) getPeer();
276    if (peer != null)
277      peer.setMultipleMode(multipleMode);
278      
279  }
280
281  /**
282   * Returns the minimum size of this component.
283   *
284   * @return The minimum size of this component.
285   * 
286   * @since 1.1
287   */
288  public Dimension getMinimumSize()
289  {
290    return getMinimumSize(getRows());
291  }
292
293  /**
294   * Returns the minimum size of this component.
295   *
296   * @return The minimum size of this component.
297   *
298   * @deprecated This method is deprecated in favor of
299   * <code>getMinimumSize</code>.
300   */
301  public Dimension minimumSize()
302  {
303    return minimumSize(getRows());
304  }
305
306  /**
307   * Returns the minimum size of this component assuming it had the specified
308   * number of rows.
309   *
310   * @param rows The number of rows to size for.
311   *
312   * @return The minimum size of this component.
313   * 
314   * @since 1.1
315   */
316  public Dimension getMinimumSize(int rows)
317  {
318    return minimumSize(rows);
319  }
320
321  /**
322   * Returns the minimum size of this component assuming it had the specified
323   * number of rows.
324   *
325   * @param rows The number of rows to size for.
326   *
327   * @return The minimum size of this component.
328   *
329   * @deprecated This method is deprecated in favor of 
330   * <code>getMinimumSize(int)</code>>
331   */
332  public Dimension minimumSize(int rows)
333  {
334    ListPeer peer = (ListPeer) getPeer();
335    if (peer != null)
336      return peer.minimumSize(rows);
337    else
338      return new Dimension(0, 0);
339  }
340
341  /**
342   * Returns the preferred size of this component.
343   *
344   * @return The preferred size of this component.
345   * 
346   * @since 1.1
347   */
348  public Dimension getPreferredSize()
349  {
350    return getPreferredSize(getRows());
351  }
352
353  /**
354   * Returns the preferred size of this component.
355   *
356   * @return The preferred size of this component.
357   *
358   * @deprecated This method is deprecated in favor of
359   * <code>getPreferredSize</code>.
360   */
361  public Dimension preferredSize() 
362  {
363    return preferredSize(getRows());
364  }
365
366  /**
367   * Returns the preferred size of this component assuming it had the specified
368   * number of rows.
369   *
370   * @param rows The number of rows to size for.
371   *
372   * @return The preferred size of this component.
373   * 
374   * @since 1.1
375   */
376  public Dimension getPreferredSize(int rows)
377  {
378    return preferredSize(rows);
379  }
380
381  /**
382   * Returns the preferred size of this component assuming it had the specified
383   * number of rows.
384   *
385   * @param rows The number of rows to size for.
386   *
387   * @return The preferred size of this component.
388   *
389   * @deprecated This method is deprecated in favor of 
390   * <code>getPreferredSize(int)</code>>
391   */
392  public Dimension preferredSize(int rows)
393  {
394    ListPeer peer = (ListPeer)getPeer();
395    if (peer != null)
396      return peer.preferredSize(rows);
397    else
398      return getSize();
399  }
400
401  /**
402   * This method adds the specified item to the end of the list.
403   *
404   * @param item The item to add to the list.
405   * 
406   * @since 1.1
407   */
408  public void add(String item)
409  {
410    add (item, -1);
411  }
412
413  /**
414   * This method adds the specified item to the end of the list.
415   *
416   * @param item The item to add to the list.
417   *
418   * @deprecated Use add() instead.
419   */
420  public void addItem(String item)
421  {
422    addItem(item, -1);
423  }
424
425  /**
426   * Adds the specified item to the specified location in the list.
427   * If the desired index is -1 or greater than the number of rows
428   * in the list, then the item is added to the end.
429   *
430   * @param item The item to add to the list.
431   * @param index The location in the list to add the item, or -1 to add
432   * to the end.
433   * 
434   * @since 1.1
435   */
436  public void add(String item, int index)
437  {
438    addItem(item, index);
439  }
440
441  /**
442   * Adds the specified item to the specified location in the list.
443   * If the desired index is -1 or greater than the number of rows
444   * in the list, then the item is added to the end.
445   *
446   * @param item The item to add to the list.
447   * @param index The location in the list to add the item, or -1 to add
448   * to the end.
449   *
450   * @deprecated Use add() instead.
451   */
452  public void addItem(String item, int index)
453  {
454    if (item == null)
455      item = ""; 
456  
457    if (index < -1)
458      index = -1;
459  
460    if ((index == -1) || (index >= items.size ()))
461      items.addElement (item);
462    else
463      items.insertElementAt(item, index);
464
465    ListPeer peer = (ListPeer) getPeer();
466    if (peer != null)
467      peer.add (item, index);
468  }
469
470  /**
471   * Deletes the item at the specified index.
472   *
473   * @param index The index of the item to delete.
474   *
475   * @exception IllegalArgumentException If the index is not valid
476   *
477   * @deprecated
478   */
479  public void delItem(int index) throws IllegalArgumentException
480  {
481    boolean selected = false;
482    if (isSelected(index))
483      {
484        selected = true;
485        deselect(index);   
486      }
487  
488    items.removeElementAt (index);
489  
490    if (selected)
491      select(index);
492
493    ListPeer peer = (ListPeer) getPeer();
494    if (peer != null)
495      peer.delItems (index, index);
496  }
497
498  /**
499   * Deletes the item at the specified index.
500   *
501   * @param index The index of the item to delete.
502   *
503   * @exception IllegalArgumentException If the index is not valid
504   * 
505   * @since 1.1
506   */
507  public void remove(int index) throws IllegalArgumentException
508  {
509    delItem(index);
510  }
511
512  /**
513   * Deletes all items in the specified index range.
514   *
515   * @param start The beginning index of the range to delete.
516   * @param end The ending index of the range to delete.
517   *
518   * @exception IllegalArgumentException If the indexes are not valid
519   *
520   * @deprecated This method is deprecated for some unknown reason.
521   */
522  public synchronized void delItems(int start, int end) 
523    throws IllegalArgumentException
524  {
525    // We must run the loop in reverse direction.
526    for (int i = end; i >= start; --i)
527      items.removeElementAt (i);
528    if (peer != null)
529      {
530        ListPeer l = (ListPeer) peer;
531        l.delItems (start, end);
532      }
533  }
534
535  /**
536   * Deletes the first occurrence of the specified item from the list.
537   *
538   * @param item The item to delete.
539   *
540   * @exception IllegalArgumentException If the specified item does not exist.
541   * 
542   * @since 1.1
543   */
544  public synchronized void remove(String item) throws IllegalArgumentException
545  {
546    int index = items.indexOf(item);
547    if (index == -1)
548      throw new IllegalArgumentException("List element to delete not found");
549
550    remove(index);
551  }
552
553  /**
554   * Deletes all of the items from the list.
555   * 
556   * @since 1.1
557   */
558  public synchronized void removeAll()
559  {
560    clear();
561  }
562
563  /**
564   * Deletes all of the items from the list.
565   * 
566   * @deprecated This method is deprecated in favor of <code>removeAll()</code>.
567   */
568  public void clear()
569  {
570    items.clear();
571
572    ListPeer peer = (ListPeer) getPeer();
573    if (peer != null)
574      peer.removeAll();
575  
576    selected = new int[0];
577  }
578
579  /**
580   * Replaces the item at the specified index with the specified item.
581   *
582   * @param item The new item value.
583   * @param index The index of the item to replace.
584   *
585   * @exception ArrayIndexOutOfBoundsException If the index is not valid.
586   */
587  public synchronized void replaceItem(String item, int index) 
588    throws ArrayIndexOutOfBoundsException
589  {
590    if ((index < 0) || (index >= items.size()))
591      throw new ArrayIndexOutOfBoundsException("Bad list index: " + index);
592
593    items.insertElementAt(item, index + 1);
594    items.removeElementAt (index);
595
596    if (peer != null)
597      {
598        ListPeer l = (ListPeer) peer;
599
600        /* We add first and then remove so that the selected
601           item remains the same */
602        l.add (item, index + 1);
603        l.delItems (index, index);
604      }
605  }
606
607  /**
608   * Returns the index of the currently selected item.  -1 will be returned
609   * if there are no selected rows or if there are multiple selected rows.
610   *
611   * @return The index of the selected row.
612   */
613  public synchronized int getSelectedIndex()
614  {
615    if (peer != null)
616      {
617        ListPeer l = (ListPeer) peer;
618        selected = l.getSelectedIndexes ();
619      }
620
621    if (selected == null || selected.length != 1)
622      return -1;
623  
624    return selected[0];
625  }
626
627  /**
628   * Returns an array containing the indexes of the rows that are 
629   * currently selected.
630   *
631   * @return A list of indexes of selected rows.
632   */
633  public synchronized int[] getSelectedIndexes()
634  {
635    if (peer != null)
636      {
637        ListPeer l = (ListPeer) peer;
638        selected = l.getSelectedIndexes();
639      }   
640   
641    return selected;
642  }
643
644  /**
645   * Returns the item that is currently selected, or <code>null</code> if there 
646   * is no item selected.  FIXME: What happens if multiple items selected?
647   *
648   * @return The selected item, or <code>null</code> if there is no
649   * selected item.
650   */
651  public synchronized String getSelectedItem()
652  {
653    int index = getSelectedIndex();
654    if (index == -1)
655      return(null);
656
657    return((String) items.elementAt(index));
658  }
659
660  /**
661   * Returns the list of items that are currently selected in this list.
662   *
663   * @return The list of currently selected items.
664   */
665  public synchronized String[] getSelectedItems()
666  {
667    int[] indexes = getSelectedIndexes();
668    if (indexes == null)
669      return(new String[0]);
670
671    String[] retvals = new String[indexes.length];
672    if (retvals.length > 0)
673      for (int i = 0 ; i < retvals.length; i++)
674         retvals[i] = (String)items.elementAt(indexes[i]);
675
676    return(retvals);
677  }
678
679  /**
680   * Returns the list of items that are currently selected in this list as
681   * an array of type <code>Object[]</code> instead of <code>String[]</code>.
682   *
683   * @return The list of currently selected items.
684   */
685  public synchronized Object[] getSelectedObjects()
686  {
687    int[] indexes = getSelectedIndexes();
688    if (indexes == null)
689      return(new Object[0]);
690
691    Object[] retvals = new Object[indexes.length];
692    if (retvals.length > 0)
693      for (int i = 0 ; i < retvals.length; i++)
694         retvals[i] = items.elementAt(indexes[i]);
695
696    return(retvals);
697  }
698
699  /**
700   * Tests whether or not the specified index is selected.
701   *
702   * @param index The index to test.
703   *
704   * @return <code>true</code> if the index is selected, <code>false</code>
705   * otherwise.
706   * 
707   * @since 1.1
708   */
709  public boolean isIndexSelected(int index)
710  {
711    return isSelected(index);
712  }
713
714  /**
715   * Tests whether or not the specified index is selected.
716   *
717   * @param index The index to test.
718   *
719   * @return <code>true</code> if the index is selected, <code>false</code>
720   * otherwise.
721   *
722   * @deprecated This method is deprecated in favor of
723   * <code>isIndexSelected(int)</code>.
724   */
725  public boolean isSelected(int index)
726  {
727    int[] indexes = getSelectedIndexes();
728
729    for (int i = 0; i < indexes.length; i++)
730      if (indexes[i] == index)
731        return true;
732
733    return false;
734  }
735
736  /**
737   * This method ensures that the item at the specified index is visible.
738   *
739   * @param index The index of the item to be made visible.
740   */
741  public synchronized void makeVisible(int index) 
742    throws IllegalArgumentException
743  {
744    visibleIndex = index;
745    if (peer != null)
746      {
747        ListPeer l = (ListPeer) peer;
748        l.makeVisible (index);
749      }
750  }
751
752  /**
753   * Returns the index of the last item that was made visible via the
754   * <code>makeVisible()</code> method.
755   *
756   * @return The index of the last item made visible via the 
757   * <code>makeVisible()</code> method.
758   */
759  public int getVisibleIndex()
760  {
761    return visibleIndex;
762  }
763
764  /**
765   * Makes the item at the specified index selected.
766   *
767   * @param index The index of the item to select.
768   */
769  public synchronized void select(int index)
770  {
771    ListPeer lp = (ListPeer) getPeer();
772    if (lp != null)
773      lp.select(index);
774    
775   if (selected != null)
776     {
777       boolean found = false;
778       for (int i = 0; i < selected.length; i++)
779         {
780           if (selected[i] == index)
781           found = true;
782         }
783       if (! found)
784         {
785           if (! isMultipleMode())
786             {
787               selected = new int[] { index };
788               return;
789             }       
790           int[] temp = new int[selected.length + 1];
791           System.arraycopy(selected, 0, temp, 0, selected.length);
792           temp[selected.length] = index;
793           selected = temp;
794         }
795     } 
796   else 
797     {
798       selected = new int[1];
799       selected[0] = index;
800     }
801  }
802
803  /**
804   * Makes the item at the specified index not selected.
805   *
806   * @param index The index of the item to unselect.
807   */
808  public synchronized void deselect(int index)
809  {
810    if (isSelected(index))
811      {
812        ListPeer lp = (ListPeer)getPeer();
813        if (lp != null)
814          lp.deselect(index);
815
816        int[] temp = new int[selected.length - 1];
817        for (int i = 0; i < temp.length; i++)
818          {
819            if (selected[i] != index)
820              temp[i] = selected[i];
821            else
822              {
823                System.arraycopy(selected, i + 1, temp, i, 
824                                 selected.length - i - 1);
825                break;
826              }
827          }
828        selected = temp;
829      }
830  }
831
832  /**
833   * Notifies this object to create its native peer.
834   */
835  public void addNotify()
836  {
837    if (peer == null)
838      peer = getToolkit ().createList(this);
839    super.addNotify ();
840  }
841
842  /**
843   * Notifies this object to destroy its native peer.
844   */
845  public void removeNotify()
846  {
847    super.removeNotify();
848  }
849
850  /**
851   * Adds the specified <code>ActionListener</code> to the list of
852   * registered listeners for this object.
853   *
854   * @param listener The listener to add.
855   * 
856   * @since 1.1
857   */
858  public synchronized void addActionListener(ActionListener listener)
859  {
860    action_listeners = AWTEventMulticaster.add(action_listeners, listener);
861  }
862
863  /**
864   * Removes the specified <code>ActionListener</code> from the list of
865   * registers listeners for this object.
866   *
867   * @param listener The listener to remove.
868   * 
869   * @since 1.1
870   */
871  public synchronized void removeActionListener(ActionListener listener)
872  {
873    action_listeners = AWTEventMulticaster.remove(action_listeners, listener);
874  }
875
876  /**
877   * Adds the specified <code>ItemListener</code> to the list of
878   * registered listeners for this object.
879   *
880   * @param listener The listener to add.
881   * 
882   * @since 1.1
883   */
884  public synchronized void addItemListener(ItemListener listener)
885  {
886    item_listeners = AWTEventMulticaster.add(item_listeners, listener);
887  }
888
889  /**
890   * Removes the specified <code>ItemListener</code> from the list of
891   * registers listeners for this object.
892   *
893   * @param listener The listener to remove.
894   * 
895   * @since 1.1
896   */
897  public synchronized void removeItemListener(ItemListener listener)
898  {
899    item_listeners = AWTEventMulticaster.remove(item_listeners, listener);
900  }
901
902  /**
903   * Processes the specified event for this object.  If the event is an
904   * instance of <code>ActionEvent</code> then the
905   * <code>processActionEvent()</code> method is called.  Similarly, if the
906   * even is an instance of <code>ItemEvent</code> then the
907   * <code>processItemEvent()</code> method is called.  Otherwise the
908   * superclass method is called to process this event.
909   *
910   * @param event The event to process.
911   * 
912   * @since 1.1
913   */
914  protected void processEvent(AWTEvent event)
915  {
916    if (event instanceof ActionEvent)
917      processActionEvent((ActionEvent)event);
918    else if (event instanceof ItemEvent)
919      processItemEvent((ItemEvent)event);
920    else
921      super.processEvent(event);
922  }
923
924  /**
925   * This method processes the specified event by dispatching it to any
926   * registered listeners.  Note that this method will only get called if
927   * action events are enabled.  This will happen automatically if any
928   * listeners are added, or it can be done "manually" by calling
929   * the <code>enableEvents()</code> method.
930   *
931   * @param event The event to process.
932   * 
933   * @since 1.1
934   */
935  protected void processActionEvent(ActionEvent event)
936  {
937    if (action_listeners != null)
938      action_listeners.actionPerformed(event);
939  }
940
941  /**
942   * This method processes the specified event by dispatching it to any
943   * registered listeners.  Note that this method will only get called if
944   * item events are enabled.  This will happen automatically if any
945   * listeners are added, or it can be done "manually" by calling
946   * the <code>enableEvents()</code> method.
947   *
948   * @param event The event to process.
949   * 
950   * @since 1.1
951   */
952  protected void processItemEvent(ItemEvent event)
953  {
954    if (item_listeners != null)
955      item_listeners.itemStateChanged(event);
956  }
957
958  void dispatchEventImpl(AWTEvent e)
959  {
960    if (e.id <= ItemEvent.ITEM_LAST
961        && e.id >= ItemEvent.ITEM_FIRST
962        && (item_listeners != null 
963        || (eventMask & AWTEvent.ITEM_EVENT_MASK) != 0))
964      processEvent(e);
965    else if (e.id <= ActionEvent.ACTION_LAST 
966           && e.id >= ActionEvent.ACTION_FIRST
967           && (action_listeners != null 
968           || (eventMask & AWTEvent.ACTION_EVENT_MASK) != 0))
969      processEvent(e);
970    else
971      super.dispatchEventImpl(e);
972  }
973
974  /**
975   * Returns a debugging string for this object.
976   *
977   * @return A debugging string for this object.
978   */
979  protected String paramString()
980  {
981    return "multiple=" + multipleMode + ",rows=" + rows + super.paramString();
982  }
983
984  /**
985   * Returns an array of all the objects currently registered as FooListeners
986   * upon this <code>List</code>. FooListeners are registered using the 
987   * addFooListener method.
988   *
989   * @exception ClassCastException If listenerType doesn't specify a class or
990   * interface that implements java.util.EventListener.
991   * 
992   * @since 1.3
993   */
994  public <T extends EventListener> T[] getListeners (Class<T> listenerType)
995  {
996    if (listenerType == ActionListener.class)
997      return AWTEventMulticaster.getListeners (action_listeners, listenerType);
998
999    if (listenerType == ItemListener.class)
1000      return AWTEventMulticaster.getListeners (item_listeners, listenerType);
1001
1002    return super.getListeners (listenerType);
1003  }
1004
1005  /**
1006   * Returns all action listeners registered to this object.
1007   * 
1008   * @since 1.4
1009   */
1010  public ActionListener[] getActionListeners ()
1011  {
1012    return (ActionListener[]) getListeners (ActionListener.class);
1013  }
1014  
1015  /**
1016   * Returns all action listeners registered to this object.
1017   * 
1018   * @since 1.4
1019   */
1020  public ItemListener[] getItemListeners ()
1021  {
1022    return (ItemListener[]) getListeners (ItemListener.class);
1023  }
1024  
1025  // Accessibility internal class 
1026  protected class AccessibleAWTList extends AccessibleAWTComponent
1027    implements AccessibleSelection, ItemListener, ActionListener
1028  {
1029    private static final long serialVersionUID = 7924617370136012829L;
1030
1031    protected class AccessibleAWTListChild extends AccessibleAWTComponent
1032      implements Accessible
1033    {
1034      private static final long serialVersionUID = 4412022926028300317L;
1035      
1036      // Field names are fixed by serialization spec.
1037      private List parent;
1038      private int indexInParent;
1039      
1040      public AccessibleAWTListChild(List parent, int indexInParent)
1041      {
1042        this.parent = parent;
1043        this.indexInParent = indexInParent;
1044        if (parent == null)
1045          this.indexInParent = -1;
1046      }
1047      
1048      /* (non-Javadoc)
1049       * @see javax.accessibility.Accessible#getAccessibleContext()
1050       */
1051      public AccessibleContext getAccessibleContext()
1052      {
1053        return this;
1054      }
1055      
1056      public AccessibleRole getAccessibleRole()
1057      {
1058        return AccessibleRole.LIST_ITEM;
1059      }
1060      
1061      public AccessibleStateSet getAccessibleStateSet()
1062      {
1063        AccessibleStateSet states = super.getAccessibleStateSet();
1064        if (parent.isIndexSelected(indexInParent))
1065          states.add(AccessibleState.SELECTED);
1066        return states;
1067      }
1068      
1069      public int getAccessibleIndexInParent()
1070      {
1071        return indexInParent;
1072      }
1073
1074    }
1075    
1076    public AccessibleAWTList()
1077    {
1078      addItemListener(this);
1079      addActionListener(this);
1080    }
1081    
1082    public AccessibleRole getAccessibleRole()
1083    {
1084      return AccessibleRole.LIST;
1085    }
1086    
1087    public AccessibleStateSet getAccessibleStateSet()
1088    {
1089      AccessibleStateSet states = super.getAccessibleStateSet();
1090      states.add(AccessibleState.SELECTABLE);
1091      if (isMultipleMode())
1092        states.add(AccessibleState.MULTISELECTABLE);
1093      return states;
1094    }
1095
1096    public int getAccessibleChildrenCount()
1097    {
1098      return getItemCount();
1099    }
1100
1101    public Accessible getAccessibleChild(int i)
1102    {
1103      if (i >= getItemCount())
1104        return null;
1105      return new AccessibleAWTListChild(List.this, i);
1106    }
1107    
1108    /* (non-Javadoc)
1109     * @see javax.accessibility.AccessibleSelection#getAccessibleSelectionCount()
1110     */
1111    public int getAccessibleSelectionCount()
1112    {
1113      return getSelectedIndexes().length;
1114    }
1115
1116    /* (non-Javadoc)
1117     * @see javax.accessibility.AccessibleSelection#getAccessibleSelection()
1118     */
1119    public AccessibleSelection getAccessibleSelection()
1120    {
1121      return this;
1122    }
1123
1124    /* (non-Javadoc)
1125     * @see javax.accessibility.AccessibleSelection#getAccessibleSelection(int)
1126     */
1127    public Accessible getAccessibleSelection(int i)
1128    {
1129      int[] items = getSelectedIndexes();
1130      if (i >= items.length)
1131        return null;
1132      return new AccessibleAWTListChild(List.this, items[i]);
1133    }
1134
1135    /* (non-Javadoc)
1136     * @see javax.accessibility.AccessibleSelection#isAccessibleChildSelected(int)
1137     */
1138    public boolean isAccessibleChildSelected(int i)
1139    {
1140      return isIndexSelected(i);
1141    }
1142
1143    /* (non-Javadoc)
1144     * @see javax.accessibility.AccessibleSelection#addAccessibleSelection(int)
1145     */
1146    public void addAccessibleSelection(int i)
1147    {
1148      select(i);
1149    }
1150
1151    /* (non-Javadoc)
1152     * @see javax.accessibility.AccessibleSelection#removeAccessibleSelection(int)
1153     */
1154    public void removeAccessibleSelection(int i)
1155    {
1156      deselect(i);
1157    }
1158
1159    /* (non-Javadoc)
1160     * @see javax.accessibility.AccessibleSelection#clearAccessibleSelection()
1161     */
1162    public void clearAccessibleSelection()
1163    {
1164      for (int i = 0; i < getItemCount(); i++)
1165        deselect(i);
1166    }
1167
1168    /* (non-Javadoc)
1169     * @see javax.accessibility.AccessibleSelection#selectAllAccessibleSelection()
1170     */
1171    public void selectAllAccessibleSelection()
1172    {
1173      if (isMultipleMode())
1174        for (int i = 0; i < getItemCount(); i++)
1175          select(i);
1176    }
1177
1178    /* (non-Javadoc)
1179     * @see java.awt.event.ItemListener#itemStateChanged(java.awt.event.ItemEvent)
1180     */
1181    public void itemStateChanged(ItemEvent event)
1182    {
1183    }
1184
1185    /* (non-Javadoc)
1186     * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
1187     */
1188    public void actionPerformed(ActionEvent event)
1189    {
1190    }
1191    
1192  }
1193
1194  /**
1195   * Gets the AccessibleContext associated with this <code>List</code>.
1196   * The context is created, if necessary.
1197   *
1198   * @return the associated context
1199   */
1200  public AccessibleContext getAccessibleContext()
1201  {
1202    /* Create the context if this is the first request */
1203    if (accessibleContext == null)
1204      accessibleContext = new AccessibleAWTList();
1205    return accessibleContext;
1206  }
1207  
1208  /**
1209   * Generate a unique name for this <code>List</code>.
1210   *
1211   * @return A unique name for this <code>List</code>.
1212   */
1213  String generateName()
1214  {
1215    return "list" + getUniqueLong();
1216  }
1217
1218  private static synchronized long getUniqueLong()
1219  {
1220    return next_list_number++;
1221  }
1222} // class List