jdk/src/share/classes/java/awt/Menu.java
changeset 2 90ce3da70b43
child 5506 202f599c92aa
equal deleted inserted replaced
0:fd16c54261b3 2:90ce3da70b43
       
     1 /*
       
     2  * Copyright 1995-2006 Sun Microsystems, Inc.  All Rights Reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any questions.
       
    24  */
       
    25 package java.awt;
       
    26 
       
    27 import java.io.IOException;
       
    28 import java.io.ObjectInputStream;
       
    29 import java.util.Vector;
       
    30 import java.util.Enumeration;
       
    31 import java.awt.peer.MenuPeer;
       
    32 import java.awt.event.KeyEvent;
       
    33 import javax.accessibility.*;
       
    34 
       
    35 /**
       
    36  * A <code>Menu</code> object is a pull-down menu component
       
    37  * that is deployed from a menu bar.
       
    38  * <p>
       
    39  * A menu can optionally be a <i>tear-off</i> menu. A tear-off menu
       
    40  * can be opened and dragged away from its parent menu bar or menu.
       
    41  * It remains on the screen after the mouse button has been released.
       
    42  * The mechanism for tearing off a menu is platform dependent, since
       
    43  * the look and feel of the tear-off menu is determined by its peer.
       
    44  * On platforms that do not support tear-off menus, the tear-off
       
    45  * property is ignored.
       
    46  * <p>
       
    47  * Each item in a menu must belong to the <code>MenuItem</code>
       
    48  * class. It can be an instance of <code>MenuItem</code>, a submenu
       
    49  * (an instance of <code>Menu</code>), or a check box (an instance of
       
    50  * <code>CheckboxMenuItem</code>).
       
    51  *
       
    52  * @author Sami Shaio
       
    53  * @see     java.awt.MenuItem
       
    54  * @see     java.awt.CheckboxMenuItem
       
    55  * @since   JDK1.0
       
    56  */
       
    57 public class Menu extends MenuItem implements MenuContainer, Accessible {
       
    58 
       
    59     static {
       
    60         /* ensure that the necessary native libraries are loaded */
       
    61         Toolkit.loadLibraries();
       
    62         if (!GraphicsEnvironment.isHeadless()) {
       
    63             initIDs();
       
    64         }
       
    65     }
       
    66 
       
    67     /**
       
    68      * A vector of the items that will be part of the Menu.
       
    69      *
       
    70      * @serial
       
    71      * @see #countItems()
       
    72      */
       
    73     Vector              items = new Vector();
       
    74 
       
    75     /**
       
    76      * This field indicates whether the menu has the
       
    77      * tear of property or not.  It will be set to
       
    78      * <code>true</code> if the menu has the tear off
       
    79      * property and it will be set to <code>false</code>
       
    80      * if it does not.
       
    81      * A torn off menu can be deleted by a user when
       
    82      * it is no longer needed.
       
    83      *
       
    84      * @serial
       
    85      * @see #isTearOff()
       
    86      */
       
    87     boolean             tearOff;
       
    88 
       
    89     /**
       
    90      * This field will be set to <code>true</code>
       
    91      * if the Menu in question is actually a help
       
    92      * menu.  Otherwise it will be set to <code>
       
    93      * false</code>.
       
    94      *
       
    95      * @serial
       
    96      */
       
    97     boolean             isHelpMenu;
       
    98 
       
    99     private static final String base = "menu";
       
   100     private static int nameCounter = 0;
       
   101 
       
   102     /*
       
   103      * JDK 1.1 serialVersionUID
       
   104      */
       
   105      private static final long serialVersionUID = -8809584163345499784L;
       
   106 
       
   107     /**
       
   108      * Constructs a new menu with an empty label. This menu is not
       
   109      * a tear-off menu.
       
   110      * @exception HeadlessException if GraphicsEnvironment.isHeadless()
       
   111      * returns true.
       
   112      * @see java.awt.GraphicsEnvironment#isHeadless
       
   113      * @since      JDK1.1
       
   114      */
       
   115     public Menu() throws HeadlessException {
       
   116         this("", false);
       
   117     }
       
   118 
       
   119     /**
       
   120      * Constructs a new menu with the specified label. This menu is not
       
   121      * a tear-off menu.
       
   122      * @param       label the menu's label in the menu bar, or in
       
   123      *                   another menu of which this menu is a submenu.
       
   124      * @exception HeadlessException if GraphicsEnvironment.isHeadless()
       
   125      * returns true.
       
   126      * @see java.awt.GraphicsEnvironment#isHeadless
       
   127      */
       
   128     public Menu(String label) throws HeadlessException {
       
   129         this(label, false);
       
   130     }
       
   131 
       
   132     /**
       
   133      * Constructs a new menu with the specified label,
       
   134      * indicating whether the menu can be torn off.
       
   135      * <p>
       
   136      * Tear-off functionality may not be supported by all
       
   137      * implementations of AWT.  If a particular implementation doesn't
       
   138      * support tear-off menus, this value is silently ignored.
       
   139      * @param       label the menu's label in the menu bar, or in
       
   140      *                   another menu of which this menu is a submenu.
       
   141      * @param       tearOff   if <code>true</code>, the menu
       
   142      *                   is a tear-off menu.
       
   143      * @exception HeadlessException if GraphicsEnvironment.isHeadless()
       
   144      * returns true.
       
   145      * @see java.awt.GraphicsEnvironment#isHeadless
       
   146      * @since       JDK1.0.
       
   147      */
       
   148     public Menu(String label, boolean tearOff) throws HeadlessException {
       
   149         super(label);
       
   150         this.tearOff = tearOff;
       
   151     }
       
   152 
       
   153     /**
       
   154      * Construct a name for this MenuComponent.  Called by getName() when
       
   155      * the name is null.
       
   156      */
       
   157     String constructComponentName() {
       
   158         synchronized (Menu.class) {
       
   159             return base + nameCounter++;
       
   160         }
       
   161     }
       
   162 
       
   163     /**
       
   164      * Creates the menu's peer.  The peer allows us to modify the
       
   165      * appearance of the menu without changing its functionality.
       
   166      */
       
   167     public void addNotify() {
       
   168         synchronized (getTreeLock()) {
       
   169             if (peer == null)
       
   170                 peer = Toolkit.getDefaultToolkit().createMenu(this);
       
   171             int nitems = getItemCount();
       
   172             for (int i = 0 ; i < nitems ; i++) {
       
   173                 MenuItem mi = getItem(i);
       
   174                 mi.parent = this;
       
   175                 mi.addNotify();
       
   176             }
       
   177         }
       
   178     }
       
   179 
       
   180     /**
       
   181      * Removes the menu's peer.  The peer allows us to modify the appearance
       
   182      * of the menu without changing its functionality.
       
   183      */
       
   184     public void removeNotify() {
       
   185         synchronized (getTreeLock()) {
       
   186             int nitems = getItemCount();
       
   187             for (int i = 0 ; i < nitems ; i++) {
       
   188                 getItem(i).removeNotify();
       
   189             }
       
   190             super.removeNotify();
       
   191         }
       
   192     }
       
   193 
       
   194     /**
       
   195      * Indicates whether this menu is a tear-off menu.
       
   196      * <p>
       
   197      * Tear-off functionality may not be supported by all
       
   198      * implementations of AWT.  If a particular implementation doesn't
       
   199      * support tear-off menus, this value is silently ignored.
       
   200      * @return      <code>true</code> if this is a tear-off menu;
       
   201      *                         <code>false</code> otherwise.
       
   202      */
       
   203     public boolean isTearOff() {
       
   204         return tearOff;
       
   205     }
       
   206 
       
   207     /**
       
   208       * Get the number of items in this menu.
       
   209       * @return     the number of items in this menu.
       
   210       * @since      JDK1.1
       
   211       */
       
   212     public int getItemCount() {
       
   213         return countItems();
       
   214     }
       
   215 
       
   216     /**
       
   217      * @deprecated As of JDK version 1.1,
       
   218      * replaced by <code>getItemCount()</code>.
       
   219      */
       
   220     @Deprecated
       
   221     public int countItems() {
       
   222         return countItemsImpl();
       
   223     }
       
   224 
       
   225     /*
       
   226      * This is called by the native code, so client code can't
       
   227      * be called on the toolkit thread.
       
   228      */
       
   229     final int countItemsImpl() {
       
   230         return items.size();
       
   231     }
       
   232 
       
   233     /**
       
   234      * Gets the item located at the specified index of this menu.
       
   235      * @param     index the position of the item to be returned.
       
   236      * @return    the item located at the specified index.
       
   237      */
       
   238     public MenuItem getItem(int index) {
       
   239         return getItemImpl(index);
       
   240     }
       
   241 
       
   242     /*
       
   243      * This is called by the native code, so client code can't
       
   244      * be called on the toolkit thread.
       
   245      */
       
   246     final MenuItem getItemImpl(int index) {
       
   247         return (MenuItem)items.elementAt(index);
       
   248     }
       
   249 
       
   250     /**
       
   251      * Adds the specified menu item to this menu. If the
       
   252      * menu item has been part of another menu, removes it
       
   253      * from that menu.
       
   254      *
       
   255      * @param       mi   the menu item to be added
       
   256      * @return      the menu item added
       
   257      * @see         java.awt.Menu#insert(java.lang.String, int)
       
   258      * @see         java.awt.Menu#insert(java.awt.MenuItem, int)
       
   259      */
       
   260     public MenuItem add(MenuItem mi) {
       
   261         synchronized (getTreeLock()) {
       
   262             if (mi.parent != null) {
       
   263                 mi.parent.remove(mi);
       
   264             }
       
   265             items.addElement(mi);
       
   266             mi.parent = this;
       
   267             MenuPeer peer = (MenuPeer)this.peer;
       
   268             if (peer != null) {
       
   269                 mi.addNotify();
       
   270                 peer.addItem(mi);
       
   271             }
       
   272             return mi;
       
   273         }
       
   274     }
       
   275 
       
   276     /**
       
   277      * Adds an item with the specified label to this menu.
       
   278      *
       
   279      * @param       label   the text on the item
       
   280      * @see         java.awt.Menu#insert(java.lang.String, int)
       
   281      * @see         java.awt.Menu#insert(java.awt.MenuItem, int)
       
   282      */
       
   283     public void add(String label) {
       
   284         add(new MenuItem(label));
       
   285     }
       
   286 
       
   287     /**
       
   288      * Inserts a menu item into this menu
       
   289      * at the specified position.
       
   290      *
       
   291      * @param         menuitem  the menu item to be inserted.
       
   292      * @param         index     the position at which the menu
       
   293      *                          item should be inserted.
       
   294      * @see           java.awt.Menu#add(java.lang.String)
       
   295      * @see           java.awt.Menu#add(java.awt.MenuItem)
       
   296      * @exception     IllegalArgumentException if the value of
       
   297      *                    <code>index</code> is less than zero
       
   298      * @since         JDK1.1
       
   299      */
       
   300 
       
   301     public void insert(MenuItem menuitem, int index) {
       
   302         synchronized (getTreeLock()) {
       
   303             if (index < 0) {
       
   304                 throw new IllegalArgumentException("index less than zero.");
       
   305             }
       
   306 
       
   307             int nitems = getItemCount();
       
   308             Vector tempItems = new Vector();
       
   309 
       
   310             /* Remove the item at index, nitems-index times
       
   311                storing them in a temporary vector in the
       
   312                order they appear on the menu.
       
   313             */
       
   314             for (int i = index ; i < nitems; i++) {
       
   315                 tempItems.addElement(getItem(index));
       
   316                 remove(index);
       
   317             }
       
   318 
       
   319             add(menuitem);
       
   320 
       
   321             /* Add the removed items back to the menu, they are
       
   322                already in the correct order in the temp vector.
       
   323             */
       
   324             for (int i = 0; i < tempItems.size()  ; i++) {
       
   325                 add((MenuItem)tempItems.elementAt(i));
       
   326             }
       
   327         }
       
   328     }
       
   329 
       
   330     /**
       
   331      * Inserts a menu item with the specified label into this menu
       
   332      * at the specified position.  This is a convenience method for
       
   333      * <code>insert(menuItem, index)</code>.
       
   334      *
       
   335      * @param       label the text on the item
       
   336      * @param       index the position at which the menu item
       
   337      *                      should be inserted
       
   338      * @see         java.awt.Menu#add(java.lang.String)
       
   339      * @see         java.awt.Menu#add(java.awt.MenuItem)
       
   340      * @exception     IllegalArgumentException if the value of
       
   341      *                    <code>index</code> is less than zero
       
   342      * @since       JDK1.1
       
   343      */
       
   344 
       
   345     public void insert(String label, int index) {
       
   346         insert(new MenuItem(label), index);
       
   347     }
       
   348 
       
   349     /**
       
   350      * Adds a separator line, or a hypen, to the menu at the current position.
       
   351      * @see         java.awt.Menu#insertSeparator(int)
       
   352      */
       
   353     public void addSeparator() {
       
   354         add("-");
       
   355     }
       
   356 
       
   357     /**
       
   358      * Inserts a separator at the specified position.
       
   359      * @param       index the position at which the
       
   360      *                       menu separator should be inserted.
       
   361      * @exception   IllegalArgumentException if the value of
       
   362      *                       <code>index</code> is less than 0.
       
   363      * @see         java.awt.Menu#addSeparator
       
   364      * @since       JDK1.1
       
   365      */
       
   366 
       
   367     public void insertSeparator(int index) {
       
   368         synchronized (getTreeLock()) {
       
   369             if (index < 0) {
       
   370                 throw new IllegalArgumentException("index less than zero.");
       
   371             }
       
   372 
       
   373             int nitems = getItemCount();
       
   374             Vector tempItems = new Vector();
       
   375 
       
   376             /* Remove the item at index, nitems-index times
       
   377                storing them in a temporary vector in the
       
   378                order they appear on the menu.
       
   379             */
       
   380             for (int i = index ; i < nitems; i++) {
       
   381                 tempItems.addElement(getItem(index));
       
   382                 remove(index);
       
   383             }
       
   384 
       
   385             addSeparator();
       
   386 
       
   387             /* Add the removed items back to the menu, they are
       
   388                already in the correct order in the temp vector.
       
   389             */
       
   390             for (int i = 0; i < tempItems.size()  ; i++) {
       
   391                 add((MenuItem)tempItems.elementAt(i));
       
   392             }
       
   393         }
       
   394     }
       
   395 
       
   396     /**
       
   397      * Removes the menu item at the specified index from this menu.
       
   398      * @param       index the position of the item to be removed.
       
   399      */
       
   400     public void remove(int index) {
       
   401         synchronized (getTreeLock()) {
       
   402             MenuItem mi = getItem(index);
       
   403             items.removeElementAt(index);
       
   404             MenuPeer peer = (MenuPeer)this.peer;
       
   405             if (peer != null) {
       
   406                 mi.removeNotify();
       
   407                 mi.parent = null;
       
   408                 peer.delItem(index);
       
   409             }
       
   410         }
       
   411     }
       
   412 
       
   413     /**
       
   414      * Removes the specified menu item from this menu.
       
   415      * @param  item the item to be removed from the menu.
       
   416      *         If <code>item</code> is <code>null</code>
       
   417      *         or is not in this menu, this method does
       
   418      *         nothing.
       
   419      */
       
   420     public void remove(MenuComponent item) {
       
   421         synchronized (getTreeLock()) {
       
   422             int index = items.indexOf(item);
       
   423             if (index >= 0) {
       
   424                 remove(index);
       
   425             }
       
   426         }
       
   427     }
       
   428 
       
   429     /**
       
   430      * Removes all items from this menu.
       
   431      * @since       JDK1.0.
       
   432      */
       
   433     public void removeAll() {
       
   434         synchronized (getTreeLock()) {
       
   435             int nitems = getItemCount();
       
   436             for (int i = nitems-1 ; i >= 0 ; i--) {
       
   437                 remove(i);
       
   438             }
       
   439         }
       
   440     }
       
   441 
       
   442     /*
       
   443      * Post an ActionEvent to the target of the MenuPeer
       
   444      * associated with the specified keyboard event (on
       
   445      * keydown).  Returns true if there is an associated
       
   446      * keyboard event.
       
   447      */
       
   448     boolean handleShortcut(KeyEvent e) {
       
   449         int nitems = getItemCount();
       
   450         for (int i = 0 ; i < nitems ; i++) {
       
   451             MenuItem mi = getItem(i);
       
   452             if (mi.handleShortcut(e)) {
       
   453                 return true;
       
   454             }
       
   455         }
       
   456         return false;
       
   457     }
       
   458 
       
   459     MenuItem getShortcutMenuItem(MenuShortcut s) {
       
   460         int nitems = getItemCount();
       
   461         for (int i = 0 ; i < nitems ; i++) {
       
   462             MenuItem mi = getItem(i).getShortcutMenuItem(s);
       
   463             if (mi != null) {
       
   464                 return mi;
       
   465             }
       
   466         }
       
   467         return null;
       
   468     }
       
   469 
       
   470     synchronized Enumeration shortcuts() {
       
   471         Vector shortcuts = new Vector();
       
   472         int nitems = getItemCount();
       
   473         for (int i = 0 ; i < nitems ; i++) {
       
   474             MenuItem mi = getItem(i);
       
   475             if (mi instanceof Menu) {
       
   476                 Enumeration e = ((Menu)mi).shortcuts();
       
   477                 while (e.hasMoreElements()) {
       
   478                     shortcuts.addElement(e.nextElement());
       
   479                 }
       
   480             } else {
       
   481                 MenuShortcut ms = mi.getShortcut();
       
   482                 if (ms != null) {
       
   483                     shortcuts.addElement(ms);
       
   484                 }
       
   485             }
       
   486         }
       
   487         return shortcuts.elements();
       
   488     }
       
   489 
       
   490     void deleteShortcut(MenuShortcut s) {
       
   491         int nitems = getItemCount();
       
   492         for (int i = 0 ; i < nitems ; i++) {
       
   493             getItem(i).deleteShortcut(s);
       
   494         }
       
   495     }
       
   496 
       
   497 
       
   498     /* Serialization support.  A MenuContainer is responsible for
       
   499      * restoring the parent fields of its children.
       
   500      */
       
   501 
       
   502     /**
       
   503      * The menu serialized Data Version.
       
   504      *
       
   505      * @serial
       
   506      */
       
   507     private int menuSerializedDataVersion = 1;
       
   508 
       
   509     /**
       
   510      * Writes default serializable fields to stream.
       
   511      *
       
   512      * @param s the <code>ObjectOutputStream</code> to write
       
   513      * @see AWTEventMulticaster#save(ObjectOutputStream, String, EventListener)
       
   514      * @see #readObject(ObjectInputStream)
       
   515      */
       
   516     private void writeObject(java.io.ObjectOutputStream s)
       
   517       throws java.io.IOException
       
   518     {
       
   519       s.defaultWriteObject();
       
   520     }
       
   521 
       
   522     /**
       
   523      * Reads the <code>ObjectInputStream</code>.
       
   524      * Unrecognized keys or values will be ignored.
       
   525      *
       
   526      * @param s the <code>ObjectInputStream</code> to read
       
   527      * @exception HeadlessException if
       
   528      *   <code>GraphicsEnvironment.isHeadless</code> returns
       
   529      *   <code>true</code>
       
   530      * @see java.awt.GraphicsEnvironment#isHeadless
       
   531      * @see #writeObject(ObjectOutputStream)
       
   532      */
       
   533     private void readObject(ObjectInputStream s)
       
   534       throws IOException, ClassNotFoundException, HeadlessException
       
   535     {
       
   536       // HeadlessException will be thrown from MenuComponent's readObject
       
   537       s.defaultReadObject();
       
   538       for(int i = 0; i < items.size(); i++) {
       
   539         MenuItem item = (MenuItem)items.elementAt(i);
       
   540         item.parent = this;
       
   541       }
       
   542     }
       
   543 
       
   544     /**
       
   545      * Returns a string representing the state of this <code>Menu</code>.
       
   546      * This method is intended to be used only for debugging purposes, and the
       
   547      * content and format of the returned string may vary between
       
   548      * implementations. The returned string may be empty but may not be
       
   549      * <code>null</code>.
       
   550      *
       
   551      * @return the parameter string of this menu
       
   552      */
       
   553     public String paramString() {
       
   554         String str = ",tearOff=" + tearOff+",isHelpMenu=" + isHelpMenu;
       
   555         return super.paramString() + str;
       
   556     }
       
   557 
       
   558     /**
       
   559      * Initialize JNI field and method IDs
       
   560      */
       
   561     private static native void initIDs();
       
   562 
       
   563 
       
   564 /////////////////
       
   565 // Accessibility support
       
   566 ////////////////
       
   567 
       
   568     /**
       
   569      * Gets the AccessibleContext associated with this Menu.
       
   570      * For menus, the AccessibleContext takes the form of an
       
   571      * AccessibleAWTMenu.
       
   572      * A new AccessibleAWTMenu instance is created if necessary.
       
   573      *
       
   574      * @return an AccessibleAWTMenu that serves as the
       
   575      *         AccessibleContext of this Menu
       
   576      * @since 1.3
       
   577      */
       
   578     public AccessibleContext getAccessibleContext() {
       
   579         if (accessibleContext == null) {
       
   580             accessibleContext = new AccessibleAWTMenu();
       
   581         }
       
   582         return accessibleContext;
       
   583     }
       
   584 
       
   585     /**
       
   586      * Defined in MenuComponent. Overridden here.
       
   587      */
       
   588     int getAccessibleChildIndex(MenuComponent child) {
       
   589         return items.indexOf(child);
       
   590     }
       
   591 
       
   592     /**
       
   593      * Inner class of Menu used to provide default support for
       
   594      * accessibility.  This class is not meant to be used directly by
       
   595      * application developers, but is instead meant only to be
       
   596      * subclassed by menu component developers.
       
   597      * <p>
       
   598      * This class implements accessibility support for the
       
   599      * <code>Menu</code> class.  It provides an implementation of the
       
   600      * Java Accessibility API appropriate to menu user-interface elements.
       
   601      * @since 1.3
       
   602      */
       
   603     protected class AccessibleAWTMenu extends AccessibleAWTMenuItem
       
   604     {
       
   605         /*
       
   606          * JDK 1.3 serialVersionUID
       
   607          */
       
   608         private static final long serialVersionUID = 5228160894980069094L;
       
   609 
       
   610         /**
       
   611          * Get the role of this object.
       
   612          *
       
   613          * @return an instance of AccessibleRole describing the role of the
       
   614          * object
       
   615          */
       
   616         public AccessibleRole getAccessibleRole() {
       
   617             return AccessibleRole.MENU;
       
   618         }
       
   619 
       
   620     } // class AccessibleAWTMenu
       
   621 
       
   622 }