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

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