1 /* Menu.java -- A Java AWT Menu
2    Copyright (C) 1999, 2002, 2004, 2006 Free Software Foundation, Inc.
3 
4 This file is part of GNU Classpath.
5 
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)
9 any later version.
10 
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.
15 
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., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20 
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
24 combination.
25 
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. */
37 
38 
39 package java.awt;
40 
41 import java.awt.peer.MenuPeer;
42 import java.io.Serializable;
43 import java.util.Enumeration;
44 import java.util.Vector;
45 
46 import javax.accessibility.AccessibleContext;
47 import javax.accessibility.AccessibleRole;
48 
49 /**
50   * This class represents a pull down or tear off menu in Java's AWT.
51   *
52   * @author Aaron M. Renn (arenn@urbanophile.com)
53   */
54 public class Menu extends MenuItem implements MenuContainer, Serializable
55 {
56 
57   /**
58    * The number used to generate the name returned by getName.
59    */
60   private static transient long next_menu_number;
61 
62   // Serialization Constant
63   private static final long serialVersionUID = -8809584163345499784L;
64 
65   /**
66     * @serial The actual items in the menu
67     */
68   private Vector items = new Vector();
69 
70   /**
71    * @serial Flag indicating whether or not this menu is a tear off
72    */
73   private boolean tearOff;
74 
75   /**
76    * @serial Indicates whether or not this is a help menu.
77    */
78   private boolean isHelpMenu;
79 
80   /*
81    * @serial Unused in this implementation, but present in Sun's
82    * serialization spec.  Value obtained via reflection.
83    */
84   private int menuSerializedDataVersion = 1;
85 
86   static final transient String separatorLabel = "-";
87 
88   /**
89    * Initializes a new instance of <code>Menu</code> with no label and that
90    * is not a tearoff;
91    *
92    * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true.
93    */
Menu()94   public Menu()
95   {
96   }
97 
98   /**
99    * 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    */
Menu(String label)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    */
Menu(String label, boolean isTearOff)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    */
isTearOff()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    */
getItemCount()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    */
countItems()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    */
getItem(int index)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    */
add(MenuItem item)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    */
add(String label)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    */
insert(MenuItem item, int index)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    */
insert(String label, int index)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    */
addSeparator()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    */
insertSeparator(int index)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    */
remove(int index)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    */
remove(MenuComponent item)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    */
removeAll()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    */
addNotify()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    */
removeNotify()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    */
paramString()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 
AccessibleAWTMenu()405     protected AccessibleAWTMenu()
406     {
407     }
408 
getAccessibleRole()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    */
getAccessibleContext()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    */
generateName()434   String generateName()
435   {
436     return "menu" + getUniqueLong();
437   }
438 
getUniqueLong()439   private static synchronized long getUniqueLong()
440   {
441     return next_menu_number++;
442   }
443 
444 } // class Menu
445