KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > swing > JMenu


1 /*
2  * @(#)JMenu.java 1.172 03/12/19
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package javax.swing;
9
10 import java.awt.AWTEvent JavaDoc;
11 import java.awt.Component JavaDoc;
12 import java.awt.ComponentOrientation JavaDoc;
13 import java.awt.Container JavaDoc;
14 import java.awt.Dimension JavaDoc;
15 import java.awt.Frame JavaDoc;
16 import java.awt.Graphics JavaDoc;
17 import java.awt.GraphicsConfiguration JavaDoc;
18 import java.awt.GraphicsDevice JavaDoc;
19 import java.awt.GraphicsEnvironment JavaDoc;
20 import java.awt.Insets JavaDoc;
21 import java.awt.Point JavaDoc;
22 import java.awt.Polygon JavaDoc;
23 import java.awt.Rectangle JavaDoc;
24 import java.awt.Toolkit JavaDoc;
25 import java.awt.event.*;
26 import java.beans.*;
27
28 import java.util.*;
29
30 import java.io.Serializable JavaDoc;
31 import java.io.ObjectOutputStream JavaDoc;
32 import java.io.ObjectInputStream JavaDoc;
33 import java.io.IOException JavaDoc;
34
35 import javax.swing.event.*;
36 import javax.swing.plaf.*;
37 import javax.swing.plaf.basic.*;
38 import javax.accessibility.*;
39
40 import java.lang.ref.WeakReference JavaDoc;
41
42 /**
43  * An implementation of a menu -- a popup window containing
44  * <code>JMenuItem</code>s that
45  * is displayed when the user selects an item on the <code>JMenuBar</code>.
46  * In addition to <code>JMenuItem</code>s, a <code>JMenu</code> can
47  * also contain <code>JSeparator</code>s.
48  * <p>
49  * In essence, a menu is a button with an associated <code>JPopupMenu</code>.
50  * When the "button" is pressed, the <code>JPopupMenu</code> appears. If the
51  * "button" is on the <code>JMenuBar</code>, the menu is a top-level window.
52  * If the "button" is another menu item, then the <code>JPopupMenu</code> is
53  * "pull-right" menu.
54  * <p>
55  * For information and examples of using menus see
56  * <a HREF="http://java.sun.com/doc/books/tutorial/uiswing/components/menu.html">How to Use Menus</a>,
57  * a section in <em>The Java Tutorial.</em>
58  * <p>
59  * <strong>Warning:</strong>
60  * Serialized objects of this class will not be compatible with
61  * future Swing releases. The current serialization support is
62  * appropriate for short term storage or RMI between applications running
63  * the same version of Swing. As of 1.4, support for long term storage
64  * of all JavaBeans<sup><font size="-2">TM</font></sup>
65  * has been added to the <code>java.beans</code> package.
66  * Please see {@link java.beans.XMLEncoder}.
67  *
68  * @beaninfo
69  * attribute: isContainer true
70  * description: A popup window containing menu items displayed in a menu bar.
71  *
72  * @version 1.172 12/19/03
73  * @author Georges Saab
74  * @author David Karlton
75  * @author Arnaud Weber
76  * @see JMenuItem
77  * @see JSeparator
78  * @see JMenuBar
79  * @see JPopupMenu
80  */

