Home » openjdk-7 » javax » swing » [javadoc | source]

    1   /*
    2    * Copyright (c) 1997, 2008, Oracle and/or its affiliates. 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.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22    * or visit www.oracle.com if you need additional information or have any
   23    * questions.
   24    */
   25   
   26   package javax.swing;
   27   
   28   import java.awt;
   29   import java.awt.event;
   30   import java.io.IOException;
   31   import java.io.ObjectInputStream;
   32   import java.io.ObjectOutputStream;
   33   import java.io.Serializable;
   34   import java.beans;
   35   
   36   import java.util.Locale;
   37   import java.util.Vector;
   38   import java.util.Hashtable;
   39   import javax.accessibility;
   40   import javax.swing.plaf.PopupMenuUI;
   41   import javax.swing.plaf.ComponentUI;
   42   import javax.swing.plaf.basic.BasicComboPopup;
   43   import javax.swing.event;
   44   import sun.security.util.SecurityConstants;
   45   
   46   import java.applet.Applet;
   47   
   48   /**
   49    * An implementation of a popup menu -- a small window that pops up
   50    * and displays a series of choices. A <code>JPopupMenu</code> is used for the
   51    * menu that appears when the user selects an item on the menu bar.
   52    * It is also used for "pull-right" menu that appears when the
   53    * selects a menu item that activates it. Finally, a <code>JPopupMenu</code>
   54    * can also be used anywhere else you want a menu to appear.  For
   55    * example, when the user right-clicks in a specified area.
   56    * <p>
   57    * For information and examples of using popup menus, see
   58    * <a
   59    href="http://java.sun.com/docs/books/tutorial/uiswing/components/menu.html">How to Use Menus</a>
   60    * in <em>The Java Tutorial.</em>
   61    * <p>
   62    * <strong>Warning:</strong> Swing is not thread safe. For more
   63    * information see <a
   64    * href="package-summary.html#threading">Swing's Threading
   65    * Policy</a>.
   66    * <p>
   67    * <strong>Warning:</strong>
   68    * Serialized objects of this class will not be compatible with
   69    * future Swing releases. The current serialization support is
   70    * appropriate for short term storage or RMI between applications running
   71    * the same version of Swing.  As of 1.4, support for long term storage
   72    * of all JavaBeans<sup><font size="-2">TM</font></sup>
   73    * has been added to the <code>java.beans</code> package.
   74    * Please see {@link java.beans.XMLEncoder}.
   75    *
   76    * @beaninfo
   77    *   attribute: isContainer false
   78    * description: A small window that pops up and displays a series of choices.
   79    *
   80    * @author Georges Saab
   81    * @author David Karlton
   82    * @author Arnaud Weber
   83    */
   84   public class JPopupMenu extends JComponent implements Accessible,MenuElement {
   85   
   86       /**
   87        * @see #getUIClassID
   88        * @see #readObject
   89        */
   90       private static final String uiClassID = "PopupMenuUI";
   91   
   92       /**
   93        * Key used in AppContext to determine if light way popups are the default.
   94        */
   95       private static final Object defaultLWPopupEnabledKey =
   96           new StringBuffer("JPopupMenu.defaultLWPopupEnabledKey");
   97   
   98       /** Bug#4425878-Property javax.swing.adjustPopupLocationToFit introduced */
   99       static boolean popupPostionFixDisabled = false;
  100   
  101       static {
  102           popupPostionFixDisabled = java.security.AccessController.doPrivileged(
  103                   new sun.security.action.GetPropertyAction(
  104                   "javax.swing.adjustPopupLocationToFit","")).equals("false");
  105   
  106       }
  107   
  108       transient  Component invoker;
  109       transient  Popup popup;
  110       transient  Frame frame;
  111       private    int desiredLocationX,desiredLocationY;
  112   
  113       private    String     label                   = null;
  114       private    boolean   paintBorder              = true;
  115       private    Insets    margin                   = null;
  116   
  117       /**
  118        * Used to indicate if lightweight popups should be used.
  119        */
  120       private    boolean   lightWeightPopup         = true;
  121   
  122       /*
  123        * Model for the selected subcontrol.
  124        */
  125       private SingleSelectionModel selectionModel;
  126   
  127       /* Lock object used in place of class object for synchronization.
  128        * (4187686)
  129        */
  130       private static final Object classLock = new Object();
  131   
  132       /* diagnostic aids -- should be false for production builds. */
  133       private static final boolean TRACE =   false; // trace creates and disposes
  134       private static final boolean VERBOSE = false; // show reuse hits/misses
  135       private static final boolean DEBUG =   false;  // show bad params, misc.
  136   
  137       /**
  138        *  Sets the default value of the <code>lightWeightPopupEnabled</code>
  139        *  property.
  140        *
  141        *  @param aFlag <code>true</code> if popups can be lightweight,
  142        *               otherwise <code>false</code>
  143        *  @see #getDefaultLightWeightPopupEnabled
  144        *  @see #setLightWeightPopupEnabled
  145        */
  146       public static void setDefaultLightWeightPopupEnabled(boolean aFlag) {
  147           SwingUtilities.appContextPut(defaultLWPopupEnabledKey,
  148                                        Boolean.valueOf(aFlag));
  149       }
  150   
  151       /**
  152        *  Gets the <code>defaultLightWeightPopupEnabled</code> property,
  153        *  which by default is <code>true</code>.
  154        *
  155        *  @return the value of the <code>defaultLightWeightPopupEnabled</code>
  156        *          property
  157        *
  158        *  @see #setDefaultLightWeightPopupEnabled
  159        */
  160       public static boolean getDefaultLightWeightPopupEnabled() {
  161           Boolean b = (Boolean)
  162               SwingUtilities.appContextGet(defaultLWPopupEnabledKey);
  163           if (b == null) {
  164               SwingUtilities.appContextPut(defaultLWPopupEnabledKey,
  165                                            Boolean.TRUE);
  166               return true;
  167           }
  168           return b.booleanValue();
  169       }
  170   
  171       /**
  172        * Constructs a <code>JPopupMenu</code> without an "invoker".
  173        */
  174       public JPopupMenu() {
  175           this(null);
  176       }
  177   
  178       /**
  179        * Constructs a <code>JPopupMenu</code> with the specified title.
  180        *
  181        * @param label  the string that a UI may use to display as a title
  182        * for the popup menu.
  183        */
  184       public JPopupMenu(String label) {
  185           this.label = label;
  186           lightWeightPopup = getDefaultLightWeightPopupEnabled();
  187           setSelectionModel(new DefaultSingleSelectionModel());
  188           enableEvents(AWTEvent.MOUSE_EVENT_MASK);
  189           setFocusTraversalKeysEnabled(false);
  190           updateUI();
  191       }
  192   
  193   
  194   
  195       /**
  196        * Returns the look and feel (L&F) object that renders this component.
  197        *
  198        * @return the <code>PopupMenuUI</code> object that renders this component
  199        */
  200       public PopupMenuUI getUI() {
  201           return (PopupMenuUI)ui;
  202       }
  203   
  204       /**
  205        * Sets the L&F object that renders this component.
  206        *
  207        * @param ui the new <code>PopupMenuUI</code> L&F object
  208        * @see UIDefaults#getUI
  209        * @beaninfo
  210        *        bound: true
  211        *       hidden: true
  212        *    attribute: visualUpdate true
  213        *  description: The UI object that implements the Component's LookAndFeel.
  214        */
  215       public void setUI(PopupMenuUI ui) {
  216           super.setUI(ui);
  217       }
  218   
  219       /**
  220        * Resets the UI property to a value from the current look and feel.
  221        *
  222        * @see JComponent#updateUI
  223        */
  224       public void updateUI() {
  225           setUI((PopupMenuUI)UIManager.getUI(this));
  226       }
  227   
  228   
  229       /**
  230        * Returns the name of the L&F class that renders this component.
  231        *
  232        * @return the string "PopupMenuUI"
  233        * @see JComponent#getUIClassID
  234        * @see UIDefaults#getUI
  235        */
  236       public String getUIClassID() {
  237           return uiClassID;
  238       }
  239   
  240       protected void processFocusEvent(FocusEvent evt) {
  241           super.processFocusEvent(evt);
  242       }
  243   
  244       /**
  245        * Processes key stroke events such as mnemonics and accelerators.
  246        *
  247        * @param evt  the key event to be processed
  248        */
  249       protected void processKeyEvent(KeyEvent evt) {
  250           MenuSelectionManager.defaultManager().processKeyEvent(evt);
  251           if (evt.isConsumed()) {
  252               return;
  253           }
  254           super.processKeyEvent(evt);
  255       }
  256   
  257   
  258       /**
  259        * Returns the model object that handles single selections.
  260        *
  261        * @return the <code>selectionModel</code> property
  262        * @see SingleSelectionModel
  263        */
  264       public SingleSelectionModel getSelectionModel() {
  265           return selectionModel;
  266       }
  267   
  268       /**
  269        * Sets the model object to handle single selections.
  270        *
  271        * @param model the new <code>SingleSelectionModel</code>
  272        * @see SingleSelectionModel
  273        * @beaninfo
  274        * description: The selection model for the popup menu
  275        *      expert: true
  276        */
  277       public void setSelectionModel(SingleSelectionModel model) {
  278           selectionModel = model;
  279       }
  280   
  281       /**
  282        * Appends the specified menu item to the end of this menu.
  283        *
  284        * @param menuItem the <code>JMenuItem</code> to add
  285        * @return the <code>JMenuItem</code> added
  286        */
  287       public JMenuItem add(JMenuItem menuItem) {
  288           super.add(menuItem);
  289           return menuItem;
  290       }
  291   
  292       /**
  293        * Creates a new menu item with the specified text and appends
  294        * it to the end of this menu.
  295        *
  296        * @param s the string for the menu item to be added
  297        */
  298       public JMenuItem add(String s) {
  299           return add(new JMenuItem(s));
  300       }
  301   
  302       /**
  303        * Appends a new menu item to the end of the menu which
  304        * dispatches the specified <code>Action</code> object.
  305        *
  306        * @param a the <code>Action</code> to add to the menu
  307        * @return the new menu item
  308        * @see Action
  309        */
  310       public JMenuItem add(Action a) {
  311           JMenuItem mi = createActionComponent(a);
  312           mi.setAction(a);
  313           add(mi);
  314           return mi;
  315       }
  316   
  317       /**
  318        * Returns an point which has been adjusted to take into account of the
  319        * desktop bounds, taskbar and multi-monitor configuration.
  320        * <p>
  321        * This adustment may be cancelled by invoking the application with
  322        * -Djavax.swing.adjustPopupLocationToFit=false
  323        */
  324       Point adjustPopupLocationToFitScreen(int xPosition, int yPosition) {
  325           Point popupLocation = new Point(xPosition, yPosition);
  326   
  327           if(popupPostionFixDisabled == true || GraphicsEnvironment.isHeadless()) {
  328               return popupLocation;
  329           }
  330   
  331           // Get screen bounds
  332           Rectangle scrBounds;
  333           GraphicsConfiguration gc = getCurrentGraphicsConfiguration(popupLocation);
  334           Toolkit toolkit = Toolkit.getDefaultToolkit();
  335           if(gc != null) {
  336               // If we have GraphicsConfiguration use it to get screen bounds
  337               scrBounds = gc.getBounds();
  338           } else {
  339               // If we don't have GraphicsConfiguration use primary screen
  340               scrBounds = new Rectangle(toolkit.getScreenSize());
  341           }
  342   
  343           // Calculate the screen size that popup should fit
  344           Dimension popupSize = JPopupMenu.this.getPreferredSize();
  345           long popupRightX = (long)popupLocation.x + (long)popupSize.width;
  346           long popupBottomY = (long)popupLocation.y + (long)popupSize.height;
  347           int scrWidth = scrBounds.width;
  348           int scrHeight = scrBounds.height;
  349           if (!canPopupOverlapTaskBar()) {
  350               // Insets include the task bar. Take them into account.
  351               Insets scrInsets = toolkit.getScreenInsets(gc);
  352               scrBounds.x += scrInsets.left;
  353               scrBounds.y += scrInsets.top;
  354               scrWidth -= scrInsets.left + scrInsets.right;
  355               scrHeight -= scrInsets.top + scrInsets.bottom;
  356           }
  357           int scrRightX = scrBounds.x + scrWidth;
  358           int scrBottomY = scrBounds.y + scrHeight;
  359   
  360           // Ensure that popup menu fits the screen
  361           if (popupRightX > (long)scrRightX) {
  362               popupLocation.x = scrRightX - popupSize.width;
  363               if( popupLocation.x < scrBounds.x ) {
  364                   popupLocation.x = scrBounds.x ;
  365               }
  366           }
  367           if (popupBottomY > (long)scrBottomY) {
  368               popupLocation.y = scrBottomY - popupSize.height;
  369               if( popupLocation.y < scrBounds.y ) {
  370                   popupLocation.y = scrBounds.y;
  371               }
  372           }
  373   
  374           return popupLocation;
  375       }
  376   
  377       /**
  378        * Tries to find GraphicsConfiguration
  379        * that contains the mouse cursor position.
  380        * Can return null.
  381        */
  382       private GraphicsConfiguration getCurrentGraphicsConfiguration(
  383               Point popupLocation) {
  384           GraphicsConfiguration gc = null;
  385           GraphicsEnvironment ge =
  386               GraphicsEnvironment.getLocalGraphicsEnvironment();
  387           GraphicsDevice[] gd = ge.getScreenDevices();
  388           for(int i = 0; i < gd.length; i++) {
  389               if(gd[i].getType() == GraphicsDevice.TYPE_RASTER_SCREEN) {
  390                   GraphicsConfiguration dgc =
  391                       gd[i].getDefaultConfiguration();
  392                   if(dgc.getBounds().contains(popupLocation)) {
  393                       gc = dgc;
  394                       break;
  395                   }
  396               }
  397           }
  398           // If not found and we have invoker, ask invoker about his gc
  399           if(gc == null && getInvoker() != null) {
  400               gc = getInvoker().getGraphicsConfiguration();
  401           }
  402           return gc;
  403       }
  404   
  405       /**
  406        * Checks that there are enough security permissions
  407        * to make popup "always on top", which allows to show it above the task bar.
  408        */
  409       static boolean canPopupOverlapTaskBar() {
  410           boolean result = true;
  411           try {
  412               SecurityManager sm = System.getSecurityManager();
  413               if (sm != null) {
  414                   sm.checkPermission(
  415                       SecurityConstants.AWT.SET_WINDOW_ALWAYS_ON_TOP_PERMISSION);
  416               }
  417           } catch (SecurityException se) {
  418               // There is no permission to show popups over the task bar
  419               result = false;
  420           }
  421           return result;
  422       }
  423   
  424   
  425       /**
  426        * Factory method which creates the <code>JMenuItem</code> for
  427        * <code>Actions</code> added to the <code>JPopupMenu</code>.
  428        *
  429        * @param a the <code>Action</code> for the menu item to be added
  430        * @return the new menu item
  431        * @see Action
  432        *
  433        * @since 1.3
  434        */
  435       protected JMenuItem createActionComponent(Action a) {
  436           JMenuItem mi = new JMenuItem() {
  437               protected PropertyChangeListener createActionPropertyChangeListener(Action a) {
  438                   PropertyChangeListener pcl = createActionChangeListener(this);
  439                   if (pcl == null) {
  440                       pcl = super.createActionPropertyChangeListener(a);
  441                   }
  442                   return pcl;
  443               }
  444           };
  445           mi.setHorizontalTextPosition(JButton.TRAILING);
  446           mi.setVerticalTextPosition(JButton.CENTER);
  447           return mi;
  448       }
  449   
  450       /**
  451        * Returns a properly configured <code>PropertyChangeListener</code>
  452        * which updates the control as changes to the <code>Action</code> occur.
  453        */
  454       protected PropertyChangeListener createActionChangeListener(JMenuItem b) {
  455           return b.createActionPropertyChangeListener0(b.getAction());
  456       }
  457   
  458       /**
  459        * Removes the component at the specified index from this popup menu.
  460        *
  461        * @param       pos the position of the item to be removed
  462        * @exception   IllegalArgumentException if the value of
  463        *                          <code>pos</code> < 0, or if the value of
  464        *                          <code>pos</code> is greater than the
  465        *                          number of items
  466        */
  467       public void remove(int pos) {
  468           if (pos < 0) {
  469               throw new IllegalArgumentException("index less than zero.");
  470           }
  471           if (pos > getComponentCount() -1) {
  472               throw new IllegalArgumentException("index greater than the number of items.");
  473           }
  474           super.remove(pos);
  475       }
  476   
  477       /**
  478        * Sets the value of the <code>lightWeightPopupEnabled</code> property,
  479        * which by default is <code>true</code>.
  480        * By default, when a look and feel displays a popup,
  481        * it can choose to
  482        * use a lightweight (all-Java) popup.
  483        * Lightweight popup windows are more efficient than heavyweight
  484        * (native peer) windows,
  485        * but lightweight and heavyweight components do not mix well in a GUI.
  486        * If your application mixes lightweight and heavyweight components,
  487        * you should disable lightweight popups.
  488        * Some look and feels might always use heavyweight popups,
  489        * no matter what the value of this property.
  490        *
  491        * @param aFlag  <code>false</code> to disable lightweight popups
  492        * @beaninfo
  493        * description: Determines whether lightweight popups are used when possible
  494        *      expert: true
  495        *
  496        * @see #isLightWeightPopupEnabled
  497        */
  498       public void setLightWeightPopupEnabled(boolean aFlag) {
  499           // NOTE: this use to set the flag on a shared JPopupMenu, which meant
  500           // this effected ALL JPopupMenus.
  501           lightWeightPopup = aFlag;
  502       }
  503   
  504       /**
  505        * Gets the <code>lightWeightPopupEnabled</code> property.
  506        *
  507        * @return the value of the <code>lightWeightPopupEnabled</code> property
  508        * @see #setLightWeightPopupEnabled
  509        */
  510       public boolean isLightWeightPopupEnabled() {
  511           return lightWeightPopup;
  512       }
  513   
  514       /**
  515        * Returns the popup menu's label
  516        *
  517        * @return a string containing the popup menu's label
  518        * @see #setLabel
  519        */
  520       public String getLabel() {
  521           return label;
  522       }
  523   
  524       /**
  525        * Sets the popup menu's label.  Different look and feels may choose
  526        * to display or not display this.
  527        *
  528        * @param label a string specifying the label for the popup menu
  529        *
  530        * @see #setLabel
  531        * @beaninfo
  532        * description: The label for the popup menu.
  533        *       bound: true
  534        */
  535       public void setLabel(String label) {
  536           String oldValue = this.label;
  537           this.label = label;
  538           firePropertyChange("label", oldValue, label);
  539           if (accessibleContext != null) {
  540               accessibleContext.firePropertyChange(
  541                   AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  542                   oldValue, label);
  543           }
  544           invalidate();
  545           repaint();
  546       }
  547   
  548       /**
  549        * Appends a new separator at the end of the menu.
  550        */
  551       public void addSeparator() {
  552           add( new JPopupMenu.Separator() );
  553       }
  554   
  555       /**
  556        * Inserts a menu item for the specified <code>Action</code> object at
  557        * a given position.
  558        *
  559        * @param a  the <code>Action</code> object to insert
  560        * @param index      specifies the position at which to insert the
  561        *                   <code>Action</code>, where 0 is the first
  562        * @exception IllegalArgumentException if <code>index</code> < 0
  563        * @see Action
  564        */
  565       public void insert(Action a, int index) {
  566           JMenuItem mi = createActionComponent(a);
  567           mi.setAction(a);
  568           insert(mi, index);
  569       }
  570   
  571       /**
  572        * Inserts the specified component into the menu at a given
  573        * position.
  574        *
  575        * @param component  the <code>Component</code> to insert
  576        * @param index      specifies the position at which
  577        *                   to insert the component, where 0 is the first
  578        * @exception IllegalArgumentException if <code>index</code> < 0
  579        */
  580       public void insert(Component component, int index) {
  581           if (index < 0) {
  582               throw new IllegalArgumentException("index less than zero.");
  583           }
  584   
  585           int nitems = getComponentCount();
  586           // PENDING(ges): Why not use an array?
  587           Vector<Component> tempItems = new Vector<Component>();
  588   
  589           /* Remove the item at index, nitems-index times
  590              storing them in a temporary vector in the
  591              order they appear on the menu.
  592              */
  593           for (int i = index ; i < nitems; i++) {
  594               tempItems.addElement(getComponent(index));
  595               remove(index);
  596           }
  597   
  598           add(component);
  599   
  600           /* Add the removed items back to the menu, they are
  601              already in the correct order in the temp vector.
  602              */
  603           for (Component tempItem : tempItems) {
  604               add(tempItem);
  605           }
  606       }
  607   
  608       /**
  609        *  Adds a <code>PopupMenu</code> listener.
  610        *
  611        *  @param l  the <code>PopupMenuListener</code> to add
  612        */
  613       public void addPopupMenuListener(PopupMenuListener l) {
  614           listenerList.add(PopupMenuListener.class,l);
  615       }
  616   
  617       /**
  618        * Removes a <code>PopupMenu</code> listener.
  619        *
  620        * @param l  the <code>PopupMenuListener</code> to remove
  621        */
  622       public void removePopupMenuListener(PopupMenuListener l) {
  623           listenerList.remove(PopupMenuListener.class,l);
  624       }
  625   
  626       /**
  627        * Returns an array of all the <code>PopupMenuListener</code>s added
  628        * to this JMenuItem with addPopupMenuListener().
  629        *
  630        * @return all of the <code>PopupMenuListener</code>s added or an empty
  631        *         array if no listeners have been added
  632        * @since 1.4
  633        */
  634       public PopupMenuListener[] getPopupMenuListeners() {
  635           return listenerList.getListeners(PopupMenuListener.class);
  636       }
  637   
  638       /**
  639        * Adds a <code>MenuKeyListener</code> to the popup menu.
  640        *
  641        * @param l the <code>MenuKeyListener</code> to be added
  642        * @since 1.5
  643        */
  644       public void addMenuKeyListener(MenuKeyListener l) {
  645           listenerList.add(MenuKeyListener.class, l);
  646       }
  647   
  648       /**
  649        * Removes a <code>MenuKeyListener</code> from the popup menu.
  650        *
  651        * @param l the <code>MenuKeyListener</code> to be removed
  652        * @since 1.5
  653        */
  654       public void removeMenuKeyListener(MenuKeyListener l) {
  655           listenerList.remove(MenuKeyListener.class, l);
  656       }
  657   
  658       /**
  659        * Returns an array of all the <code>MenuKeyListener</code>s added
  660        * to this JPopupMenu with addMenuKeyListener().
  661        *
  662        * @return all of the <code>MenuKeyListener</code>s added or an empty
  663        *         array if no listeners have been added
  664        * @since 1.5
  665        */
  666       public MenuKeyListener[] getMenuKeyListeners() {
  667           return listenerList.getListeners(MenuKeyListener.class);
  668       }
  669   
  670       /**
  671        * Notifies <code>PopupMenuListener</code>s that this popup menu will
  672        * become visible.
  673        */
  674       protected void firePopupMenuWillBecomeVisible() {
  675           Object[] listeners = listenerList.getListenerList();
  676           PopupMenuEvent e=null;
  677           for (int i = listeners.length-2; i>=0; i-=2) {
  678               if (listeners[i]==PopupMenuListener.class) {
  679                   if (e == null)
  680                       e = new PopupMenuEvent(this);
  681                   ((PopupMenuListener)listeners[i+1]).popupMenuWillBecomeVisible(e);
  682               }
  683           }
  684       }
  685   
  686       /**
  687        * Notifies <code>PopupMenuListener</code>s that this popup menu will
  688        * become invisible.
  689        */
  690       protected void firePopupMenuWillBecomeInvisible() {
  691           Object[] listeners = listenerList.getListenerList();
  692           PopupMenuEvent e=null;
  693           for (int i = listeners.length-2; i>=0; i-=2) {
  694               if (listeners[i]==PopupMenuListener.class) {
  695                   if (e == null)
  696                       e = new PopupMenuEvent(this);
  697                   ((PopupMenuListener)listeners[i+1]).popupMenuWillBecomeInvisible(e);
  698               }
  699           }
  700       }
  701   
  702       /**
  703        * Notifies <code>PopupMenuListeners</code> that this popup menu is
  704        * cancelled.
  705        */
  706       protected void firePopupMenuCanceled() {
  707           Object[] listeners = listenerList.getListenerList();
  708           PopupMenuEvent e=null;
  709           for (int i = listeners.length-2; i>=0; i-=2) {
  710               if (listeners[i]==PopupMenuListener.class) {
  711                   if (e == null)
  712                       e = new PopupMenuEvent(this);
  713                   ((PopupMenuListener)listeners[i+1]).popupMenuCanceled(e);
  714               }
  715           }
  716       }
  717   
  718       /**
  719        * Always returns true since popups, by definition, should always
  720        * be on top of all other windows.
  721        * @return true
  722        */
  723       // package private
  724       boolean alwaysOnTop() {
  725           return true;
  726       }
  727   
  728       /**
  729        * Lays out the container so that it uses the minimum space
  730        * needed to display its contents.
  731        */
  732       public void pack() {
  733           if(popup != null) {
  734               Dimension pref = getPreferredSize();
  735   
  736               if (pref == null || pref.width != getWidth() ||
  737                                   pref.height != getHeight()) {
  738                   popup = getPopup();
  739               } else {
  740                   validate();
  741               }
  742           }
  743       }
  744   
  745       /**
  746        * Sets the visibility of the popup menu.
  747        *
  748        * @param b true to make the popup visible, or false to
  749        *          hide it
  750        * @beaninfo
  751        *           bound: true
  752        *     description: Makes the popup visible
  753        */
  754       public void setVisible(boolean b) {
  755           if (DEBUG) {
  756               System.out.println("JPopupMenu.setVisible " + b);
  757           }
  758   
  759           // Is it a no-op?
  760           if (b == isVisible())
  761               return;
  762   
  763           // if closing, first close all Submenus
  764           if (b == false) {
  765   
  766               // 4234793: This is a workaround because JPopupMenu.firePopupMenuCanceled is
  767               // a protected method and cannot be called from BasicPopupMenuUI directly
  768               // The real solution could be to make
  769               // firePopupMenuCanceled public and call it directly.
  770               Boolean doCanceled = (Boolean)getClientProperty("JPopupMenu.firePopupMenuCanceled");
  771               if (doCanceled != null && doCanceled == Boolean.TRUE) {
  772                   putClientProperty("JPopupMenu.firePopupMenuCanceled", Boolean.FALSE);
  773                   firePopupMenuCanceled();
  774               }
  775               getSelectionModel().clearSelection();
  776   
  777           } else {
  778               // This is a popup menu with MenuElement children,
  779               // set selection path before popping up!
  780               if (isPopupMenu()) {
  781                   MenuElement me[] = new MenuElement[1];
  782                   me[0] = this;
  783                   MenuSelectionManager.defaultManager().setSelectedPath(me);
  784               }
  785           }
  786   
  787           if(b) {
  788               firePopupMenuWillBecomeVisible();
  789               popup = getPopup();
  790               firePropertyChange("visible", Boolean.FALSE, Boolean.TRUE);
  791   
  792   
  793           } else if(popup != null) {
  794               firePopupMenuWillBecomeInvisible();
  795               popup.hide();
  796               popup = null;
  797               firePropertyChange("visible", Boolean.TRUE, Boolean.FALSE);
  798               // 4694797: When popup menu is made invisible, selected path
  799               // should be cleared
  800               if (isPopupMenu()) {
  801                   MenuSelectionManager.defaultManager().clearSelectedPath();
  802               }
  803           }
  804       }
  805   
  806       /**
  807        * Returns a <code>Popup</code> instance from the
  808        * <code>PopupMenuUI</code> that has had <code>show</code> invoked on
  809        * it. If the current <code>popup</code> is non-null,
  810        * this will invoke <code>dispose</code> of it, and then
  811        * <code>show</code> the new one.
  812        * <p>
  813        * This does NOT fire any events, it is up the caller to dispatch
  814        * the necessary events.
  815        */
  816       private Popup getPopup() {
  817           Popup oldPopup = popup;
  818   
  819           if (oldPopup != null) {
  820               oldPopup.hide();
  821           }
  822           PopupFactory popupFactory = PopupFactory.getSharedInstance();
  823   
  824           if (isLightWeightPopupEnabled()) {
  825               popupFactory.setPopupType(PopupFactory.LIGHT_WEIGHT_POPUP);
  826           }
  827           else {
  828               popupFactory.setPopupType(PopupFactory.MEDIUM_WEIGHT_POPUP);
  829           }
  830   
  831           // adjust the location of the popup
  832           Point p = adjustPopupLocationToFitScreen(desiredLocationX,desiredLocationY);
  833           desiredLocationX = p.x;
  834           desiredLocationY = p.y;
  835   
  836           Popup newPopup = getUI().getPopup(this, desiredLocationX,
  837                                             desiredLocationY);
  838   
  839           popupFactory.setPopupType(PopupFactory.LIGHT_WEIGHT_POPUP);
  840           newPopup.show();
  841           return newPopup;
  842       }
  843   
  844       /**
  845        * Returns true if the popup menu is visible (currently
  846        * being displayed).
  847        */
  848       public boolean isVisible() {
  849           return popup != null;
  850       }
  851   
  852       /**
  853        * Sets the location of the upper left corner of the
  854        * popup menu using x, y coordinates.
  855        *
  856        * @param x the x coordinate of the popup's new position
  857        *          in the screen's coordinate space
  858        * @param y the y coordinate of the popup's new position
  859        *          in the screen's coordinate space
  860        * @beaninfo
  861        * description: The location of the popup menu.
  862        */
  863       public void setLocation(int x, int y) {
  864           int oldX = desiredLocationX;
  865           int oldY = desiredLocationY;
  866   
  867           desiredLocationX = x;
  868           desiredLocationY = y;
  869           if(popup != null && (x != oldX || y != oldY)) {
  870               popup = getPopup();
  871           }
  872       }
  873   
  874       /**
  875        * Returns true if the popup menu is a standalone popup menu
  876        * rather than the submenu of a <code>JMenu</code>.
  877        *
  878        * @return true if this menu is a standalone popup menu, otherwise false
  879        */
  880       private boolean isPopupMenu() {
  881           return  ((invoker != null) && !(invoker instanceof JMenu));
  882       }
  883   
  884       /**
  885        * Returns the component which is the 'invoker' of this
  886        * popup menu.
  887        *
  888        * @return the <code>Component</code> in which the popup menu is displayed
  889        */
  890       public Component getInvoker() {
  891           return this.invoker;
  892       }
  893   
  894       /**
  895        * Sets the invoker of this popup menu -- the component in which
  896        * the popup menu menu is to be displayed.
  897        *
  898        * @param invoker the <code>Component</code> in which the popup
  899        *          menu is displayed
  900        * @beaninfo
  901        * description: The invoking component for the popup menu
  902        *      expert: true
  903        */
  904       public void setInvoker(Component invoker) {
  905           Component oldInvoker = this.invoker;
  906           this.invoker = invoker;
  907           if ((oldInvoker != this.invoker) && (ui != null)) {
  908               ui.uninstallUI(this);
  909               ui.installUI(this);
  910           }
  911           invalidate();
  912       }
  913   
  914       /**
  915        * Displays the popup menu at the position x,y in the coordinate
  916        * space of the component invoker.
  917        *
  918        * @param invoker the component in whose space the popup menu is to appear
  919        * @param x the x coordinate in invoker's coordinate space at which
  920        * the popup menu is to be displayed
  921        * @param y the y coordinate in invoker's coordinate space at which
  922        * the popup menu is to be displayed
  923        */
  924       public void show(Component invoker, int x, int y) {
  925           if (DEBUG) {
  926               System.out.println("in JPopupMenu.show " );
  927           }
  928           setInvoker(invoker);
  929           Frame newFrame = getFrame(invoker);
  930           if (newFrame != frame) {
  931               // Use the invoker's frame so that events
  932               // are propagated properly
  933               if (newFrame!=null) {
  934                   this.frame = newFrame;
  935                   if(popup != null) {
  936                       setVisible(false);
  937                   }
  938               }
  939           }
  940           Point invokerOrigin;
  941           if (invoker != null) {
  942               invokerOrigin = invoker.getLocationOnScreen();
  943   
  944               // To avoid integer overflow
  945               long lx, ly;
  946               lx = ((long) invokerOrigin.x) +
  947                    ((long) x);
  948               ly = ((long) invokerOrigin.y) +
  949                    ((long) y);
  950               if(lx > Integer.MAX_VALUE) lx = Integer.MAX_VALUE;
  951               if(lx < Integer.MIN_VALUE) lx = Integer.MIN_VALUE;
  952               if(ly > Integer.MAX_VALUE) ly = Integer.MAX_VALUE;
  953               if(ly < Integer.MIN_VALUE) ly = Integer.MIN_VALUE;
  954   
  955               setLocation((int) lx, (int) ly);
  956           } else {
  957               setLocation(x, y);
  958           }
  959           setVisible(true);
  960       }
  961   
  962       /**
  963        * Returns the popup menu which is at the root of the menu system
  964        * for this popup menu.
  965        *
  966        * @return the topmost grandparent <code>JPopupMenu</code>
  967        */
  968       JPopupMenu getRootPopupMenu() {
  969           JPopupMenu mp = this;
  970           while((mp!=null) && (mp.isPopupMenu()!=true) &&
  971                 (mp.getInvoker() != null) &&
  972                 (mp.getInvoker().getParent() != null) &&
  973                 (mp.getInvoker().getParent() instanceof JPopupMenu)
  974                 ) {
  975               mp = (JPopupMenu) mp.getInvoker().getParent();
  976           }
  977           return mp;
  978       }
  979   
  980       /**
  981        * Returns the component at the specified index.
  982        *
  983        * @param i  the index of the component, where 0 is the first
  984        * @return the <code>Component</code> at that index
  985        * @deprecated replaced by {@link java.awt.Container#getComponent(int)}
  986        */
  987       @Deprecated
  988       public Component getComponentAtIndex(int i) {
  989           return getComponent(i);
  990       }
  991   
  992       /**
  993        * Returns the index of the specified component.
  994        *
  995        * @param  c the <code>Component</code> to find
  996        * @return the index of the component, where 0 is the first;
  997        *         or -1 if the component is not found
  998        */
  999       public int getComponentIndex(Component c) {
 1000           int ncomponents = this.getComponentCount();
 1001           Component[] component = this.getComponents();
 1002           for (int i = 0 ; i < ncomponents ; i++) {
 1003               Component comp = component[i];
 1004               if (comp == c)
 1005                   return i;
 1006           }
 1007           return -1;
 1008       }
 1009   
 1010       /**
 1011        * Sets the size of the Popup window using a <code>Dimension</code> object.
 1012        * This is equivalent to <code>setPreferredSize(d)</code>.
 1013        *
 1014        * @param d   the <code>Dimension</code> specifying the new size
 1015        * of this component.
 1016        * @beaninfo
 1017        * description: The size of the popup menu
 1018        */
 1019       public void setPopupSize(Dimension d) {
 1020           Dimension oldSize = getPreferredSize();
 1021   
 1022           setPreferredSize(d);
 1023           if (popup != null) {
 1024               Dimension newSize = getPreferredSize();
 1025   
 1026               if (!oldSize.equals(newSize)) {
 1027                   popup = getPopup();
 1028               }
 1029           }
 1030       }
 1031   
 1032       /**
 1033        * Sets the size of the Popup window to the specified width and
 1034        * height. This is equivalent to
 1035        *  <code>setPreferredSize(new Dimension(width, height))</code>.
 1036        *
 1037        * @param width the new width of the Popup in pixels
 1038        * @param height the new height of the Popup in pixels
 1039        * @beaninfo
 1040        * description: The size of the popup menu
 1041        */
 1042       public void setPopupSize(int width, int height) {
 1043           setPopupSize(new Dimension(width, height));
 1044       }
 1045   
 1046       /**
 1047        * Sets the currently selected component,  This will result
 1048        * in a change to the selection model.
 1049        *
 1050        * @param sel the <code>Component</code> to select
 1051        * @beaninfo
 1052        * description: The selected component on the popup menu
 1053        *      expert: true
 1054        *      hidden: true
 1055        */
 1056       public void setSelected(Component sel) {
 1057           SingleSelectionModel model = getSelectionModel();
 1058           int index = getComponentIndex(sel);
 1059           model.setSelectedIndex(index);
 1060       }
 1061   
 1062       /**
 1063        * Checks whether the border should be painted.
 1064        *
 1065        * @return true if the border is painted, false otherwise
 1066        * @see #setBorderPainted
 1067        */
 1068       public boolean isBorderPainted() {
 1069           return paintBorder;
 1070       }
 1071   
 1072       /**
 1073        * Sets whether the border should be painted.
 1074        *
 1075        * @param b if true, the border is painted.
 1076        * @see #isBorderPainted
 1077        * @beaninfo
 1078        * description: Is the border of the popup menu painted
 1079        */
 1080       public void setBorderPainted(boolean b) {
 1081           paintBorder = b;
 1082           repaint();
 1083       }
 1084   
 1085       /**
 1086        * Paints the popup menu's border if the <code>borderPainted</code>
 1087        * property is <code>true</code>.
 1088        * @param g  the <code>Graphics</code> object
 1089        *
 1090        * @see JComponent#paint
 1091        * @see JComponent#setBorder
 1092        */
 1093       protected void paintBorder(Graphics g) {
 1094           if (isBorderPainted()) {
 1095               super.paintBorder(g);
 1096           }
 1097       }
 1098   
 1099       /**
 1100        * Returns the margin, in pixels, between the popup menu's border and
 1101        * its containees.
 1102        *
 1103        * @return an <code>Insets</code> object containing the margin values.
 1104        */
 1105       public Insets getMargin() {
 1106           if(margin == null) {
 1107               return new Insets(0,0,0,0);
 1108           } else {
 1109               return margin;
 1110           }
 1111       }
 1112   
 1113   
 1114       /**
 1115        * Examines the list of menu items to determine whether
 1116        * <code>popup</code> is a popup menu.
 1117        *
 1118        * @param popup  a <code>JPopupMenu</code>
 1119        * @return true if <code>popup</code>
 1120        */
 1121       boolean isSubPopupMenu(JPopupMenu popup) {
 1122           int ncomponents = this.getComponentCount();
 1123           Component[] component = this.getComponents();
 1124           for (int i = 0 ; i < ncomponents ; i++) {
 1125               Component comp = component[i];
 1126               if (comp instanceof JMenu) {
 1127                   JMenu menu = (JMenu)comp;
 1128                   JPopupMenu subPopup = menu.getPopupMenu();
 1129                   if (subPopup == popup)
 1130                       return true;
 1131                   if (subPopup.isSubPopupMenu(popup))
 1132                       return true;
 1133               }
 1134           }
 1135           return false;
 1136       }
 1137   
 1138   
 1139       private static Frame getFrame(Component c) {
 1140           Component w = c;
 1141   
 1142           while(!(w instanceof Frame) && (w!=null)) {
 1143               w = w.getParent();
 1144           }
 1145           return (Frame)w;
 1146       }
 1147   
 1148   
 1149       /**
 1150        * Returns a string representation of this <code>JPopupMenu</code>.
 1151        * This method
 1152        * is intended to be used only for debugging purposes, and the
 1153        * content and format of the returned string may vary between
 1154        * implementations. The returned string may be empty but may not
 1155        * be <code>null</code>.
 1156        *
 1157        * @return  a string representation of this <code>JPopupMenu</code>.
 1158        */
 1159       protected String paramString() {
 1160           String labelString = (label != null ?
 1161                                 label : "");
 1162           String paintBorderString = (paintBorder ?
 1163                                       "true" : "false");
 1164           String marginString = (margin != null ?
 1165                                 margin.toString() : "");
 1166           String lightWeightPopupEnabledString = (isLightWeightPopupEnabled() ?
 1167                                                   "true" : "false");
 1168           return super.paramString() +
 1169               ",desiredLocationX=" + desiredLocationX +
 1170               ",desiredLocationY=" + desiredLocationY +
 1171           ",label=" + labelString +
 1172           ",lightWeightPopupEnabled=" + lightWeightPopupEnabledString +
 1173           ",margin=" + marginString +
 1174           ",paintBorder=" + paintBorderString;
 1175       }
 1176   
 1177   /////////////////
 1178   // Accessibility support
 1179   ////////////////
 1180   
 1181       /**
 1182        * Gets the AccessibleContext associated with this JPopupMenu.
 1183        * For JPopupMenus, the AccessibleContext takes the form of an
 1184        * AccessibleJPopupMenu.
 1185        * A new AccessibleJPopupMenu instance is created if necessary.
 1186        *
 1187        * @return an AccessibleJPopupMenu that serves as the
 1188        *         AccessibleContext of this JPopupMenu
 1189        */
 1190       public AccessibleContext getAccessibleContext() {
 1191           if (accessibleContext == null) {
 1192               accessibleContext = new AccessibleJPopupMenu();
 1193           }
 1194           return accessibleContext;
 1195       }
 1196   
 1197       /**
 1198        * This class implements accessibility support for the
 1199        * <code>JPopupMenu</code> class.  It provides an implementation of the
 1200        * Java Accessibility API appropriate to popup menu user-interface
 1201        * elements.
 1202        */
 1203       protected class AccessibleJPopupMenu extends AccessibleJComponent
 1204           implements PropertyChangeListener {
 1205   
 1206           /**
 1207            * AccessibleJPopupMenu constructor
 1208            *
 1209            * @since 1.5
 1210            */
 1211           protected AccessibleJPopupMenu() {
 1212               JPopupMenu.this.addPropertyChangeListener(this);
 1213           }
 1214   
 1215           /**
 1216            * Get the role of this object.
 1217            *
 1218            * @return an instance of AccessibleRole describing the role of
 1219            * the object
 1220            */
 1221           public AccessibleRole getAccessibleRole() {
 1222               return AccessibleRole.POPUP_MENU;
 1223           }
 1224   
 1225           /**
 1226            * This method gets called when a bound property is changed.
 1227            * @param e A <code>PropertyChangeEvent</code> object describing
 1228            * the event source and the property that has changed. Must not be null.
 1229            *
 1230            * @throws NullPointerException if the parameter is null.
 1231            * @since 1.5
 1232            */
 1233           public void propertyChange(PropertyChangeEvent e) {
 1234               String propertyName = e.getPropertyName();
 1235               if (propertyName == "visible") {
 1236                   if (e.getOldValue() == Boolean.FALSE &&
 1237                       e.getNewValue() == Boolean.TRUE) {
 1238                       handlePopupIsVisibleEvent(true);
 1239   
 1240                   } else if (e.getOldValue() == Boolean.TRUE &&
 1241                              e.getNewValue() == Boolean.FALSE) {
 1242                       handlePopupIsVisibleEvent(false);
 1243                   }
 1244               }
 1245           }
 1246   
 1247           /*
 1248            * Handles popup "visible" PropertyChangeEvent
 1249            */
 1250           private void handlePopupIsVisibleEvent(boolean visible) {
 1251               if (visible) {
 1252                   // notify listeners that the popup became visible
 1253                   firePropertyChange(ACCESSIBLE_STATE_PROPERTY,
 1254                                      null, AccessibleState.VISIBLE);
 1255                   // notify listeners that a popup list item is selected
 1256                   fireActiveDescendant();
 1257               } else {
 1258                   // notify listeners that the popup became hidden
 1259                   firePropertyChange(ACCESSIBLE_STATE_PROPERTY,
 1260                                      AccessibleState.VISIBLE, null);
 1261               }
 1262           }
 1263   
 1264           /*
 1265            * Fires AccessibleActiveDescendant PropertyChangeEvent to notify listeners
 1266            * on the popup menu invoker that a popup list item has been selected
 1267            */
 1268           private void fireActiveDescendant() {
 1269               if (JPopupMenu.this instanceof BasicComboPopup) {
 1270                   // get the popup list
 1271                   JList popupList = ((BasicComboPopup)JPopupMenu.this).getList();
 1272                   if (popupList == null) {
 1273                       return;
 1274                   }
 1275   
 1276                   // get the first selected item
 1277                   AccessibleContext ac = popupList.getAccessibleContext();
 1278                   AccessibleSelection selection = ac.getAccessibleSelection();
 1279                   if (selection == null) {
 1280                       return;
 1281                   }
 1282                   Accessible a = selection.getAccessibleSelection(0);
 1283                   if (a == null) {
 1284                       return;
 1285                   }
 1286                   AccessibleContext selectedItem = a.getAccessibleContext();
 1287   
 1288                   // fire the event with the popup invoker as the source.
 1289                   if (selectedItem != null && invoker != null) {
 1290                       AccessibleContext invokerContext = invoker.getAccessibleContext();
 1291                       if (invokerContext != null) {
 1292                           // Check invokerContext because Component.getAccessibleContext
 1293                           // returns null. Classes that extend Component are responsible
 1294                           // for returning a non-null AccessibleContext.
 1295                           invokerContext.firePropertyChange(
 1296                               ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY,
 1297                               null, selectedItem);
 1298                       }
 1299                   }
 1300               }
 1301           }
 1302       } // inner class AccessibleJPopupMenu
 1303   
 1304   
 1305   ////////////
 1306   // Serialization support.
 1307   ////////////
 1308       private void writeObject(ObjectOutputStream s) throws IOException {
 1309           Vector<Object> values = new Vector<Object>();
 1310   
 1311           s.defaultWriteObject();
 1312           // Save the invoker, if its Serializable.
 1313           if(invoker != null && invoker instanceof Serializable) {
 1314               values.addElement("invoker");
 1315               values.addElement(invoker);
 1316           }
 1317           // Save the popup, if its Serializable.
 1318           if(popup != null && popup instanceof Serializable) {
 1319               values.addElement("popup");
 1320               values.addElement(popup);
 1321           }
 1322           s.writeObject(values);
 1323   
 1324           if (getUIClassID().equals(uiClassID)) {
 1325               byte count = JComponent.getWriteObjCounter(this);
 1326               JComponent.setWriteObjCounter(this, --count);
 1327               if (count == 0 && ui != null) {
 1328                   ui.installUI(this);
 1329               }
 1330           }
 1331       }
 1332   
 1333       // implements javax.swing.MenuElement
 1334       private void readObject(ObjectInputStream s)
 1335           throws IOException, ClassNotFoundException {
 1336           s.defaultReadObject();
 1337   
 1338           Vector          values = (Vector)s.readObject();
 1339           int             indexCounter = 0;
 1340           int             maxCounter = values.size();
 1341   
 1342           if(indexCounter < maxCounter && values.elementAt(indexCounter).
 1343              equals("invoker")) {
 1344               invoker = (Component)values.elementAt(++indexCounter);
 1345               indexCounter++;
 1346           }
 1347           if(indexCounter < maxCounter && values.elementAt(indexCounter).
 1348              equals("popup")) {
 1349               popup = (Popup)values.elementAt(++indexCounter);
 1350               indexCounter++;
 1351           }
 1352       }
 1353   
 1354   
 1355       /**
 1356        * This method is required to conform to the
 1357        * <code>MenuElement</code> interface, but it not implemented.
 1358        * @see MenuElement#processMouseEvent(MouseEvent, MenuElement[], MenuSelectionManager)
 1359        */
 1360       public void processMouseEvent(MouseEvent event,MenuElement path[],MenuSelectionManager manager) {}
 1361   
 1362       /**
 1363        * Processes a key event forwarded from the
 1364        * <code>MenuSelectionManager</code> and changes the menu selection,
 1365        * if necessary, by using <code>MenuSelectionManager</code>'s API.
 1366        * <p>
 1367        * Note: you do not have to forward the event to sub-components.
 1368        * This is done automatically by the <code>MenuSelectionManager</code>.
 1369        *
 1370        * @param e  a <code>KeyEvent</code>
 1371        * @param path the <code>MenuElement</code> path array
 1372        * @param manager   the <code>MenuSelectionManager</code>
 1373        */
 1374       public void processKeyEvent(KeyEvent e, MenuElement path[],
 1375                                   MenuSelectionManager manager) {
 1376           MenuKeyEvent mke = new MenuKeyEvent(e.getComponent(), e.getID(),
 1377                                                e.getWhen(), e.getModifiers(),
 1378                                                e.getKeyCode(), e.getKeyChar(),
 1379                                                path, manager);
 1380           processMenuKeyEvent(mke);
 1381   
 1382           if (mke.isConsumed())  {
 1383               e.consume();
 1384       }
 1385       }
 1386   
 1387       /**
 1388        * Handles a keystroke in a menu.
 1389        *
 1390        * @param e  a <code>MenuKeyEvent</code> object
 1391        * @since 1.5
 1392        */
 1393       private void processMenuKeyEvent(MenuKeyEvent e) {
 1394           switch (e.getID()) {
 1395           case KeyEvent.KEY_PRESSED:
 1396               fireMenuKeyPressed(e); break;
 1397           case KeyEvent.KEY_RELEASED:
 1398               fireMenuKeyReleased(e); break;
 1399           case KeyEvent.KEY_TYPED:
 1400               fireMenuKeyTyped(e); break;
 1401           default:
 1402               break;
 1403           }
 1404       }
 1405   
 1406       /**
 1407        * Notifies all listeners that have registered interest for
 1408        * notification on this event type.
 1409        *
 1410        * @param event a <code>MenuKeyEvent</code>
 1411        * @see EventListenerList
 1412        */
 1413       private void fireMenuKeyPressed(MenuKeyEvent event) {
 1414           Object[] listeners = listenerList.getListenerList();
 1415           for (int i = listeners.length-2; i>=0; i-=2) {
 1416               if (listeners[i]==MenuKeyListener.class) {
 1417                   ((MenuKeyListener)listeners[i+1]).menuKeyPressed(event);
 1418               }
 1419           }
 1420       }
 1421   
 1422       /**
 1423        * Notifies all listeners that have registered interest for
 1424        * notification on this event type.
 1425        *
 1426        * @param event a <code>MenuKeyEvent</code>
 1427        * @see EventListenerList
 1428        */
 1429       private void fireMenuKeyReleased(MenuKeyEvent event) {
 1430           Object[] listeners = listenerList.getListenerList();
 1431           for (int i = listeners.length-2; i>=0; i-=2) {
 1432               if (listeners[i]==MenuKeyListener.class) {
 1433                   ((MenuKeyListener)listeners[i+1]).menuKeyReleased(event);
 1434               }
 1435           }
 1436       }
 1437   
 1438       /**
 1439        * Notifies all listeners that have registered interest for
 1440        * notification on this event type.
 1441        *
 1442        * @param event a <code>MenuKeyEvent</code>
 1443        * @see EventListenerList
 1444        */
 1445       private void fireMenuKeyTyped(MenuKeyEvent event) {
 1446           Object[] listeners = listenerList.getListenerList();
 1447           for (int i = listeners.length-2; i>=0; i-=2) {
 1448               if (listeners[i]==MenuKeyListener.class) {
 1449                   ((MenuKeyListener)listeners[i+1]).menuKeyTyped(event);
 1450               }
 1451           }
 1452       }
 1453   
 1454       /**
 1455        * Messaged when the menubar selection changes to activate or
 1456        * deactivate this menu. This implements the
 1457        * <code>javax.swing.MenuElement</code> interface.
 1458        * Overrides <code>MenuElement.menuSelectionChanged</code>.
 1459        *
 1460        * @param isIncluded  true if this menu is active, false if
 1461        *        it is not
 1462        * @see MenuElement#menuSelectionChanged(boolean)
 1463        */
 1464       public void menuSelectionChanged(boolean isIncluded) {
 1465           if (DEBUG) {
 1466               System.out.println("In JPopupMenu.menuSelectionChanged " + isIncluded);
 1467           }
 1468           if(invoker instanceof JMenu) {
 1469               JMenu m = (JMenu) invoker;
 1470               if(isIncluded)
 1471                   m.setPopupMenuVisible(true);
 1472               else
 1473                   m.setPopupMenuVisible(false);
 1474           }
 1475           if (isPopupMenu() && !isIncluded)
 1476             setVisible(false);
 1477       }
 1478   
 1479       /**
 1480        * Returns an array of <code>MenuElement</code>s containing the submenu
 1481        * for this menu component.  It will only return items conforming to
 1482        * the <code>JMenuElement</code> interface.
 1483        * If popup menu is <code>null</code> returns
 1484        * an empty array.  This method is required to conform to the
 1485        * <code>MenuElement</code> interface.
 1486        *
 1487        * @return an array of <code>MenuElement</code> objects
 1488        * @see MenuElement#getSubElements
 1489        */
 1490       public MenuElement[] getSubElements() {
 1491           MenuElement result[];
 1492           Vector<MenuElement> tmp = new Vector<MenuElement>();
 1493           int c = getComponentCount();
 1494           int i;
 1495           Component m;
 1496   
 1497           for(i=0 ; i < c ; i++) {
 1498               m = getComponent(i);
 1499               if(m instanceof MenuElement)
 1500                   tmp.addElement((MenuElement) m);
 1501           }
 1502   
 1503           result = new MenuElement[tmp.size()];
 1504           for(i=0,c=tmp.size() ; i < c ; i++)
 1505               result[i] = tmp.elementAt(i);
 1506           return result;
 1507       }
 1508   
 1509       /**
 1510        * Returns this <code>JPopupMenu</code> component.
 1511        * @return this <code>JPopupMenu</code> object
 1512        * @see MenuElement#getComponent
 1513        */
 1514       public Component getComponent() {
 1515           return this;
 1516       }
 1517   
 1518   
 1519       /**
 1520        * A popup menu-specific separator.
 1521        */
 1522       static public class Separator extends JSeparator
 1523       {
 1524           public Separator( )
 1525           {
 1526               super( JSeparator.HORIZONTAL );
 1527           }
 1528   
 1529           /**
 1530            * Returns the name of the L&F class that renders this component.
 1531            *
 1532            * @return the string "PopupMenuSeparatorUI"
 1533            * @see JComponent#getUIClassID
 1534            * @see UIDefaults#getUI
 1535            */
 1536           public String getUIClassID()
 1537           {
 1538               return "PopupMenuSeparatorUI";
 1539   
 1540           }
 1541       }
 1542   
 1543       /**
 1544        * Returns true if the <code>MouseEvent</code> is considered a popup trigger
 1545        * by the <code>JPopupMenu</code>'s currently installed UI.
 1546        *
 1547        * @return true if the mouse event is a popup trigger
 1548        * @since 1.3
 1549        */
 1550       public boolean isPopupTrigger(MouseEvent e) {
 1551           return getUI().isPopupTrigger(e);
 1552       }
 1553   }

Home » openjdk-7 » javax » swing » [javadoc | source]