001    /* Menu.java -- A Java AWT Menu
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.peer.MenuPeer;
042    import java.io.Serializable;
043    import java.util.Enumeration;
044    import java.util.Vector;
045    
046    import javax.accessibility.AccessibleContext;
047    import javax.accessibility.AccessibleRole;
048    
049    /**
050      * This class represents a pull down or tear off menu in Java's AWT.
051      *
052      * @author Aaron M. Renn (arenn@urbanophile.com)
053      */
054    public class Menu extends MenuItem implements MenuContainer, Serializable
055    {
056    
057      /**
058       * The number used to generate the name returned by getName.
059       */
060      private static transient long next_menu_number;
061    
062      // Serialization Constant
063      private static final long serialVersionUID = -8809584163345499784L;
064    
065      /**
066        * @serial The actual items in the menu
067        */
068      private Vector items = new Vector();
069    
070      /**
071       * @serial Flag indicating whether or not this menu is a tear off
072       */
073      private boolean tearOff;
074    
075      /**
076       * @serial Indicates whether or not this is a help menu.
077       */
078      private boolean isHelpMenu;
079    
080      /*
081       * @serial Unused in this implementation, but present in Sun's
082       * serialization spec.  Value obtained via reflection.
083       */
084      private int menuSerializedDataVersion = 1;
085    
086      static final transient String separatorLabel = "-";
087    
088      /**
089       * Initializes a new instance of <code>Menu</code> with no label and that
090       * is not a tearoff;
091       *
092       * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true.
093       */
094      public Menu()
095      {
096      }
097    
098      /**
099       * Initializes a new instance of <code>Menu</code> that is not a tearoff and
100       * that has the specified label.
101       *
102       * @param label The menu label.
103       *
104       * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true.
105       */
106      public Menu(String label)
107      {
108        this(label, false);
109      }
110    
111      /**
112       * Initializes a new instance of <code>Menu</code> with the specified
113       * label and tearoff status.
114       *
115       * @param label The label for this menu
116       * @param isTearOff <code>true</code> if this menu is a tear off menu,
117       * <code>false</code> otherwise.
118       *
119       * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true.
120       */
121      public Menu(String label, boolean isTearOff)
122      {
123        super(label);
124    
125        tearOff = isTearOff;
126    
127        if (label.equals("Help"))
128          isHelpMenu = true;
129    
130        if (GraphicsEnvironment.isHeadless())
131          throw new HeadlessException();
132      }
133    
134      /**
135       * Tests whether or not this menu is a tearoff.
136       *
137       * @return <code>true</code> if this menu is a tearoff, <code>false</code>
138       * otherwise.
139       */
140      public boolean isTearOff()
141      {
142        return(tearOff);
143      }
144    
145      /**
146       * Returns the number of items in this menu.
147       *
148       * @return The number of items in this menu.
149       */
150      public int getItemCount()
151      {
152        return countItems();
153      }
154    
155      /**
156       * Returns the number of items in this menu.
157       *
158       * @return The number of items in this menu.
159       *
160       * @deprecated As of JDK 1.1, replaced by getItemCount().
161       */
162      public int countItems()
163      {
164        return items.size();
165      }
166    
167      /**
168       * Returns the item at the specified index.
169       *
170       * @param index  the item index.
171       *
172       * @return The item at the specified index.
173       *
174       * @exception ArrayIndexOutOfBoundsException If the index value is not valid.
175       */
176      public MenuItem getItem(int index)
177      {
178        return((MenuItem) items.elementAt(index));
179      }
180    
181      /**
182       * Adds the specified item to this menu.  If it was previously part of
183       * another menu, it is first removed from that menu.
184       *
185       * @param item The new item to add.
186       *
187       * @return The item that was added.
188       */
189      public MenuItem add(MenuItem item)
190      {
191        MenuContainer parent = item.getParent();
192        if (parent != null)
193          parent.remove(item);
194    
195        items.addElement(item);
196        item.setParent(this);
197    
198        if (peer != null)
199          {
200            item.addNotify();
201            MenuPeer mp = (MenuPeer) peer;
202            mp.addItem(item);
203          }
204    
205        return item;
206      }
207    
208      /**
209       * Add an item with the specified label to this menu.
210       *
211       * @param label The label of the menu item to add.
212       */
213      public void add(String label)
214      {
215        add(new MenuItem(label));
216      }
217    
218      /**
219       * Inserts the specified menu item into this menu at the specified index.  If
220       * the index is greater than or equal to the number of items already in the
221       * menu, the new item is added as the last item in the menu.
222       *
223       * @param item The menu item to add (<code>null</code> not permitted).
224       * @param index The index of the menu item (>= 0).
225       *
226       * @throws IllegalArgumentException if the index is less than zero.
227       * @throws NullPointerException if <code>item</code> is <code>null</code>.
228       */
229      public void insert(MenuItem item, int index)
230      {
231        if (index < 0)
232          throw new IllegalArgumentException("Index is less than zero");
233    
234        int count = getItemCount();
235    
236        if (index >= count)
237          add(item);
238        else
239          {
240            MenuContainer parent = item.getParent();
241            if (parent != null)
242              parent.remove(item);
243    
244            items.insertElementAt(item, index);
245            item.setParent(this);
246    
247            MenuPeer peer = (MenuPeer) getPeer();
248            if (peer == null)
249              return;
250    
251            for (int i = count - 1; i >= index; i--)
252              peer.delItem(i);
253    
254            item.addNotify();
255            peer.addItem(item);
256    
257            // bear in mind that count is the number of items *before* the new
258            // item was added
259            for (int i = index + 1; i <= count; i++)
260              peer.addItem((MenuItem) items.elementAt(i));
261          }
262    
263      }
264    
265      /**
266       * Inserts an item with the specified label into this menu at the specified
267       * index.  If the index is greater than or equal to the number of items
268       * already in the menu, the new item is added as the last item in the menu.
269       *
270       * @param label The label of the item to add.
271       * @param index The index of the menu item (>= 0).
272       *
273       * @throws IllegalArgumentException If the index is less than zero.
274       */
275      public void insert(String label, int index)
276      {
277        insert(new MenuItem(label), index);
278      }
279    
280      /**
281       * Adds a separator bar at the current menu location.
282       */
283      public void addSeparator()
284      {
285        add(new MenuItem(separatorLabel));
286      }
287    
288      /**
289       * Inserts a separator bar at the specified index value.
290       *
291       * @param index The index at which to insert a separator bar.
292       *
293       * @exception IllegalArgumentException If the index is less than zero.
294       * @exception ArrayIndexOutOfBoundsException If the index is otherwise invalid.
295       */
296      public void insertSeparator(int index)
297      {
298        insert(new MenuItem(separatorLabel), index);
299      }
300    
301      /**
302       * Deletes the item at the specified index from this menu.
303       *
304       * @param index The index of the item to remove.
305       *
306       * @exception ArrayIndexOutOfBoundsException If the index is otherwise invalid.
307       */
308      public synchronized void remove(int index)
309      {
310        MenuItem item = (MenuItem) items.remove(index);
311    
312        MenuPeer mp = (MenuPeer) getPeer();
313        if (mp != null)
314          {
315            mp.delItem(index);
316            item.removeNotify();
317          }
318        item.setParent(null);
319      }
320    
321      /**
322       * Removes the specifed item from the menu.  If the specified component
323       * does not exist, this method does nothing.
324       *
325       * @param item The component to remove.
326       */
327      public void remove(MenuComponent item)
328      {
329        int index = items.indexOf(item);
330        if (index == -1)
331          return;
332    
333        remove(index);
334      }
335    
336      /**
337       * Removes all the elements from this menu.
338       */
339      public synchronized void removeAll()
340      {
341        int count = getItemCount();
342        for(int i = 0; i < count; i++)
343          {
344            // We must always remove item 0.
345            remove(0);
346          }
347      }
348    
349      /**
350       * Creates the native peer for this object.
351       */
352      public void addNotify()
353      {
354        MenuPeer peer = (MenuPeer) getPeer();
355        if (peer == null)
356          {
357            peer = getToolkit().createMenu(this);
358            setPeer(peer);
359          }
360    
361        Enumeration e = items.elements();
362        while (e.hasMoreElements())
363        {
364          MenuItem mi = (MenuItem)e.nextElement();
365          mi.addNotify();
366          peer.addItem(mi);
367        }
368    
369        super.addNotify();
370      }
371    
372      /**
373       * Destroys the native peer for this object.
374       */
375      public void removeNotify()
376      {
377        Enumeration e = items.elements();
378        while (e.hasMoreElements())
379        {
380          MenuItem mi = (MenuItem) e.nextElement();
381          mi.removeNotify();
382        }
383        super.removeNotify();
384      }
385    
386      /**
387       * Returns a debugging string for this menu.
388       *
389       * @return A debugging string for this menu.
390       */
391      public String paramString()
392      {
393        return (",tearOff=" + tearOff + ",isHelpMenu=" + isHelpMenu
394                + super.paramString());
395      }
396    
397      /**
398       * Basic Accessibility class for Menu.  Details get provided in derived
399       * classes.
400       */
401      protected class AccessibleAWTMenu extends AccessibleAWTMenuItem
402      {
403        private static final long serialVersionUID = 5228160894980069094L;
404    
405        protected AccessibleAWTMenu()
406        {
407        }
408    
409        public AccessibleRole getAccessibleRole()
410        {
411          return AccessibleRole.MENU;
412        }
413      }
414    
415      /**
416       * Gets the AccessibleContext associated with this <code>Menu</code>.
417       * The context is created, if necessary.
418       *
419       * @return the associated context
420       */
421      public AccessibleContext getAccessibleContext()
422      {
423        /* Create the context if this is the first request */
424        if (accessibleContext == null)
425          accessibleContext = new AccessibleAWTMenu();
426        return accessibleContext;
427      }
428    
429      /**
430       * Generate a unique name for this <code>Menu</code>.
431       *
432       * @return A unique name for this <code>Menu</code>.
433       */
434      String generateName()
435      {
436        return "menu" + getUniqueLong();
437      }
438    
439      private static synchronized long getUniqueLong()
440      {
441        return next_menu_number++;
442      }
443    
444    } // class Menu