001    /* List.java -- A listbox widget
002       Copyright (C) 1999, 2002, 2004, 2006,  Free Software Foundation, Inc.
003    
004    This file is part of GNU Classpath.
005    
006    GNU Classpath is free software; you can redistribute it and/or modify
007    it under the terms of the GNU General Public License as published by
008    the Free Software Foundation; either version 2, or (at your option)
009    any later version.
010    
011    GNU Classpath is distributed in the hope that it will be useful, but
012    WITHOUT ANY WARRANTY; without even the implied warranty of
013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014    General Public License for more details.
015    
016    You should have received a copy of the GNU General Public License
017    along with GNU Classpath; see the file COPYING.  If not, write to the
018    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019    02110-1301 USA.
020    
021    Linking this library statically or dynamically with other modules is
022    making a combined work based on this library.  Thus, the terms and
023    conditions of the GNU General Public License cover the whole
024    combination.
025    
026    As a special exception, the copyright holders of this library give you
027    permission to link this library with independent modules to produce an
028    executable, regardless of the license terms of these independent
029    modules, and to copy and distribute the resulting executable under
030    terms of your choice, provided that you also meet, for each linked
031    independent module, the terms and conditions of the license of that
032    module.  An independent module is a module which is not derived from
033    or based on this library.  If you modify this library, you may extend
034    this exception to your version of the library, but you are not
035    obligated to do so.  If you do not wish to do so, delete this
036    exception statement from your version. */
037    
038    
039    package java.awt;
040    
041    import java.awt.event.ActionEvent;
042    import java.awt.event.ActionListener;
043    import java.awt.event.ItemEvent;
044    import java.awt.event.ItemListener;
045    import java.awt.peer.ListPeer;
046    import java.util.EventListener;
047    import java.util.Vector;
048    
049    import javax.accessibility.Accessible;
050    import javax.accessibility.AccessibleContext;
051    import javax.accessibility.AccessibleRole;
052    import javax.accessibility.AccessibleSelection;
053    import javax.accessibility.AccessibleState;
054    import javax.accessibility.AccessibleStateSet;
055    
056    /**
057     * Class that implements a listbox widget
058     *
059     * @author Aaron M. Renn (arenn@urbanophile.com)
060     */
061    public 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