81 public class JMenu extends JMenuItem JavaDoc implements Accessible,MenuElement JavaDoc
82 {
83     /**
84      * @see #getUIClassID
85      * @see #readObject
86      */

87     private static final String JavaDoc uiClassID = "MenuUI";
88
89     /*
90      * The popup menu portion of the menu.
91      */

92     private JPopupMenu JavaDoc popupMenu;
93
94     /*
95      * The button's model listeners. Default is <code>null</code>.
96      */

97     private ChangeListener menuChangeListener = null;
98
99     /*
100      * Only one <code>MenuEvent</code> is needed for each menu since the
101      * event's only state is the source property. The source of events
102      * generated is always "this". Default is <code>null</code>.
103      */

104     private MenuEvent menuEvent = null;
105
106     /* Registry of listeners created for <code>Action-JMenuItem</code>
107      * linkage. This is needed so that references can
108      * be cleaned up at remove time to allow garbage collection
109      * Default is <code>null</code>.
110      */

111     private static Hashtable listenerRegistry = null;
112
113     /*
114      * Used by the look and feel (L&F) code to handle
115      * implementation specific menu behaviors.
116      */

117     private int delay;
118
119      /*
120       * Location of the popup component. Location is <code>null</code>
121       * if it was not customized by <code>setMenuLocation</code>
122       */

123      private Point JavaDoc customMenuLocation = null;
124
125     /* Diagnostic aids -- should be false for production builds. */
126     private static final boolean TRACE = false; // trace creates and disposes
127
private static final boolean VERBOSE = false; // show reuse hits/misses
128
private static final boolean DEBUG = false; // show bad params, misc.
129

130     /**
131      * Constructs a new <code>JMenu</code> with no text.
132      */

133     public JMenu() {
134         this("");
135     }
136
137     /**
138      * Constructs a new <code>JMenu</code> with the supplied string
139      * as its text.
140      *
141      * @param s the text for the menu label
142      */

143     public JMenu(String JavaDoc s) {
144     super(s);
145     }
146
147     /**
148      * Constructs a menu whose properties are taken from the
149      * <code>Action</code> supplied.
150      * @param a an <code>Action</code>
151      *
152      * @since 1.3
153      */

154     public JMenu(Action JavaDoc a) {
155         this();
156     setAction(a);
157     }
158
159     /**
160      * Constructs a new <code>JMenu</code> with the supplied string as
161      * its text and specified as a tear-off menu or not.
162      *
163      * @param s the text for the menu label
164      * @param b can the menu be torn off (not yet implemented)
165      */

166     public JMenu(String JavaDoc s, boolean b) {
167         this(s);
168     }
169
170
171     /**
172      * Overriden to do nothing. We want JMenu to be focusable, but
173      * <code>JMenuItem</code> doesn't want to be, thus we override this
174      * do nothing. We don't invoke <code>setFocusable(true)</code> after
175      * super's constructor has completed as this has the side effect that
176      * <code>JMenu</code> will be considered traversable via the
177      * keyboard, which we don't want. Making a Component traversable by
178      * the keyboard after invoking <code>setFocusable(true)</code> is OK,
179      * as <code>setFocusable</code> is new API
180      * and is speced as such, but internally we don't want to use it like
181      * this else we change the keyboard traversability.
182      */

183     void initFocusability() {
184     }
185
186     /**
187      * Resets the UI property with a value from the current look and feel.
188      *
189      * @see JComponent#updateUI
190      */

191     public void updateUI() {
192         setUI((MenuItemUI)UIManager.getUI(this));
193
194         if ( popupMenu != null )
195           {
196             popupMenu.setUI((PopupMenuUI)UIManager.getUI(popupMenu));
197           }
198
199     }
200
201
202     /**
203      * Returns the name of the L&F class that renders this component.
204      *
205      * @return the string "MenuUI"
206      * @see JComponent#getUIClassID
207      * @see UIDefaults#getUI
208      */

209     public String JavaDoc getUIClassID() {
210         return uiClassID;
211     }
212
213     // public void repaint(long tm, int x, int y, int width, int height) {
214
// Thread.currentThread().dumpStack();
215
// super.repaint(tm,x,y,width,height);
216
// }
217

218     /**
219      * Sets the data model for the "menu button" -- the label
220      * that the user clicks to open or close the menu.
221      *
222      * @param newModel the <code>ButtonModel</code>
223      * @see #getModel
224      * @beaninfo
225      * description: The menu's model
226      * bound: true
227      * expert: true
228      * hidden: true
229      */

230     public void setModel(ButtonModel JavaDoc newModel) {
231         ButtonModel JavaDoc oldModel = getModel();
232
233         super.setModel(newModel);
234
235         if (oldModel != null && menuChangeListener != null) {
236             oldModel.removeChangeListener(menuChangeListener);
237             menuChangeListener = null;
238         }
239         
240         model = newModel;
241         
242         if (newModel != null) {
243             menuChangeListener = createMenuChangeListener();
244             newModel.addChangeListener(menuChangeListener);
245         }
246     }
247
248     /**
249      * Returns true if the menu is currently selected (highlighted).
250      *
251      * @return true if the menu is selected, else false
252      */

253     public boolean isSelected() {
254         return getModel().isSelected();
255     }
256
257     /**
258      * Sets the selection status of the menu.
259      *
260      * @param b true to select (highlight) the menu; false to de-select
261      * the menu
262      * @beaninfo
263      * description: When the menu is selected, its popup child is shown.
264      * expert: true
265      * hidden: true
266      */

267     public void setSelected(boolean b) {
268         ButtonModel JavaDoc model = getModel();
269         boolean oldValue = model.isSelected();
270
271         // TIGER - 4840653
272
// Removed code which fired an AccessibleState.SELECTED
273
// PropertyChangeEvent since this resulted in two
274
// identical events being fired since
275
// AbstractButton.fireItemStateChanged also fires the
276
// same event. This caused screen readers to speak the
277
// name of the item twice.
278

279         if (b != model.isSelected()) {
280             getModel().setSelected(b);
281         }
282     }
283
284     /**
285      * Returns true if the menu's popup window is visible.
286      *
287      * @return true if the menu is visible, else false
288      */

289     public boolean isPopupMenuVisible() {
290         ensurePopupMenuCreated();
291         return popupMenu.isVisible();
292     }
293
294     /**
295      * Sets the visibility of the menu's popup. If the menu is
296      * not enabled, this method will have no effect.
297      *
298      * @param b a boolean value -- true to make the menu visible,
299      * false to hide it
300      * @beaninfo
301      * description: The popup menu's visibility
302      * expert: true
303      * hidden: true
304      */

305     public void setPopupMenuVisible(boolean b) {
306     if (DEBUG) {
307         System.out.println("in JMenu.setPopupMenuVisible " + b);
308         // Thread.dumpStack();
309
}
310
311     boolean isVisible = isPopupMenuVisible();
312         if (b != isVisible && (isEnabled() || !b)) {
313             ensurePopupMenuCreated();
314             if ((b==true) && isShowing()) {
315                 // Set location of popupMenu (pulldown or pullright)
316
Point JavaDoc p = getCustomMenuLocation();
317         if (p == null) {
318             p = getPopupMenuOrigin();
319         }
320         getPopupMenu().show(this, p.x, p.y);
321             } else {
322                 getPopupMenu().setVisible(false);
323             }
324         }
325
326     }
327
328     /**
329      * Computes the origin for the <code>JMenu</code>'s popup menu.
330      * This method uses Look and Feel properties named
331      * <code>Menu.menuPopupOffsetX</code>,
332      * <code>Menu.menuPopupOffsetY</code>,
333      * <code>Menu.submenuPopupOffsetX</code>, and
334      * <code>Menu.submenuPopupOffsetY</code>
335      * to adjust the exact location of popup.
336      *
337      * @return a <code>Point</code> in the coordinate space of the
338      * menu which should be used as the origin
339      * of the <code>JMenu</code>'s popup menu
340      *
341      * @since 1.3
342      */

343     protected Point JavaDoc getPopupMenuOrigin() {
344     int x = 0;
345     int y = 0;
346     JPopupMenu JavaDoc pm = getPopupMenu();
347     // Figure out the sizes needed to caclulate the menu position
348
Dimension JavaDoc s = getSize();
349     Dimension JavaDoc pmSize = pm.getSize();
350     // For the first time the menu is popped up,
351
// the size has not yet been initiated
352
if (pmSize.width==0) {
353         pmSize = pm.getPreferredSize();
354     }
355     Point JavaDoc position = getLocationOnScreen();
356         Toolkit JavaDoc toolkit = Toolkit.getDefaultToolkit();
357         GraphicsConfiguration JavaDoc gc = getGraphicsConfiguration();
358         Rectangle JavaDoc screenBounds = new Rectangle JavaDoc(toolkit.getScreenSize());
359         GraphicsEnvironment JavaDoc ge =
360             GraphicsEnvironment.getLocalGraphicsEnvironment();
361         GraphicsDevice JavaDoc[] gd = ge.getScreenDevices();
362         for(int i = 0; i < gd.length; i++) {
363             if(gd[i].getType() == GraphicsDevice.TYPE_RASTER_SCREEN) {
364                 GraphicsConfiguration JavaDoc dgc =
365                     gd[i].getDefaultConfiguration();
366                 if(dgc.getBounds().contains(position)) {
367                     gc = dgc;
368                     break;
369                 }
370             }
371         }
372
373
374         if (gc != null) {
375             screenBounds = gc.getBounds();
376             // take screen insets (e.g. taskbar) into account
377
Insets JavaDoc screenInsets = toolkit.getScreenInsets(gc);
378
379             screenBounds.width -=
380                         Math.abs(screenInsets.left + screenInsets.right);
381             screenBounds.height -=
382                         Math.abs(screenInsets.top + screenInsets.bottom);
383             position.x -= Math.abs(screenInsets.left);
384             position.y -= Math.abs(screenInsets.top);
385         }
386     
387     Container JavaDoc parent = getParent();
388     if (parent instanceof JPopupMenu JavaDoc) {
389         // We are a submenu (pull-right)
390
int xOffset = UIManager.getInt("Menu.submenuPopupOffsetX");
391             int yOffset = UIManager.getInt("Menu.submenuPopupOffsetY");
392
393             if( SwingUtilities.isLeftToRight(this) ) {
394                 // First determine x:
395
x = s.width + xOffset; // Prefer placement to the right
396
if (position.x + x + pmSize.width >= screenBounds.width
397                                                      + screenBounds.x &&
398                     // popup doesn't fit - place it wherever there's more room
399
screenBounds.width - s.width < 2*(position.x
400                                                     - screenBounds.x)) {
401
402                     x = 0 - xOffset - pmSize.width;
403                 }
404             } else {
405                 // First determine x:
406
x = 0 - xOffset - pmSize.width; // Prefer placement to the left
407
if (position.x + x < screenBounds.x &&
408                     // popup doesn't fit - place it wherever there's more room
409
screenBounds.width - s.width > 2*(position.x -
410                                                     screenBounds.x)) {
411
412                     x = s.width + xOffset;
413                 }
414             }
415             // Then the y:
416
y = yOffset; // Prefer dropping down
417
if (position.y + y + pmSize.height >= screenBounds.height
418                                                   + screenBounds.y &&
419                 // popup doesn't fit - place it wherever there's more room
420
screenBounds.height - s.height < 2*(position.y
421                                                   - screenBounds.y)) {
422
423                 y = s.height - yOffset - pmSize.height;
424             }
425     } else {
426         // We are a toplevel menu (pull-down)
427
int xOffset = UIManager.getInt("Menu.menuPopupOffsetX");
428             int yOffset = UIManager.getInt("Menu.menuPopupOffsetY");
429
430             if( SwingUtilities.isLeftToRight(this) ) {
431                 // First determine the x:
432
x = xOffset; // Extend to the right
433
if (position.x + x + pmSize.width >= screenBounds.width
434                                                      + screenBounds.x &&
435                     // popup doesn't fit - place it wherever there's more room
436
screenBounds.width - s.width < 2*(position.x
437                                                     - screenBounds.x)) {
438
439                     x = s.width - xOffset - pmSize.width;
440                 }
441             } else {
442                 // First determine the x:
443
x = s.width - xOffset - pmSize.width; // Extend to the left
444
if (position.x + x < screenBounds.x &&
445                     // popup doesn't fit - place it wherever there's more room
446
screenBounds.width - s.width > 2*(position.x
447                                                     - screenBounds.x)) {
448
449                     x = xOffset;
450                 }
451             }
452         // Then the y:
453
y = s.height + yOffset; // Prefer dropping down
454
if (position.y + y + pmSize.height >= screenBounds.height &&
455                 // popup doesn't fit - place it wherever there's more room
456
screenBounds.height - s.height < 2*(position.y
457                                                   - screenBounds.y)) {
458
459         y = 0 - yOffset - pmSize.height; // Otherwise drop 'up'
460
}
461     }
462     return new Point JavaDoc(x,y);
463     }
464
465
466     /**
467      * Returns the suggested delay, in milliseconds, before submenus
468      * are popped up or down.
469      * Each look and feel (L&F) may determine its own policy for
470      * observing the <code>delay</code> property.
471      * In most cases, the delay is not observed for top level menus
472      * or while dragging. The default for <code>delay</code> is 0.
473      * This method is a property of the look and feel code and is used
474      * to manage the idiosyncracies of the various UI implementations.
475      *
476      *
477      * @return the <code>delay</code> property
478      */

479     public int getDelay() {
480         return delay;
481     }
482     
483     /**
484      * Sets the suggested delay before the menu's <code>PopupMenu</code>
485      * is popped up or down. Each look and feel (L&F) may determine
486      * it's own policy for observing the delay property. In most cases,
487      * the delay is not observed for top level menus or while dragging.
488      * This method is a property of the look and feel code and is used
489      * to manage the idiosyncracies of the various UI implementations.
490      *
491      * @param d the number of milliseconds to delay
492      * @exception IllegalArgumentException if <code>d</code>
493      * is less than 0
494      * @beaninfo
495      * description: The delay between menu selection and making the popup menu visible
496      * expert: true
497      */

498     public void setDelay(int d) {
499         if (d < 0)
500             throw new IllegalArgumentException JavaDoc("Delay must be a positive integer");
501
502         delay = d;
503     }
504
505     /**
506      * The window-closing listener for the popup.
507      *
508      * @see WinListener
509      */

510     protected WinListener popupListener;
511
512     private void ensurePopupMenuCreated() {
513         if (popupMenu == null) {
514             final JMenu JavaDoc thisMenu = this;
515             this.popupMenu = new JPopupMenu JavaDoc();
516             popupMenu.setInvoker(this);
517             popupListener = createWinListener(popupMenu);
518         }
519     }
520
521     /*
522      * Return the customized location of the popup component.
523      */

524     private Point JavaDoc getCustomMenuLocation() {
525     return customMenuLocation;
526     }
527     
528     /**
529      * Sets the location of the popup component.
530      *
531      * @param x the x coordinate of the popup's new position
532      * @param y the y coordinate of the popup's new position
533      */

534     public void setMenuLocation(int x, int y) {
535     customMenuLocation = new Point JavaDoc(x, y);
536         if (popupMenu != null)
537         popupMenu.setLocation(x, y);
538     }
539
540     /**
541      * Appends a menu item to the end of this menu.
542      * Returns the menu item added.
543      *
544      * @param menuItem the <code>JMenuitem</code> to be added
545      * @return the <code>JMenuItem</code> added
546      */

547     public JMenuItem JavaDoc add(JMenuItem JavaDoc menuItem) {
548         AccessibleContext ac = menuItem.getAccessibleContext();
549         ac.setAccessibleParent(this);
550         ensurePopupMenuCreated();
551         return popupMenu.add(menuItem);
552     }
553
554     /**
555      * Appends a component to the end of this menu.
556      * Returns the component added.
557      *
558      * @param c the <code>Component</code> to add
559      * @return the <code>Component</code> added
560      */

561     public Component JavaDoc add(Component JavaDoc c) {
562     if (c instanceof JComponent JavaDoc) {
563         AccessibleContext ac = ((JComponent JavaDoc) c).getAccessibleContext();
564         if (ac != null) {
565         ac.setAccessibleParent(this);
566         }
567     }
568         ensurePopupMenuCreated();
569         popupMenu.add(c);
570         return c;
571     }
572
573     /**
574      * Adds the specified component to this container at the given
575      * position. If <code>index</code> equals -1, the component will
576      * be appended to the end.
577      * @param c the <code>Component</code> to add
578      * @param index the position at which to insert the component
579      * @return the <code>Component</code> added
580      * @see #remove
581      * @see java.awt.Container#add(Component, int)
582      */

583     public Component JavaDoc add(Component JavaDoc c, int index) {
584     if (c instanceof JComponent JavaDoc) {
585         AccessibleContext ac = ((JComponent JavaDoc) c).getAccessibleContext();
586         if (ac != null) {
587         ac.setAccessibleParent(this);
588         }
589     }
590         ensurePopupMenuCreated();
591         popupMenu.add(c, index);
592         return c;
593     }
594
595     /**
596      * Creates a new menu item with the specified text and appends
597      * it to the end of this menu.
598      *
599      * @param s the string for the menu item to be added
600      */

601     public JMenuItem JavaDoc add(String JavaDoc s) {
602         return add(new JMenuItem JavaDoc(s));
603     }
604
605     /**
606      * Creates a new menu item attached to the specified
607      * <code>Action</code> object and appends it to the end of this menu.
608      * As of 1.3, this is no longer the preferred method for adding
609      * <code>Actions</code> to
610      * a container. Instead it is recommended to configure a control with
611      * an action using <code>setAction</code>,
612      * and then add that control directly
613      * to the <code>Container</code>.
614      *
615      * @param a the <code>Action</code> for the menu item to be added
616      * @see Action
617      */

618     public JMenuItem JavaDoc add(Action JavaDoc a) {
619     JMenuItem JavaDoc mi = createActionComponent(a);
620         mi.setAction(a);
621         add(mi);
622         return mi;
623     }
624     
625     /**
626      * Factory method which creates the <code>JMenuItem</code> for
627      * <code>Action</code>s added to the <code>JMenu</code>.
628      * As of 1.3, this is no
629      * longer the preferred method. Instead it is recommended to configure
630      * a control with an action using <code>setAction</code>,
631      * and then adding that
632      * control directly to the <code>Container</code>.
633      *
634      * @param a the <code>Action</code> for the menu item to be added
635      * @return the new menu item
636      * @see Action
637      *
638      * @since 1.3
639      */

640     protected JMenuItem JavaDoc createActionComponent(Action JavaDoc a) {
641         JMenuItem JavaDoc mi = new JMenuItem JavaDoc((String JavaDoc)a.getValue(Action.NAME),
642                                      (Icon JavaDoc)a.getValue(Action.SMALL_ICON)){
643         protected PropertyChangeListener createActionPropertyChangeListener(Action JavaDoc a) {
644         PropertyChangeListener pcl = createActionChangeListener(this);
645         if (pcl == null) {
646             pcl = super.createActionPropertyChangeListener(a);
647         }
648         return pcl;
649         }
650     };
651         mi.setHorizontalTextPosition(JButton.TRAILING);
652         mi.setVerticalTextPosition(JButton.CENTER);
653         mi.setEnabled(a.isEnabled());
654     return mi;
655     }
656
657     /**
658      * Returns a properly configured <code>PropertyChangeListener</code>
659      * which updates the control as changes to the <code>Action</code> occur.
660      * As of 1.3, this is no longer the preferred method for adding
661      * <code>Action</code>s to a <code>Container</code>.
662      * Instead it is recommended to configure a control with
663      * an action using <code>setAction</code>, and then add that
664      * control directly
665      * to the <code>Container</code>.
666      */

667     protected PropertyChangeListener createActionChangeListener(JMenuItem JavaDoc b) {
668         return new ActionChangedListener(b);
669     }
670
671     private class ActionChangedListener implements PropertyChangeListener {
672         WeakReference JavaDoc menuItem;
673         
674         ActionChangedListener(JMenuItem JavaDoc mi) {
675             super();
676         setTarget(mi);
677         }
678         public void propertyChange(PropertyChangeEvent e) {
679             String JavaDoc propertyName = e.getPropertyName();
680             JMenuItem JavaDoc mi = (JMenuItem JavaDoc)getTarget();
681             if (mi == null) {
682                 Action JavaDoc action = (Action JavaDoc)e.getSource();
683                 action.removePropertyChangeListener(this);
684             } else {
685                 if (propertyName.equals(Action.NAME)) {
686                     String JavaDoc text = (String JavaDoc) e.getNewValue();
687                     mi.setText(text);
688                 } else if (propertyName.equals("enabled")) {
689                     Boolean JavaDoc enabledState = (Boolean JavaDoc) e.getNewValue();
690                     mi.setEnabled(enabledState.booleanValue());
691                 } else if (propertyName.equals(Action.SMALL_ICON)) {
692                     Icon JavaDoc icon = (Icon JavaDoc) e.getNewValue();
693                     mi.setIcon(icon);
694                     mi.invalidate();
695                     mi.repaint();
696                 } else if (propertyName.equals(Action.ACTION_COMMAND_KEY)) {
697                     mi.setActionCommand((String JavaDoc)e.getNewValue());
698                 }
699             }
700         }
701     public void setTarget(JMenuItem JavaDoc b) {
702         menuItem = new WeakReference JavaDoc(b);
703     }
704         public JMenuItem JavaDoc getTarget() {
705             return (JMenuItem JavaDoc)menuItem.get();
706         }
707     }
708
709     /**
710      * Appends a new separator to the end of the menu.
711      */

712     public void addSeparator()
713     {
714         ensurePopupMenuCreated();
715         popupMenu.addSeparator();
716     }
717
718     /**
719      * Inserts a new menu item with the specified text at a
720      * given position.
721      *
722      * @param s the text for the menu item to add
723      * @param pos an integer specifying the position at which to add the
724      * new menu item
725      * @exception IllegalArgumentException when the value of
726      * <code>pos</code> < 0
727      */

728     public void insert(String JavaDoc s, int pos) {
729         if (pos < 0) {
730             throw new IllegalArgumentException JavaDoc("index less than zero.");
731         }
732
733         ensurePopupMenuCreated();
734         popupMenu.insert(new JMenuItem JavaDoc(s), pos);
735     }
736
737     /**
738      * Inserts the specified <code>JMenuitem</code> at a given position.
739      *
740      * @param mi the <code>JMenuitem</code> to add
741      * @param pos an integer specifying the position at which to add the
742      * new <code>JMenuitem</code>
743      * @return the new menu item
744      * @exception IllegalArgumentException if the value of
745      * <code>pos</code> < 0
746      */

747     public JMenuItem JavaDoc insert(JMenuItem JavaDoc mi, int pos) {
748         if (pos < 0) {
749             throw new IllegalArgumentException JavaDoc("index less than zero.");
750         }
751         AccessibleContext ac = mi.getAccessibleContext();
752         ac.setAccessibleParent(this);
753         ensurePopupMenuCreated();
754         popupMenu.insert(mi, pos);
755         return mi;
756     }
757
758     /**
759      * Inserts a new menu item attached to the specified <code>Action</code>
760      * object at a given position.
761      *
762      * @param a the <code>Action</code> object for the menu item to add
763      * @param pos an integer specifying the position at which to add the
764      * new menu item
765      * @exception IllegalArgumentException if the value of
766      * <code>pos</code> < 0
767      */

768     public JMenuItem JavaDoc insert(Action JavaDoc a, int pos) {
769         if (pos < 0) {
770             throw new IllegalArgumentException JavaDoc("index less than zero.");
771         }
772
773         ensurePopupMenuCreated();
774         JMenuItem JavaDoc mi = new JMenuItem JavaDoc((String JavaDoc)a.getValue(Action.NAME),
775                      (Icon JavaDoc)a.getValue(Action.SMALL_ICON));
776         mi.setHorizontalTextPosition(JButton.TRAILING);
777         mi.setVerticalTextPosition(JButton.CENTER);
778         mi.setEnabled(a.isEnabled());
779         mi.setAction(a);
780         popupMenu.insert(mi, pos);
781         return mi;
782     }
783
784     /**
785      * Inserts a separator at the specified position.
786      *
787      * @param index an integer specifying the position at which to
788      * insert the menu separator
789      * @exception IllegalArgumentException if the value of
790      * <code>index</code> < 0
791      */

792     public void insertSeparator(int index) {
793         if (index < 0) {
794             throw new IllegalArgumentException JavaDoc("index less than zero.");
795         }
796
797         ensurePopupMenuCreated();
798         popupMenu.insert( new JPopupMenu.Separator JavaDoc(), index );
799     }
800
801     /**
802      * Returns the <code>JMenuItem</code> at the specified position.
803      * If the component at <code>pos</code> is not a menu item,
804      * <code>null</code> is returned.
805      * This method is included for AWT compatibility.
806      *
807      * @param pos an integer specifying the position
808      * @exception IllegalArgumentException if the value of
809      * <code>pos</code> < 0
810      * @return the menu item at the specified position; or <code>null</code>
811      * if the item as the specified position is not a menu item
812      */

813     public JMenuItem JavaDoc getItem(int pos) {
814         if (pos < 0) {
815             throw new IllegalArgumentException JavaDoc("index less than zero.");
816         }
817
818         Component JavaDoc c = getMenuComponent(pos);
819         if (c instanceof JMenuItem JavaDoc) {
820             JMenuItem JavaDoc mi = (JMenuItem JavaDoc) c;
821             return mi;
822         }
823
824         // 4173633
825
return null;
826     }
827
828     /**
829      * Returns the number of items on the menu, including separators.
830      * This method is included for AWT compatibility.
831      *
832      * @return an integer equal to the number of items on the menu
833      * @see #getMenuComponentCount
834      */

835     public int getItemCount() {
836         return getMenuComponentCount();
837     }
838
839     /**
840      * Returns true if the menu can be torn off. This method is not
841      * yet implemented.
842      *
843      * @return true if the menu can be torn off, else false
844      * @exception Error if invoked -- this method is not yet implemented
845      */

846     public boolean isTearOff() {
847         throw new Error JavaDoc("boolean isTearOff() {} not yet implemented");
848     }
849
850     /**
851      * Removes the specified menu item from this menu. If there is no
852      * popup menu, this method will have no effect.
853      *
854      * @param item the <code>JMenuItem</code> to be removed from the menu
855      */

856     public void remove(JMenuItem JavaDoc item) {
857         if (popupMenu != null)
858         popupMenu.remove(item);
859     }
860
861     /**
862      * Removes the menu item at the specified index from this menu.
863      *
864      * @param pos the position of the item to be removed
865      * @exception IllegalArgumentException if the value of
866      * <code>pos</code> < 0, or if <code>pos</code>
867      * is greater than the number of menu items
868      */

869     public void remove(int pos) {
870         if (pos < 0) {
871             throw new IllegalArgumentException JavaDoc("index less than zero.");
872         }
873         if (pos > getItemCount()) {
874             throw new IllegalArgumentException JavaDoc("index greater than the number of items.");
875         }
876         if (popupMenu != null)
877         popupMenu.remove(pos);
878     }
879
880     /**
881      * Removes the component <code>c</code> from this menu.
882      *
883      * @param c the component to be removed
884      */

885     public void remove(Component JavaDoc c) {
886         if (popupMenu != null)
887         popupMenu.remove(c);
888     }
889
890     /**