< prev index next >

src/java.desktop/share/classes/javax/swing/JPopupMenu.java

Print this page




  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 sun.awt.SunToolkit;
  46 import sun.security.util.SecurityConstants;
  47 
  48 import java.applet.Applet;
  49 
  50 /**
  51  * An implementation of a popup menu -- a small window that pops up
  52  * and displays a series of choices. A <code>JPopupMenu</code> is used for the
  53  * menu that appears when the user selects an item on the menu bar.
  54  * It is also used for "pull-right" menu that appears when the
  55  * selects a menu item that activates it. Finally, a <code>JPopupMenu</code>
  56  * can also be used anywhere else you want a menu to appear.  For
  57  * example, when the user right-clicks in a specified area.
  58  * <p>
  59  * For information and examples of using popup menus, see
  60  * <a
  61  href="http://docs.oracle.com/javase/tutorial/uiswing/components/menu.html">How to Use Menus</a>
  62  * in <em>The Java Tutorial.</em>
  63  * <p>
  64  * <strong>Warning:</strong> Swing is not thread safe. For more
  65  * information see <a
  66  * href="package-summary.html#threading">Swing's Threading
  67  * Policy</a>.
  68  * <p>
  69  * <strong>Warning:</strong>
  70  * Serialized objects of this class will not be compatible with
  71  * future Swing releases. The current serialization support is
  72  * appropriate for short term storage or RMI between applications running
  73  * the same version of Swing.  As of 1.4, support for long term storage
  74  * of all JavaBeans&trade;
  75  * has been added to the <code>java.beans</code> package.
  76  * Please see {@link java.beans.XMLEncoder}.
  77  *
  78  * @beaninfo
  79  *   attribute: isContainer false
  80  * description: A small window that pops up and displays a series of choices.
  81  *
  82  * @author Georges Saab
  83  * @author David Karlton
  84  * @author Arnaud Weber
  85  * @since 1.2
  86  */
  87 @SuppressWarnings("serial")
  88 public class JPopupMenu extends JComponent implements Accessible,MenuElement {
  89 
  90     /**
  91      * @see #getUIClassID
  92      * @see #readObject
  93      */
  94     private static final String uiClassID = "PopupMenuUI";
  95 


 122      * Used to indicate if lightweight popups should be used.
 123      */
 124     private    boolean   lightWeightPopup         = true;
 125 
 126     /*
 127      * Model for the selected subcontrol.
 128      */
 129     private SingleSelectionModel selectionModel;
 130 
 131     /* Lock object used in place of class object for synchronization.
 132      * (4187686)
 133      */
 134     private static final Object classLock = new Object();
 135 
 136     /* diagnostic aids -- should be false for production builds. */
 137     private static final boolean TRACE =   false; // trace creates and disposes
 138     private static final boolean VERBOSE = false; // show reuse hits/misses
 139     private static final boolean DEBUG =   false;  // show bad params, misc.
 140 
 141     /**
 142      *  Sets the default value of the <code>lightWeightPopupEnabled</code>
 143      *  property.
 144      *
 145      *  @param aFlag <code>true</code> if popups can be lightweight,
 146      *               otherwise <code>false</code>
 147      *  @see #getDefaultLightWeightPopupEnabled
 148      *  @see #setLightWeightPopupEnabled
 149      */
 150     public static void setDefaultLightWeightPopupEnabled(boolean aFlag) {
 151         SwingUtilities.appContextPut(defaultLWPopupEnabledKey,
 152                                      Boolean.valueOf(aFlag));
 153     }
 154 
 155     /**
 156      *  Gets the <code>defaultLightWeightPopupEnabled</code> property,
 157      *  which by default is <code>true</code>.
 158      *
 159      *  @return the value of the <code>defaultLightWeightPopupEnabled</code>
 160      *          property
 161      *
 162      *  @see #setDefaultLightWeightPopupEnabled
 163      */
 164     public static boolean getDefaultLightWeightPopupEnabled() {
 165         Boolean b = (Boolean)
 166             SwingUtilities.appContextGet(defaultLWPopupEnabledKey);
 167         if (b == null) {
 168             SwingUtilities.appContextPut(defaultLWPopupEnabledKey,
 169                                          Boolean.TRUE);
 170             return true;
 171         }
 172         return b.booleanValue();
 173     }
 174 
 175     /**
 176      * Constructs a <code>JPopupMenu</code> without an "invoker".
 177      */
 178     public JPopupMenu() {
 179         this(null);
 180     }
 181 
 182     /**
 183      * Constructs a <code>JPopupMenu</code> with the specified title.
 184      *
 185      * @param label  the string that a UI may use to display as a title
 186      * for the popup menu.
 187      */
 188     public JPopupMenu(String label) {
 189         this.label = label;
 190         lightWeightPopup = getDefaultLightWeightPopupEnabled();
 191         setSelectionModel(new DefaultSingleSelectionModel());
 192         enableEvents(AWTEvent.MOUSE_EVENT_MASK);
 193         setFocusTraversalKeysEnabled(false);
 194         updateUI();
 195     }
 196 
 197 
 198 
 199     /**
 200      * Returns the look and feel (L&amp;F) object that renders this component.
 201      *
 202      * @return the <code>PopupMenuUI</code> object that renders this component
 203      */
 204     public PopupMenuUI getUI() {
 205         return (PopupMenuUI)ui;
 206     }
 207 
 208     /**
 209      * Sets the L&amp;F object that renders this component.
 210      *
 211      * @param ui the new <code>PopupMenuUI</code> L&amp;F object
 212      * @see UIDefaults#getUI
 213      * @beaninfo
 214      *        bound: true
 215      *       hidden: true
 216      *    attribute: visualUpdate true
 217      *  description: The UI object that implements the Component's LookAndFeel.
 218      */
 219     public void setUI(PopupMenuUI ui) {
 220         super.setUI(ui);
 221     }
 222 
 223     /**
 224      * Resets the UI property to a value from the current look and feel.
 225      *
 226      * @see JComponent#updateUI
 227      */
 228     public void updateUI() {
 229         setUI((PopupMenuUI)UIManager.getUI(this));
 230     }
 231 


 245         super.processFocusEvent(evt);
 246     }
 247 
 248     /**
 249      * Processes key stroke events such as mnemonics and accelerators.
 250      *
 251      * @param evt  the key event to be processed
 252      */
 253     protected void processKeyEvent(KeyEvent evt) {
 254         MenuSelectionManager.defaultManager().processKeyEvent(evt);
 255         if (evt.isConsumed()) {
 256             return;
 257         }
 258         super.processKeyEvent(evt);
 259     }
 260 
 261 
 262     /**
 263      * Returns the model object that handles single selections.
 264      *
 265      * @return the <code>selectionModel</code> property
 266      * @see SingleSelectionModel
 267      */
 268     public SingleSelectionModel getSelectionModel() {
 269         return selectionModel;
 270     }
 271 
 272     /**
 273      * Sets the model object to handle single selections.
 274      *
 275      * @param model the new <code>SingleSelectionModel</code>
 276      * @see SingleSelectionModel
 277      * @beaninfo
 278      * description: The selection model for the popup menu
 279      *      expert: true
 280      */
 281     public void setSelectionModel(SingleSelectionModel model) {
 282         selectionModel = model;
 283     }
 284 
 285     /**
 286      * Appends the specified menu item to the end of this menu.
 287      *
 288      * @param menuItem the <code>JMenuItem</code> to add
 289      * @return the <code>JMenuItem</code> added
 290      */
 291     public JMenuItem add(JMenuItem menuItem) {
 292         super.add(menuItem);
 293         return menuItem;
 294     }
 295 
 296     /**
 297      * Creates a new menu item with the specified text and appends
 298      * it to the end of this menu.
 299      *
 300      * @param s the string for the menu item to be added
 301      * @return a new {@code JMenuItem} created using {@code s}
 302      */
 303     public JMenuItem add(String s) {
 304         return add(new JMenuItem(s));
 305     }
 306 
 307     /**
 308      * Appends a new menu item to the end of the menu which
 309      * dispatches the specified <code>Action</code> object.
 310      *
 311      * @param a the <code>Action</code> to add to the menu
 312      * @return the new menu item
 313      * @see Action
 314      */
 315     public JMenuItem add(Action a) {
 316         JMenuItem mi = createActionComponent(a);
 317         mi.setAction(a);
 318         add(mi);
 319         return mi;
 320     }
 321 
 322     /**
 323      * Returns an point which has been adjusted to take into account of the
 324      * desktop bounds, taskbar and multi-monitor configuration.
 325      * <p>
 326      * This adustment may be cancelled by invoking the application with
 327      * -Djavax.swing.adjustPopupLocationToFit=false
 328      */
 329     Point adjustPopupLocationToFitScreen(int xPosition, int yPosition) {
 330         Point popupLocation = new Point(xPosition, yPosition);
 331 


 409             gc = getInvoker().getGraphicsConfiguration();
 410         }
 411         return gc;
 412     }
 413 
 414     /**
 415      * Returns whether popup is allowed to be shown above the task bar.
 416      */
 417     static boolean canPopupOverlapTaskBar() {
 418         boolean result = true;
 419 
 420         Toolkit tk = Toolkit.getDefaultToolkit();
 421         if (tk instanceof SunToolkit) {
 422             result = ((SunToolkit)tk).canPopupOverlapTaskBar();
 423         }
 424 
 425         return result;
 426     }
 427 
 428     /**
 429      * Factory method which creates the <code>JMenuItem</code> for
 430      * <code>Actions</code> added to the <code>JPopupMenu</code>.
 431      *
 432      * @param a the <code>Action</code> for the menu item to be added
 433      * @return the new menu item
 434      * @see Action
 435      *
 436      * @since 1.3
 437      */
 438     protected JMenuItem createActionComponent(Action a) {
 439         JMenuItem mi = new JMenuItem() {
 440             protected PropertyChangeListener createActionPropertyChangeListener(Action a) {
 441                 PropertyChangeListener pcl = createActionChangeListener(this);
 442                 if (pcl == null) {
 443                     pcl = super.createActionPropertyChangeListener(a);
 444                 }
 445                 return pcl;
 446             }
 447         };
 448         mi.setHorizontalTextPosition(JButton.TRAILING);
 449         mi.setVerticalTextPosition(JButton.CENTER);
 450         return mi;
 451     }
 452 
 453     /**
 454      * Returns a properly configured <code>PropertyChangeListener</code>
 455      * which updates the control as changes to the <code>Action</code> occur.
 456      *
 457      * @param b the menu item for which to create a listener
 458      * @return a properly configured {@code PropertyChangeListener}
 459      */
 460     protected PropertyChangeListener createActionChangeListener(JMenuItem b) {
 461         return b.createActionPropertyChangeListener0(b.getAction());
 462     }
 463 
 464     /**
 465      * Removes the component at the specified index from this popup menu.
 466      *
 467      * @param       pos the position of the item to be removed
 468      * @exception   IllegalArgumentException if the value of
 469      *                          <code>pos</code> &lt; 0, or if the value of
 470      *                          <code>pos</code> is greater than the
 471      *                          number of items
 472      */
 473     public void remove(int pos) {
 474         if (pos < 0) {
 475             throw new IllegalArgumentException("index less than zero.");
 476         }
 477         if (pos > getComponentCount() -1) {
 478             throw new IllegalArgumentException("index greater than the number of items.");
 479         }
 480         super.remove(pos);
 481     }
 482 
 483     /**
 484      * Sets the value of the <code>lightWeightPopupEnabled</code> property,
 485      * which by default is <code>true</code>.
 486      * By default, when a look and feel displays a popup,
 487      * it can choose to
 488      * use a lightweight (all-Java) popup.
 489      * Lightweight popup windows are more efficient than heavyweight
 490      * (native peer) windows,
 491      * but lightweight and heavyweight components do not mix well in a GUI.
 492      * If your application mixes lightweight and heavyweight components,
 493      * you should disable lightweight popups.
 494      * Some look and feels might always use heavyweight popups,
 495      * no matter what the value of this property.
 496      *
 497      * @param aFlag  <code>false</code> to disable lightweight popups
 498      * @beaninfo
 499      * description: Determines whether lightweight popups are used when possible
 500      *      expert: true
 501      *
 502      * @see #isLightWeightPopupEnabled
 503      */
 504     public void setLightWeightPopupEnabled(boolean aFlag) {
 505         // NOTE: this use to set the flag on a shared JPopupMenu, which meant
 506         // this effected ALL JPopupMenus.
 507         lightWeightPopup = aFlag;
 508     }
 509 
 510     /**
 511      * Gets the <code>lightWeightPopupEnabled</code> property.
 512      *
 513      * @return the value of the <code>lightWeightPopupEnabled</code> property
 514      * @see #setLightWeightPopupEnabled
 515      */
 516     public boolean isLightWeightPopupEnabled() {
 517         return lightWeightPopup;
 518     }
 519 
 520     /**
 521      * Returns the popup menu's label
 522      *
 523      * @return a string containing the popup menu's label
 524      * @see #setLabel
 525      */
 526     public String getLabel() {
 527         return label;
 528     }
 529 
 530     /**
 531      * Sets the popup menu's label.  Different look and feels may choose
 532      * to display or not display this.
 533      *


 542         String oldValue = this.label;
 543         this.label = label;
 544         firePropertyChange("label", oldValue, label);
 545         if (accessibleContext != null) {
 546             accessibleContext.firePropertyChange(
 547                 AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
 548                 oldValue, label);
 549         }
 550         invalidate();
 551         repaint();
 552     }
 553 
 554     /**
 555      * Appends a new separator at the end of the menu.
 556      */
 557     public void addSeparator() {
 558         add( new JPopupMenu.Separator() );
 559     }
 560 
 561     /**
 562      * Inserts a menu item for the specified <code>Action</code> object at
 563      * a given position.
 564      *
 565      * @param a  the <code>Action</code> object to insert
 566      * @param index      specifies the position at which to insert the
 567      *                   <code>Action</code>, where 0 is the first
 568      * @exception IllegalArgumentException if <code>index</code> &lt; 0
 569      * @see Action
 570      */
 571     public void insert(Action a, int index) {
 572         JMenuItem mi = createActionComponent(a);
 573         mi.setAction(a);
 574         insert(mi, index);
 575     }
 576 
 577     /**
 578      * Inserts the specified component into the menu at a given
 579      * position.
 580      *
 581      * @param component  the <code>Component</code> to insert
 582      * @param index      specifies the position at which
 583      *                   to insert the component, where 0 is the first
 584      * @exception IllegalArgumentException if <code>index</code> &lt; 0
 585      */
 586     public void insert(Component component, int index) {
 587         if (index < 0) {
 588             throw new IllegalArgumentException("index less than zero.");
 589         }
 590 
 591         int nitems = getComponentCount();
 592         // PENDING(ges): Why not use an array?
 593         Vector<Component> tempItems = new Vector<Component>();
 594 
 595         /* Remove the item at index, nitems-index times
 596            storing them in a temporary vector in the
 597            order they appear on the menu.
 598            */
 599         for (int i = index ; i < nitems; i++) {
 600             tempItems.addElement(getComponent(index));
 601             remove(index);
 602         }
 603 
 604         add(component);
 605 
 606         /* Add the removed items back to the menu, they are
 607            already in the correct order in the temp vector.
 608            */
 609         for (Component tempItem : tempItems) {
 610             add(tempItem);
 611         }
 612     }
 613 
 614     /**
 615      *  Adds a <code>PopupMenu</code> listener.
 616      *
 617      *  @param l  the <code>PopupMenuListener</code> to add
 618      */
 619     public void addPopupMenuListener(PopupMenuListener l) {
 620         listenerList.add(PopupMenuListener.class,l);
 621     }
 622 
 623     /**
 624      * Removes a <code>PopupMenu</code> listener.
 625      *
 626      * @param l  the <code>PopupMenuListener</code> to remove
 627      */
 628     public void removePopupMenuListener(PopupMenuListener l) {
 629         listenerList.remove(PopupMenuListener.class,l);
 630     }
 631 
 632     /**
 633      * Returns an array of all the <code>PopupMenuListener</code>s added
 634      * to this JMenuItem with addPopupMenuListener().
 635      *
 636      * @return all of the <code>PopupMenuListener</code>s added or an empty
 637      *         array if no listeners have been added
 638      * @since 1.4
 639      */
 640     public PopupMenuListener[] getPopupMenuListeners() {
 641         return listenerList.getListeners(PopupMenuListener.class);
 642     }
 643 
 644     /**
 645      * Adds a <code>MenuKeyListener</code> to the popup menu.
 646      *
 647      * @param l the <code>MenuKeyListener</code> to be added
 648      * @since 1.5
 649      */
 650     public void addMenuKeyListener(MenuKeyListener l) {
 651         listenerList.add(MenuKeyListener.class, l);
 652     }
 653 
 654     /**
 655      * Removes a <code>MenuKeyListener</code> from the popup menu.
 656      *
 657      * @param l the <code>MenuKeyListener</code> to be removed
 658      * @since 1.5
 659      */
 660     public void removeMenuKeyListener(MenuKeyListener l) {
 661         listenerList.remove(MenuKeyListener.class, l);
 662     }
 663 
 664     /**
 665      * Returns an array of all the <code>MenuKeyListener</code>s added
 666      * to this JPopupMenu with addMenuKeyListener().
 667      *
 668      * @return all of the <code>MenuKeyListener</code>s added or an empty
 669      *         array if no listeners have been added
 670      * @since 1.5
 671      */
 672     public MenuKeyListener[] getMenuKeyListeners() {
 673         return listenerList.getListeners(MenuKeyListener.class);
 674     }
 675 
 676     /**
 677      * Notifies <code>PopupMenuListener</code>s that this popup menu will
 678      * become visible.
 679      */
 680     protected void firePopupMenuWillBecomeVisible() {
 681         Object[] listeners = listenerList.getListenerList();
 682         PopupMenuEvent e=null;
 683         for (int i = listeners.length-2; i>=0; i-=2) {
 684             if (listeners[i]==PopupMenuListener.class) {
 685                 if (e == null)
 686                     e = new PopupMenuEvent(this);
 687                 ((PopupMenuListener)listeners[i+1]).popupMenuWillBecomeVisible(e);
 688             }
 689         }
 690     }
 691 
 692     /**
 693      * Notifies <code>PopupMenuListener</code>s that this popup menu will
 694      * become invisible.
 695      */
 696     protected void firePopupMenuWillBecomeInvisible() {
 697         Object[] listeners = listenerList.getListenerList();
 698         PopupMenuEvent e=null;
 699         for (int i = listeners.length-2; i>=0; i-=2) {
 700             if (listeners[i]==PopupMenuListener.class) {
 701                 if (e == null)
 702                     e = new PopupMenuEvent(this);
 703                 ((PopupMenuListener)listeners[i+1]).popupMenuWillBecomeInvisible(e);
 704             }
 705         }
 706     }
 707 
 708     /**
 709      * Notifies <code>PopupMenuListeners</code> that this popup menu is
 710      * cancelled.
 711      */
 712     protected void firePopupMenuCanceled() {
 713         Object[] listeners = listenerList.getListenerList();
 714         PopupMenuEvent e=null;
 715         for (int i = listeners.length-2; i>=0; i-=2) {
 716             if (listeners[i]==PopupMenuListener.class) {
 717                 if (e == null)
 718                     e = new PopupMenuEvent(this);
 719                 ((PopupMenuListener)listeners[i+1]).popupMenuCanceled(e);
 720             }
 721         }
 722     }
 723 
 724     /**
 725      * Always returns true since popups, by definition, should always
 726      * be on top of all other windows.
 727      * @return true
 728      */
 729     // package private


 793         if(b) {
 794             firePopupMenuWillBecomeVisible();
 795             showPopup();
 796             firePropertyChange("visible", Boolean.FALSE, Boolean.TRUE);
 797 
 798 
 799         } else if(popup != null) {
 800             firePopupMenuWillBecomeInvisible();
 801             popup.hide();
 802             popup = null;
 803             firePropertyChange("visible", Boolean.TRUE, Boolean.FALSE);
 804             // 4694797: When popup menu is made invisible, selected path
 805             // should be cleared
 806             if (isPopupMenu()) {
 807                 MenuSelectionManager.defaultManager().clearSelectedPath();
 808             }
 809         }
 810     }
 811 
 812     /**
 813      * Retrieves <code>Popup</code> instance from the
 814      * <code>PopupMenuUI</code> that has had <code>show</code> invoked on
 815      * it. If the current <code>popup</code> is non-null,
 816      * this will invoke <code>dispose</code> of it, and then
 817      * <code>show</code> the new one.
 818      * <p>
 819      * This does NOT fire any events, it is up the caller to dispatch
 820      * the necessary events.
 821      */
 822     private void showPopup() {
 823         Popup oldPopup = popup;
 824 
 825         if (oldPopup != null) {
 826             oldPopup.hide();
 827         }
 828         PopupFactory popupFactory = PopupFactory.getSharedInstance();
 829 
 830         if (isLightWeightPopupEnabled()) {
 831             popupFactory.setPopupType(PopupFactory.LIGHT_WEIGHT_POPUP);
 832         }
 833         else {
 834             popupFactory.setPopupType(PopupFactory.HEAVY_WEIGHT_POPUP);
 835         }
 836 
 837         // adjust the location of the popup


 867      * @param x the x coordinate of the popup's new position
 868      *          in the screen's coordinate space
 869      * @param y the y coordinate of the popup's new position
 870      *          in the screen's coordinate space
 871      * @beaninfo
 872      * description: The location of the popup menu.
 873      */
 874     public void setLocation(int x, int y) {
 875         int oldX = desiredLocationX;
 876         int oldY = desiredLocationY;
 877 
 878         desiredLocationX = x;
 879         desiredLocationY = y;
 880         if(popup != null && (x != oldX || y != oldY)) {
 881             showPopup();
 882         }
 883     }
 884 
 885     /**
 886      * Returns true if the popup menu is a standalone popup menu
 887      * rather than the submenu of a <code>JMenu</code>.
 888      *
 889      * @return true if this menu is a standalone popup menu, otherwise false
 890      */
 891     private boolean isPopupMenu() {
 892         return  ((invoker != null) && !(invoker instanceof JMenu));
 893     }
 894 
 895     /**
 896      * Returns the component which is the 'invoker' of this
 897      * popup menu.
 898      *
 899      * @return the <code>Component</code> in which the popup menu is displayed
 900      */
 901     public Component getInvoker() {
 902         return this.invoker;
 903     }
 904 
 905     /**
 906      * Sets the invoker of this popup menu -- the component in which
 907      * the popup menu menu is to be displayed.
 908      *
 909      * @param invoker the <code>Component</code> in which the popup
 910      *          menu is displayed
 911      * @beaninfo
 912      * description: The invoking component for the popup menu
 913      *      expert: true
 914      */
 915     public void setInvoker(Component invoker) {
 916         Component oldInvoker = this.invoker;
 917         this.invoker = invoker;
 918         if ((oldInvoker != this.invoker) && (ui != null)) {
 919             ui.uninstallUI(this);
 920             ui.installUI(this);
 921         }
 922         invalidate();
 923     }
 924 
 925     /**
 926      * Displays the popup menu at the position x,y in the coordinate
 927      * space of the component invoker.
 928      *
 929      * @param invoker the component in whose space the popup menu is to appear


 957             lx = ((long) invokerOrigin.x) +
 958                  ((long) x);
 959             ly = ((long) invokerOrigin.y) +
 960                  ((long) y);
 961             if(lx > Integer.MAX_VALUE) lx = Integer.MAX_VALUE;
 962             if(lx < Integer.MIN_VALUE) lx = Integer.MIN_VALUE;
 963             if(ly > Integer.MAX_VALUE) ly = Integer.MAX_VALUE;
 964             if(ly < Integer.MIN_VALUE) ly = Integer.MIN_VALUE;
 965 
 966             setLocation((int) lx, (int) ly);
 967         } else {
 968             setLocation(x, y);
 969         }
 970         setVisible(true);
 971     }
 972 
 973     /**
 974      * Returns the popup menu which is at the root of the menu system
 975      * for this popup menu.
 976      *
 977      * @return the topmost grandparent <code>JPopupMenu</code>
 978      */
 979     JPopupMenu getRootPopupMenu() {
 980         JPopupMenu mp = this;
 981         while((mp!=null) && (mp.isPopupMenu()!=true) &&
 982               (mp.getInvoker() != null) &&
 983               (mp.getInvoker().getParent() != null) &&
 984               (mp.getInvoker().getParent() instanceof JPopupMenu)
 985               ) {
 986             mp = (JPopupMenu) mp.getInvoker().getParent();
 987         }
 988         return mp;
 989     }
 990 
 991     /**
 992      * Returns the component at the specified index.
 993      *
 994      * @param i  the index of the component, where 0 is the first
 995      * @return the <code>Component</code> at that index
 996      * @deprecated replaced by {@link java.awt.Container#getComponent(int)}
 997      */
 998     @Deprecated
 999     public Component getComponentAtIndex(int i) {
1000         return getComponent(i);
1001     }
1002 
1003     /**
1004      * Returns the index of the specified component.
1005      *
1006      * @param  c the <code>Component</code> to find
1007      * @return the index of the component, where 0 is the first;
1008      *         or -1 if the component is not found
1009      */
1010     public int getComponentIndex(Component c) {
1011         int ncomponents = this.getComponentCount();
1012         Component[] component = this.getComponents();
1013         for (int i = 0 ; i < ncomponents ; i++) {
1014             Component comp = component[i];
1015             if (comp == c)
1016                 return i;
1017         }
1018         return -1;
1019     }
1020 
1021     /**
1022      * Sets the size of the Popup window using a <code>Dimension</code> object.
1023      * This is equivalent to <code>setPreferredSize(d)</code>.
1024      *
1025      * @param d   the <code>Dimension</code> specifying the new size
1026      * of this component.
1027      * @beaninfo
1028      * description: The size of the popup menu
1029      */
1030     public void setPopupSize(Dimension d) {
1031         Dimension oldSize = getPreferredSize();
1032 
1033         setPreferredSize(d);
1034         if (popup != null) {
1035             Dimension newSize = getPreferredSize();
1036 
1037             if (!oldSize.equals(newSize)) {
1038                 showPopup();
1039             }
1040         }
1041     }
1042 
1043     /**
1044      * Sets the size of the Popup window to the specified width and
1045      * height. This is equivalent to
1046      *  <code>setPreferredSize(new Dimension(width, height))</code>.
1047      *
1048      * @param width the new width of the Popup in pixels
1049      * @param height the new height of the Popup in pixels
1050      * @beaninfo
1051      * description: The size of the popup menu
1052      */
1053     public void setPopupSize(int width, int height) {
1054         setPopupSize(new Dimension(width, height));
1055     }
1056 
1057     /**
1058      * Sets the currently selected component,  This will result
1059      * in a change to the selection model.
1060      *
1061      * @param sel the <code>Component</code> to select
1062      * @beaninfo
1063      * description: The selected component on the popup menu
1064      *      expert: true
1065      *      hidden: true
1066      */
1067     public void setSelected(Component sel) {
1068         SingleSelectionModel model = getSelectionModel();
1069         int index = getComponentIndex(sel);
1070         model.setSelectedIndex(index);
1071     }
1072 
1073     /**
1074      * Checks whether the border should be painted.
1075      *
1076      * @return true if the border is painted, false otherwise
1077      * @see #setBorderPainted
1078      */
1079     public boolean isBorderPainted() {
1080         return paintBorder;
1081     }
1082 
1083     /**
1084      * Sets whether the border should be painted.
1085      *
1086      * @param b if true, the border is painted.
1087      * @see #isBorderPainted
1088      * @beaninfo
1089      * description: Is the border of the popup menu painted
1090      */
1091     public void setBorderPainted(boolean b) {
1092         paintBorder = b;
1093         repaint();
1094     }
1095 
1096     /**
1097      * Paints the popup menu's border if the <code>borderPainted</code>
1098      * property is <code>true</code>.
1099      * @param g  the <code>Graphics</code> object
1100      *
1101      * @see JComponent#paint
1102      * @see JComponent#setBorder
1103      */
1104     protected void paintBorder(Graphics g) {
1105         if (isBorderPainted()) {
1106             super.paintBorder(g);
1107         }
1108     }
1109 
1110     /**
1111      * Returns the margin, in pixels, between the popup menu's border and
1112      * its containers.
1113      *
1114      * @return an <code>Insets</code> object containing the margin values.
1115      */
1116     public Insets getMargin() {
1117         if(margin == null) {
1118             return new Insets(0,0,0,0);
1119         } else {
1120             return margin;
1121         }
1122     }
1123 
1124 
1125     /**
1126      * Examines the list of menu items to determine whether
1127      * <code>popup</code> is a popup menu.
1128      *
1129      * @param popup  a <code>JPopupMenu</code>
1130      * @return true if <code>popup</code>
1131      */
1132     boolean isSubPopupMenu(JPopupMenu popup) {
1133         int ncomponents = this.getComponentCount();
1134         Component[] component = this.getComponents();
1135         for (int i = 0 ; i < ncomponents ; i++) {
1136             Component comp = component[i];
1137             if (comp instanceof JMenu) {
1138                 JMenu menu = (JMenu)comp;
1139                 JPopupMenu subPopup = menu.getPopupMenu();
1140                 if (subPopup == popup)
1141                     return true;
1142                 if (subPopup.isSubPopupMenu(popup))
1143                     return true;
1144             }
1145         }
1146         return false;
1147     }
1148 
1149 
1150     private static Frame getFrame(Component c) {
1151         Component w = c;
1152 
1153         while(!(w instanceof Frame) && (w!=null)) {
1154             w = w.getParent();
1155         }
1156         return (Frame)w;
1157     }
1158 
1159 
1160     /**
1161      * Returns a string representation of this <code>JPopupMenu</code>.
1162      * This method
1163      * is intended to be used only for debugging purposes, and the
1164      * content and format of the returned string may vary between
1165      * implementations. The returned string may be empty but may not
1166      * be <code>null</code>.
1167      *
1168      * @return  a string representation of this <code>JPopupMenu</code>.
1169      */
1170     protected String paramString() {
1171         String labelString = (label != null ?
1172                               label : "");
1173         String paintBorderString = (paintBorder ?
1174                                     "true" : "false");
1175         String marginString = (margin != null ?
1176                               margin.toString() : "");
1177         String lightWeightPopupEnabledString = (isLightWeightPopupEnabled() ?
1178                                                 "true" : "false");
1179         return super.paramString() +
1180             ",desiredLocationX=" + desiredLocationX +
1181             ",desiredLocationY=" + desiredLocationY +
1182         ",label=" + labelString +
1183         ",lightWeightPopupEnabled=" + lightWeightPopupEnabledString +
1184         ",margin=" + marginString +
1185         ",paintBorder=" + paintBorderString;
1186     }
1187 
1188 /////////////////


1190 ////////////////
1191 
1192     /**
1193      * Gets the AccessibleContext associated with this JPopupMenu.
1194      * For JPopupMenus, the AccessibleContext takes the form of an
1195      * AccessibleJPopupMenu.
1196      * A new AccessibleJPopupMenu instance is created if necessary.
1197      *
1198      * @return an AccessibleJPopupMenu that serves as the
1199      *         AccessibleContext of this JPopupMenu
1200      */
1201     public AccessibleContext getAccessibleContext() {
1202         if (accessibleContext == null) {
1203             accessibleContext = new AccessibleJPopupMenu();
1204         }
1205         return accessibleContext;
1206     }
1207 
1208     /**
1209      * This class implements accessibility support for the
1210      * <code>JPopupMenu</code> class.  It provides an implementation of the
1211      * Java Accessibility API appropriate to popup menu user-interface
1212      * elements.
1213      */
1214     @SuppressWarnings("serial")
1215     protected class AccessibleJPopupMenu extends AccessibleJComponent
1216         implements PropertyChangeListener {
1217 
1218         /**
1219          * AccessibleJPopupMenu constructor
1220          *
1221          * @since 1.5
1222          */
1223         protected AccessibleJPopupMenu() {
1224             JPopupMenu.this.addPropertyChangeListener(this);
1225         }
1226 
1227         /**
1228          * Get the role of this object.
1229          *
1230          * @return an instance of AccessibleRole describing the role of
1231          * the object
1232          */
1233         public AccessibleRole getAccessibleRole() {
1234             return AccessibleRole.POPUP_MENU;
1235         }
1236 
1237         /**
1238          * This method gets called when a bound property is changed.
1239          * @param e A <code>PropertyChangeEvent</code> object describing
1240          * the event source and the property that has changed. Must not be null.
1241          *
1242          * @throws NullPointerException if the parameter is null.
1243          * @since 1.5
1244          */
1245         public void propertyChange(PropertyChangeEvent e) {
1246             String propertyName = e.getPropertyName();
1247             if (propertyName == "visible") {
1248                 if (e.getOldValue() == Boolean.FALSE &&
1249                     e.getNewValue() == Boolean.TRUE) {
1250                     handlePopupIsVisibleEvent(true);
1251 
1252                 } else if (e.getOldValue() == Boolean.TRUE &&
1253                            e.getNewValue() == Boolean.FALSE) {
1254                     handlePopupIsVisibleEvent(false);
1255                 }
1256             }
1257         }
1258 
1259         /*


1362 
1363         Vector<?>          values = (Vector)s.readObject();
1364         int             indexCounter = 0;
1365         int             maxCounter = values.size();
1366 
1367         if(indexCounter < maxCounter && values.elementAt(indexCounter).
1368            equals("invoker")) {
1369             invoker = (Component)values.elementAt(++indexCounter);
1370             indexCounter++;
1371         }
1372         if(indexCounter < maxCounter && values.elementAt(indexCounter).
1373            equals("popup")) {
1374             popup = (Popup)values.elementAt(++indexCounter);
1375             indexCounter++;
1376         }
1377     }
1378 
1379 
1380     /**
1381      * This method is required to conform to the
1382      * <code>MenuElement</code> interface, but it not implemented.
1383      * @see MenuElement#processMouseEvent(MouseEvent, MenuElement[], MenuSelectionManager)
1384      */
1385     public void processMouseEvent(MouseEvent event,MenuElement path[],MenuSelectionManager manager) {}
1386 
1387     /**
1388      * Processes a key event forwarded from the
1389      * <code>MenuSelectionManager</code> and changes the menu selection,
1390      * if necessary, by using <code>MenuSelectionManager</code>'s API.
1391      * <p>
1392      * Note: you do not have to forward the event to sub-components.
1393      * This is done automatically by the <code>MenuSelectionManager</code>.
1394      *
1395      * @param e  a <code>KeyEvent</code>
1396      * @param path the <code>MenuElement</code> path array
1397      * @param manager   the <code>MenuSelectionManager</code>
1398      */
1399     public void processKeyEvent(KeyEvent e, MenuElement path[],
1400                                 MenuSelectionManager manager) {
1401         MenuKeyEvent mke = new MenuKeyEvent(e.getComponent(), e.getID(),
1402                                              e.getWhen(), e.getModifiers(),
1403                                              e.getKeyCode(), e.getKeyChar(),
1404                                              path, manager);
1405         processMenuKeyEvent(mke);
1406 
1407         if (mke.isConsumed())  {
1408             e.consume();
1409     }
1410     }
1411 
1412     /**
1413      * Handles a keystroke in a menu.
1414      *
1415      * @param e  a <code>MenuKeyEvent</code> object
1416      * @since 1.5
1417      */
1418     private void processMenuKeyEvent(MenuKeyEvent e) {
1419         switch (e.getID()) {
1420         case KeyEvent.KEY_PRESSED:
1421             fireMenuKeyPressed(e); break;
1422         case KeyEvent.KEY_RELEASED:
1423             fireMenuKeyReleased(e); break;
1424         case KeyEvent.KEY_TYPED:
1425             fireMenuKeyTyped(e); break;
1426         default:
1427             break;
1428         }
1429     }
1430 
1431     /**
1432      * Notifies all listeners that have registered interest for
1433      * notification on this event type.
1434      *
1435      * @param event a <code>MenuKeyEvent</code>
1436      * @see EventListenerList
1437      */
1438     private void fireMenuKeyPressed(MenuKeyEvent event) {
1439         Object[] listeners = listenerList.getListenerList();
1440         for (int i = listeners.length-2; i>=0; i-=2) {
1441             if (listeners[i]==MenuKeyListener.class) {
1442                 ((MenuKeyListener)listeners[i+1]).menuKeyPressed(event);
1443             }
1444         }
1445     }
1446 
1447     /**
1448      * Notifies all listeners that have registered interest for
1449      * notification on this event type.
1450      *
1451      * @param event a <code>MenuKeyEvent</code>
1452      * @see EventListenerList
1453      */
1454     private void fireMenuKeyReleased(MenuKeyEvent event) {
1455         Object[] listeners = listenerList.getListenerList();
1456         for (int i = listeners.length-2; i>=0; i-=2) {
1457             if (listeners[i]==MenuKeyListener.class) {
1458                 ((MenuKeyListener)listeners[i+1]).menuKeyReleased(event);
1459             }
1460         }
1461     }
1462 
1463     /**
1464      * Notifies all listeners that have registered interest for
1465      * notification on this event type.
1466      *
1467      * @param event a <code>MenuKeyEvent</code>
1468      * @see EventListenerList
1469      */
1470     private void fireMenuKeyTyped(MenuKeyEvent event) {
1471         Object[] listeners = listenerList.getListenerList();
1472         for (int i = listeners.length-2; i>=0; i-=2) {
1473             if (listeners[i]==MenuKeyListener.class) {
1474                 ((MenuKeyListener)listeners[i+1]).menuKeyTyped(event);
1475             }
1476         }
1477     }
1478 
1479     /**
1480      * Messaged when the menubar selection changes to activate or
1481      * deactivate this menu. This implements the
1482      * <code>javax.swing.MenuElement</code> interface.
1483      * Overrides <code>MenuElement.menuSelectionChanged</code>.
1484      *
1485      * @param isIncluded  true if this menu is active, false if
1486      *        it is not
1487      * @see MenuElement#menuSelectionChanged(boolean)
1488      */
1489     public void menuSelectionChanged(boolean isIncluded) {
1490         if (DEBUG) {
1491             System.out.println("In JPopupMenu.menuSelectionChanged " + isIncluded);
1492         }
1493         if(invoker instanceof JMenu) {
1494             JMenu m = (JMenu) invoker;
1495             if(isIncluded)
1496                 m.setPopupMenuVisible(true);
1497             else
1498                 m.setPopupMenuVisible(false);
1499         }
1500         if (isPopupMenu() && !isIncluded)
1501           setVisible(false);
1502     }
1503 
1504     /**
1505      * Returns an array of <code>MenuElement</code>s containing the submenu
1506      * for this menu component.  It will only return items conforming to
1507      * the <code>JMenuElement</code> interface.
1508      * If popup menu is <code>null</code> returns
1509      * an empty array.  This method is required to conform to the
1510      * <code>MenuElement</code> interface.
1511      *
1512      * @return an array of <code>MenuElement</code> objects
1513      * @see MenuElement#getSubElements
1514      */
1515     public MenuElement[] getSubElements() {
1516         MenuElement result[];
1517         Vector<MenuElement> tmp = new Vector<MenuElement>();
1518         int c = getComponentCount();
1519         int i;
1520         Component m;
1521 
1522         for(i=0 ; i < c ; i++) {
1523             m = getComponent(i);
1524             if(m instanceof MenuElement)
1525                 tmp.addElement((MenuElement) m);
1526         }
1527 
1528         result = new MenuElement[tmp.size()];
1529         for(i=0,c=tmp.size() ; i < c ; i++)
1530             result[i] = tmp.elementAt(i);
1531         return result;
1532     }
1533 
1534     /**
1535      * Returns this <code>JPopupMenu</code> component.
1536      * @return this <code>JPopupMenu</code> object
1537      * @see MenuElement#getComponent
1538      */
1539     public Component getComponent() {
1540         return this;
1541     }
1542 
1543 
1544     /**
1545      * A popup menu-specific separator.
1546      */
1547     @SuppressWarnings("serial")
1548     public static class Separator extends JSeparator
1549     {
1550         /**
1551          * Constructs a popup menu-specific Separator.
1552          */
1553         public Separator( )
1554         {
1555             super( JSeparator.HORIZONTAL );
1556         }
1557 
1558         /**
1559          * Returns the name of the L&amp;F class that renders this component.
1560          *
1561          * @return the string "PopupMenuSeparatorUI"
1562          * @see JComponent#getUIClassID
1563          * @see UIDefaults#getUI
1564          */
1565         public String getUIClassID()
1566         {
1567             return "PopupMenuSeparatorUI";
1568 
1569         }
1570     }
1571 
1572     /**
1573      * Returns true if the <code>MouseEvent</code> is considered a popup trigger
1574      * by the <code>JPopupMenu</code>'s currently installed UI.
1575      *
1576      * @param e a {@code MouseEvent}
1577      * @return true if the mouse event is a popup trigger
1578      * @since 1.3
1579      */
1580     public boolean isPopupTrigger(MouseEvent e) {
1581         return getUI().isPopupTrigger(e);
1582     }
1583 }


  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 sun.awt.SunToolkit;
  46 import sun.security.util.SecurityConstants;
  47 
  48 import java.applet.Applet;
  49 
  50 /**
  51  * An implementation of a popup menu -- a small window that pops up
  52  * and displays a series of choices. A {@code JPopupMenu} is used for the
  53  * menu that appears when the user selects an item on the menu bar.
  54  * It is also used for "pull-right" menu that appears when the
  55  * selects a menu item that activates it. Finally, a {@code JPopupMenu}
  56  * can also be used anywhere else you want a menu to appear.  For
  57  * example, when the user right-clicks in a specified area.
  58  * <p>
  59  * For information and examples of using popup menus, see
  60  * <a
  61  href="http://docs.oracle.com/javase/tutorial/uiswing/components/menu.html">How to Use Menus</a>
  62  * in <em>The Java Tutorial.</em>
  63  * <p>
  64  * <strong>Warning:</strong> Swing is not thread safe. For more
  65  * information see <a
  66  * href="package-summary.html#threading">Swing's Threading
  67  * Policy</a>.
  68  * <p>
  69  * <strong>Warning:</strong>
  70  * Serialized objects of this class will not be compatible with
  71  * future Swing releases. The current serialization support is
  72  * appropriate for short term storage or RMI between applications running
  73  * the same version of Swing.  As of 1.4, support for long term storage
  74  * of all JavaBeans&trade;
  75  * has been added to the {@code java.beans} package.
  76  * Please see {@link java.beans.XMLEncoder}.
  77  *
  78  * @beaninfo
  79  *   attribute: isContainer false
  80  * description: A small window that pops up and displays a series of choices.
  81  *
  82  * @author Georges Saab
  83  * @author David Karlton
  84  * @author Arnaud Weber
  85  * @since 1.2
  86  */
  87 @SuppressWarnings("serial")
  88 public class JPopupMenu extends JComponent implements Accessible,MenuElement {
  89 
  90     /**
  91      * @see #getUIClassID
  92      * @see #readObject
  93      */
  94     private static final String uiClassID = "PopupMenuUI";
  95 


 122      * Used to indicate if lightweight popups should be used.
 123      */
 124     private    boolean   lightWeightPopup         = true;
 125 
 126     /*
 127      * Model for the selected subcontrol.
 128      */
 129     private SingleSelectionModel selectionModel;
 130 
 131     /* Lock object used in place of class object for synchronization.
 132      * (4187686)
 133      */
 134     private static final Object classLock = new Object();
 135 
 136     /* diagnostic aids -- should be false for production builds. */
 137     private static final boolean TRACE =   false; // trace creates and disposes
 138     private static final boolean VERBOSE = false; // show reuse hits/misses
 139     private static final boolean DEBUG =   false;  // show bad params, misc.
 140 
 141     /**
 142      *  Sets the default value of the {@code lightWeightPopupEnabled}
 143      *  property.
 144      *
 145      *  @param aFlag {@code true} if popups can be lightweight,
 146      *               otherwise {@code false}
 147      *  @see #getDefaultLightWeightPopupEnabled
 148      *  @see #setLightWeightPopupEnabled
 149      */
 150     public static void setDefaultLightWeightPopupEnabled(boolean aFlag) {
 151         SwingUtilities.appContextPut(defaultLWPopupEnabledKey,
 152                                      Boolean.valueOf(aFlag));
 153     }
 154 
 155     /**
 156      *  Gets the {@code defaultLightWeightPopupEnabled} property,
 157      *  which by default is {@code true}.
 158      *
 159      *  @return the value of the {@code defaultLightWeightPopupEnabled}
 160      *          property
 161      *
 162      *  @see #setDefaultLightWeightPopupEnabled
 163      */
 164     public static boolean getDefaultLightWeightPopupEnabled() {
 165         Boolean b = (Boolean)
 166             SwingUtilities.appContextGet(defaultLWPopupEnabledKey);
 167         if (b == null) {
 168             SwingUtilities.appContextPut(defaultLWPopupEnabledKey,
 169                                          Boolean.TRUE);
 170             return true;
 171         }
 172         return b.booleanValue();
 173     }
 174 
 175     /**
 176      * Constructs a {@code JPopupMenu} without an "invoker".
 177      */
 178     public JPopupMenu() {
 179         this(null);
 180     }
 181 
 182     /**
 183      * Constructs a {@code JPopupMenu} with the specified title.
 184      *
 185      * @param label  the string that a UI may use to display as a title
 186      * for the popup menu.
 187      */
 188     public JPopupMenu(String label) {
 189         this.label = label;
 190         lightWeightPopup = getDefaultLightWeightPopupEnabled();
 191         setSelectionModel(new DefaultSingleSelectionModel());
 192         enableEvents(AWTEvent.MOUSE_EVENT_MASK);
 193         setFocusTraversalKeysEnabled(false);
 194         updateUI();
 195     }
 196 
 197 
 198 
 199     /**
 200      * Returns the look and feel (L&amp;F) object that renders this component.
 201      *
 202      * @return the {@code PopupMenuUI} object that renders this component
 203      */
 204     public PopupMenuUI getUI() {
 205         return (PopupMenuUI)ui;
 206     }
 207 
 208     /**
 209      * Sets the L&amp;F object that renders this component.
 210      *
 211      * @param ui the new {@code PopupMenuUI} L&amp;F object
 212      * @see UIDefaults#getUI
 213      * @beaninfo
 214      *        bound: true
 215      *       hidden: true
 216      *    attribute: visualUpdate true
 217      *  description: The UI object that implements the Component's LookAndFeel.
 218      */
 219     public void setUI(PopupMenuUI ui) {
 220         super.setUI(ui);
 221     }
 222 
 223     /**
 224      * Resets the UI property to a value from the current look and feel.
 225      *
 226      * @see JComponent#updateUI
 227      */
 228     public void updateUI() {
 229         setUI((PopupMenuUI)UIManager.getUI(this));
 230     }
 231 


 245         super.processFocusEvent(evt);
 246     }
 247 
 248     /**
 249      * Processes key stroke events such as mnemonics and accelerators.
 250      *
 251      * @param evt  the key event to be processed
 252      */
 253     protected void processKeyEvent(KeyEvent evt) {
 254         MenuSelectionManager.defaultManager().processKeyEvent(evt);
 255         if (evt.isConsumed()) {
 256             return;
 257         }
 258         super.processKeyEvent(evt);
 259     }
 260 
 261 
 262     /**
 263      * Returns the model object that handles single selections.
 264      *
 265      * @return the {@code selectionModel} property
 266      * @see SingleSelectionModel
 267      */
 268     public SingleSelectionModel getSelectionModel() {
 269         return selectionModel;
 270     }
 271 
 272     /**
 273      * Sets the model object to handle single selections.
 274      *
 275      * @param model the new {@code SingleSelectionModel}
 276      * @see SingleSelectionModel
 277      * @beaninfo
 278      * description: The selection model for the popup menu
 279      *      expert: true
 280      */
 281     public void setSelectionModel(SingleSelectionModel model) {
 282         selectionModel = model;
 283     }
 284 
 285     /**
 286      * Appends the specified menu item to the end of this menu.
 287      *
 288      * @param menuItem the {@code JMenuItem} to add
 289      * @return the {@code JMenuItem} added
 290      */
 291     public JMenuItem add(JMenuItem menuItem) {
 292         super.add(menuItem);
 293         return menuItem;
 294     }
 295 
 296     /**
 297      * Creates a new menu item with the specified text and appends
 298      * it to the end of this menu.
 299      *
 300      * @param s the string for the menu item to be added
 301      * @return a new {@code JMenuItem} created using {@code s}
 302      */
 303     public JMenuItem add(String s) {
 304         return add(new JMenuItem(s));
 305     }
 306 
 307     /**
 308      * Appends a new menu item to the end of the menu which
 309      * dispatches the specified {@code Action} object.
 310      *
 311      * @param a the {@code Action} to add to the menu
 312      * @return the new menu item
 313      * @see Action
 314      */
 315     public JMenuItem add(Action a) {
 316         JMenuItem mi = createActionComponent(a);
 317         mi.setAction(a);
 318         add(mi);
 319         return mi;
 320     }
 321 
 322     /**
 323      * Returns an point which has been adjusted to take into account of the
 324      * desktop bounds, taskbar and multi-monitor configuration.
 325      * <p>
 326      * This adustment may be cancelled by invoking the application with
 327      * -Djavax.swing.adjustPopupLocationToFit=false
 328      */
 329     Point adjustPopupLocationToFitScreen(int xPosition, int yPosition) {
 330         Point popupLocation = new Point(xPosition, yPosition);
 331 


 409             gc = getInvoker().getGraphicsConfiguration();
 410         }
 411         return gc;
 412     }
 413 
 414     /**
 415      * Returns whether popup is allowed to be shown above the task bar.
 416      */
 417     static boolean canPopupOverlapTaskBar() {
 418         boolean result = true;
 419 
 420         Toolkit tk = Toolkit.getDefaultToolkit();
 421         if (tk instanceof SunToolkit) {
 422             result = ((SunToolkit)tk).canPopupOverlapTaskBar();
 423         }
 424 
 425         return result;
 426     }
 427 
 428     /**
 429      * Factory method which creates the {@code JMenuItem} for
 430      * {@code Actions} added to the {@code JPopupMenu}.
 431      *
 432      * @param a the {@code Action} for the menu item to be added
 433      * @return the new menu item
 434      * @see Action
 435      *
 436      * @since 1.3
 437      */
 438     protected JMenuItem createActionComponent(Action a) {
 439         JMenuItem mi = new JMenuItem() {
 440             protected PropertyChangeListener createActionPropertyChangeListener(Action a) {
 441                 PropertyChangeListener pcl = createActionChangeListener(this);
 442                 if (pcl == null) {
 443                     pcl = super.createActionPropertyChangeListener(a);
 444                 }
 445                 return pcl;
 446             }
 447         };
 448         mi.setHorizontalTextPosition(JButton.TRAILING);
 449         mi.setVerticalTextPosition(JButton.CENTER);
 450         return mi;
 451     }
 452 
 453     /**
 454      * Returns a properly configured {@code PropertyChangeListener}
 455      * which updates the control as changes to the {@code Action} occur.
 456      *
 457      * @param b the menu item for which to create a listener
 458      * @return a properly configured {@code PropertyChangeListener}
 459      */
 460     protected PropertyChangeListener createActionChangeListener(JMenuItem b) {
 461         return b.createActionPropertyChangeListener0(b.getAction());
 462     }
 463 
 464     /**
 465      * Removes the component at the specified index from this popup menu.
 466      *
 467      * @param       pos the position of the item to be removed
 468      * @exception   IllegalArgumentException if the value of
 469      *                          {@code pos < 0}, or if the value of
 470      *                          {@code pos} is greater than the
 471      *                          number of items
 472      */
 473     public void remove(int pos) {
 474         if (pos < 0) {
 475             throw new IllegalArgumentException("index less than zero.");
 476         }
 477         if (pos > getComponentCount() -1) {
 478             throw new IllegalArgumentException("index greater than the number of items.");
 479         }
 480         super.remove(pos);
 481     }
 482 
 483     /**
 484      * Sets the value of the {@code lightWeightPopupEnabled} property,
 485      * which by default is {@code true}.
 486      * By default, when a look and feel displays a popup,
 487      * it can choose to
 488      * use a lightweight (all-Java) popup.
 489      * Lightweight popup windows are more efficient than heavyweight
 490      * (native peer) windows,
 491      * but lightweight and heavyweight components do not mix well in a GUI.
 492      * If your application mixes lightweight and heavyweight components,
 493      * you should disable lightweight popups.
 494      * Some look and feels might always use heavyweight popups,
 495      * no matter what the value of this property.
 496      *
 497      * @param aFlag  {@code false} to disable lightweight popups
 498      * @beaninfo
 499      * description: Determines whether lightweight popups are used when possible
 500      *      expert: true
 501      *
 502      * @see #isLightWeightPopupEnabled
 503      */
 504     public void setLightWeightPopupEnabled(boolean aFlag) {
 505         // NOTE: this use to set the flag on a shared JPopupMenu, which meant
 506         // this effected ALL JPopupMenus.
 507         lightWeightPopup = aFlag;
 508     }
 509 
 510     /**
 511      * Gets the {@code lightWeightPopupEnabled} property.
 512      *
 513      * @return the value of the {@code lightWeightPopupEnabled} property
 514      * @see #setLightWeightPopupEnabled
 515      */
 516     public boolean isLightWeightPopupEnabled() {
 517         return lightWeightPopup;
 518     }
 519 
 520     /**
 521      * Returns the popup menu's label
 522      *
 523      * @return a string containing the popup menu's label
 524      * @see #setLabel
 525      */
 526     public String getLabel() {
 527         return label;
 528     }
 529 
 530     /**
 531      * Sets the popup menu's label.  Different look and feels may choose
 532      * to display or not display this.
 533      *


 542         String oldValue = this.label;
 543         this.label = label;
 544         firePropertyChange("label", oldValue, label);
 545         if (accessibleContext != null) {
 546             accessibleContext.firePropertyChange(
 547                 AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
 548                 oldValue, label);
 549         }
 550         invalidate();
 551         repaint();
 552     }
 553 
 554     /**
 555      * Appends a new separator at the end of the menu.
 556      */
 557     public void addSeparator() {
 558         add( new JPopupMenu.Separator() );
 559     }
 560 
 561     /**
 562      * Inserts a menu item for the specified {@code Action} object at
 563      * a given position.
 564      *
 565      * @param a  the {@code Action} object to insert
 566      * @param index      specifies the position at which to insert the
 567      *                   {@code Action}, where 0 is the first
 568      * @exception IllegalArgumentException if {@code index < 0}
 569      * @see Action
 570      */
 571     public void insert(Action a, int index) {
 572         JMenuItem mi = createActionComponent(a);
 573         mi.setAction(a);
 574         insert(mi, index);
 575     }
 576 
 577     /**
 578      * Inserts the specified component into the menu at a given
 579      * position.
 580      *
 581      * @param component  the {@code Component} to insert
 582      * @param index      specifies the position at which
 583      *                   to insert the component, where 0 is the first
 584      * @exception IllegalArgumentException if {@code index < 0}
 585      */
 586     public void insert(Component component, int index) {
 587         if (index < 0) {
 588             throw new IllegalArgumentException("index less than zero.");
 589         }
 590 
 591         int nitems = getComponentCount();
 592         // PENDING(ges): Why not use an array?
 593         Vector<Component> tempItems = new Vector<Component>();
 594 
 595         /* Remove the item at index, nitems-index times
 596            storing them in a temporary vector in the
 597            order they appear on the menu.
 598            */
 599         for (int i = index ; i < nitems; i++) {
 600             tempItems.addElement(getComponent(index));
 601             remove(index);
 602         }
 603 
 604         add(component);
 605 
 606         /* Add the removed items back to the menu, they are
 607            already in the correct order in the temp vector.
 608            */
 609         for (Component tempItem : tempItems) {
 610             add(tempItem);
 611         }
 612     }
 613 
 614     /**
 615      *  Adds a {@code PopupMenu} listener.
 616      *
 617      *  @param l  the {@code PopupMenuListener} to add
 618      */
 619     public void addPopupMenuListener(PopupMenuListener l) {
 620         listenerList.add(PopupMenuListener.class,l);
 621     }
 622 
 623     /**
 624      * Removes a {@code PopupMenu} listener.
 625      *
 626      * @param l  the {@code PopupMenuListener} to remove
 627      */
 628     public void removePopupMenuListener(PopupMenuListener l) {
 629         listenerList.remove(PopupMenuListener.class,l);
 630     }
 631 
 632     /**
 633      * Returns an array of all the {@code PopupMenuListener}s added
 634      * to this JMenuItem with addPopupMenuListener().
 635      *
 636      * @return all of the {@code PopupMenuListener}s added or an empty
 637      *         array if no listeners have been added
 638      * @since 1.4
 639      */
 640     public PopupMenuListener[] getPopupMenuListeners() {
 641         return listenerList.getListeners(PopupMenuListener.class);
 642     }
 643 
 644     /**
 645      * Adds a {@code MenuKeyListener} to the popup menu.
 646      *
 647      * @param l the {@code MenuKeyListener} to be added
 648      * @since 1.5
 649      */
 650     public void addMenuKeyListener(MenuKeyListener l) {
 651         listenerList.add(MenuKeyListener.class, l);
 652     }
 653 
 654     /**
 655      * Removes a {@code MenuKeyListener} from the popup menu.
 656      *
 657      * @param l the {@code MenuKeyListener} to be removed
 658      * @since 1.5
 659      */
 660     public void removeMenuKeyListener(MenuKeyListener l) {
 661         listenerList.remove(MenuKeyListener.class, l);
 662     }
 663 
 664     /**
 665      * Returns an array of all the {@code MenuKeyListener}s added
 666      * to this JPopupMenu with addMenuKeyListener().
 667      *
 668      * @return all of the {@code MenuKeyListener}s added or an empty
 669      *         array if no listeners have been added
 670      * @since 1.5
 671      */
 672     public MenuKeyListener[] getMenuKeyListeners() {
 673         return listenerList.getListeners(MenuKeyListener.class);
 674     }
 675 
 676     /**
 677      * Notifies {@code PopupMenuListener}s that this popup menu will
 678      * become visible.
 679      */
 680     protected void firePopupMenuWillBecomeVisible() {
 681         Object[] listeners = listenerList.getListenerList();
 682         PopupMenuEvent e=null;
 683         for (int i = listeners.length-2; i>=0; i-=2) {
 684             if (listeners[i]==PopupMenuListener.class) {
 685                 if (e == null)
 686                     e = new PopupMenuEvent(this);
 687                 ((PopupMenuListener)listeners[i+1]).popupMenuWillBecomeVisible(e);
 688             }
 689         }
 690     }
 691 
 692     /**
 693      * Notifies {@code PopupMenuListener}s that this popup menu will
 694      * become invisible.
 695      */
 696     protected void firePopupMenuWillBecomeInvisible() {
 697         Object[] listeners = listenerList.getListenerList();
 698         PopupMenuEvent e=null;
 699         for (int i = listeners.length-2; i>=0; i-=2) {
 700             if (listeners[i]==PopupMenuListener.class) {
 701                 if (e == null)
 702                     e = new PopupMenuEvent(this);
 703                 ((PopupMenuListener)listeners[i+1]).popupMenuWillBecomeInvisible(e);
 704             }
 705         }
 706     }
 707 
 708     /**
 709      * Notifies {@code PopupMenuListeners} that this popup menu is
 710      * cancelled.
 711      */
 712     protected void firePopupMenuCanceled() {
 713         Object[] listeners = listenerList.getListenerList();
 714         PopupMenuEvent e=null;
 715         for (int i = listeners.length-2; i>=0; i-=2) {
 716             if (listeners[i]==PopupMenuListener.class) {
 717                 if (e == null)
 718                     e = new PopupMenuEvent(this);
 719                 ((PopupMenuListener)listeners[i+1]).popupMenuCanceled(e);
 720             }
 721         }
 722     }
 723 
 724     /**
 725      * Always returns true since popups, by definition, should always
 726      * be on top of all other windows.
 727      * @return true
 728      */
 729     // package private


 793         if(b) {
 794             firePopupMenuWillBecomeVisible();
 795             showPopup();
 796             firePropertyChange("visible", Boolean.FALSE, Boolean.TRUE);
 797 
 798 
 799         } else if(popup != null) {
 800             firePopupMenuWillBecomeInvisible();
 801             popup.hide();
 802             popup = null;
 803             firePropertyChange("visible", Boolean.TRUE, Boolean.FALSE);
 804             // 4694797: When popup menu is made invisible, selected path
 805             // should be cleared
 806             if (isPopupMenu()) {
 807                 MenuSelectionManager.defaultManager().clearSelectedPath();
 808             }
 809         }
 810     }
 811 
 812     /**
 813      * Retrieves {@code Popup} instance from the
 814      * {@code PopupMenuUI} that has had {@code show} invoked on
 815      * it. If the current {@code popup} is non-null,
 816      * this will invoke {@code dispose} of it, and then
 817      * {@code show} the new one.
 818      * <p>
 819      * This does NOT fire any events, it is up the caller to dispatch
 820      * the necessary events.
 821      */
 822     private void showPopup() {
 823         Popup oldPopup = popup;
 824 
 825         if (oldPopup != null) {
 826             oldPopup.hide();
 827         }
 828         PopupFactory popupFactory = PopupFactory.getSharedInstance();
 829 
 830         if (isLightWeightPopupEnabled()) {
 831             popupFactory.setPopupType(PopupFactory.LIGHT_WEIGHT_POPUP);
 832         }
 833         else {
 834             popupFactory.setPopupType(PopupFactory.HEAVY_WEIGHT_POPUP);
 835         }
 836 
 837         // adjust the location of the popup


 867      * @param x the x coordinate of the popup's new position
 868      *          in the screen's coordinate space
 869      * @param y the y coordinate of the popup's new position
 870      *          in the screen's coordinate space
 871      * @beaninfo
 872      * description: The location of the popup menu.
 873      */
 874     public void setLocation(int x, int y) {
 875         int oldX = desiredLocationX;
 876         int oldY = desiredLocationY;
 877 
 878         desiredLocationX = x;
 879         desiredLocationY = y;
 880         if(popup != null && (x != oldX || y != oldY)) {
 881             showPopup();
 882         }
 883     }
 884 
 885     /**
 886      * Returns true if the popup menu is a standalone popup menu
 887      * rather than the submenu of a {@code JMenu}.
 888      *
 889      * @return true if this menu is a standalone popup menu, otherwise false
 890      */
 891     private boolean isPopupMenu() {
 892         return  ((invoker != null) && !(invoker instanceof JMenu));
 893     }
 894 
 895     /**
 896      * Returns the component which is the 'invoker' of this
 897      * popup menu.
 898      *
 899      * @return the {@code Component} in which the popup menu is displayed
 900      */
 901     public Component getInvoker() {
 902         return this.invoker;
 903     }
 904 
 905     /**
 906      * Sets the invoker of this popup menu -- the component in which
 907      * the popup menu menu is to be displayed.
 908      *
 909      * @param invoker the {@code Component} in which the popup
 910      *          menu is displayed
 911      * @beaninfo
 912      * description: The invoking component for the popup menu
 913      *      expert: true
 914      */
 915     public void setInvoker(Component invoker) {
 916         Component oldInvoker = this.invoker;
 917         this.invoker = invoker;
 918         if ((oldInvoker != this.invoker) && (ui != null)) {
 919             ui.uninstallUI(this);
 920             ui.installUI(this);
 921         }
 922         invalidate();
 923     }
 924 
 925     /**
 926      * Displays the popup menu at the position x,y in the coordinate
 927      * space of the component invoker.
 928      *
 929      * @param invoker the component in whose space the popup menu is to appear


 957             lx = ((long) invokerOrigin.x) +
 958                  ((long) x);
 959             ly = ((long) invokerOrigin.y) +
 960                  ((long) y);
 961             if(lx > Integer.MAX_VALUE) lx = Integer.MAX_VALUE;
 962             if(lx < Integer.MIN_VALUE) lx = Integer.MIN_VALUE;
 963             if(ly > Integer.MAX_VALUE) ly = Integer.MAX_VALUE;
 964             if(ly < Integer.MIN_VALUE) ly = Integer.MIN_VALUE;
 965 
 966             setLocation((int) lx, (int) ly);
 967         } else {
 968             setLocation(x, y);
 969         }
 970         setVisible(true);
 971     }
 972 
 973     /**
 974      * Returns the popup menu which is at the root of the menu system
 975      * for this popup menu.
 976      *
 977      * @return the topmost grandparent {@code JPopupMenu}
 978      */
 979     JPopupMenu getRootPopupMenu() {
 980         JPopupMenu mp = this;
 981         while((mp!=null) && (mp.isPopupMenu()!=true) &&
 982               (mp.getInvoker() != null) &&
 983               (mp.getInvoker().getParent() != null) &&
 984               (mp.getInvoker().getParent() instanceof JPopupMenu)
 985               ) {
 986             mp = (JPopupMenu) mp.getInvoker().getParent();
 987         }
 988         return mp;
 989     }
 990 
 991     /**
 992      * Returns the component at the specified index.
 993      *
 994      * @param i  the index of the component, where 0 is the first
 995      * @return the {@code Component} at that index
 996      * @deprecated replaced by {@link java.awt.Container#getComponent(int)}
 997      */
 998     @Deprecated
 999     public Component getComponentAtIndex(int i) {
1000         return getComponent(i);
1001     }
1002 
1003     /**
1004      * Returns the index of the specified component.
1005      *
1006      * @param  c the {@code Component} to find
1007      * @return the index of the component, where 0 is the first;
1008      *         or -1 if the component is not found
1009      */
1010     public int getComponentIndex(Component c) {
1011         int ncomponents = this.getComponentCount();
1012         Component[] component = this.getComponents();
1013         for (int i = 0 ; i < ncomponents ; i++) {
1014             Component comp = component[i];
1015             if (comp == c)
1016                 return i;
1017         }
1018         return -1;
1019     }
1020 
1021     /**
1022      * Sets the size of the Popup window using a {@code Dimension} object.
1023      * This is equivalent to {@code setPreferredSize(d)}.
1024      *
1025      * @param d   the {@code Dimension} specifying the new size
1026      * of this component.
1027      * @beaninfo
1028      * description: The size of the popup menu
1029      */
1030     public void setPopupSize(Dimension d) {
1031         Dimension oldSize = getPreferredSize();
1032 
1033         setPreferredSize(d);
1034         if (popup != null) {
1035             Dimension newSize = getPreferredSize();
1036 
1037             if (!oldSize.equals(newSize)) {
1038                 showPopup();
1039             }
1040         }
1041     }
1042 
1043     /**
1044      * Sets the size of the Popup window to the specified width and
1045      * height. This is equivalent to
1046      *  {@code setPreferredSize(new Dimension(width, height))}.
1047      *
1048      * @param width the new width of the Popup in pixels
1049      * @param height the new height of the Popup in pixels
1050      * @beaninfo
1051      * description: The size of the popup menu
1052      */
1053     public void setPopupSize(int width, int height) {
1054         setPopupSize(new Dimension(width, height));
1055     }
1056 
1057     /**
1058      * Sets the currently selected component,  This will result
1059      * in a change to the selection model.
1060      *
1061      * @param sel the {@code Component} to select
1062      * @beaninfo
1063      * description: The selected component on the popup menu
1064      *      expert: true
1065      *      hidden: true
1066      */
1067     public void setSelected(Component sel) {
1068         SingleSelectionModel model = getSelectionModel();
1069         int index = getComponentIndex(sel);
1070         model.setSelectedIndex(index);
1071     }
1072 
1073     /**
1074      * Checks whether the border should be painted.
1075      *
1076      * @return true if the border is painted, false otherwise
1077      * @see #setBorderPainted
1078      */
1079     public boolean isBorderPainted() {
1080         return paintBorder;
1081     }
1082 
1083     /**
1084      * Sets whether the border should be painted.
1085      *
1086      * @param b if true, the border is painted.
1087      * @see #isBorderPainted
1088      * @beaninfo
1089      * description: Is the border of the popup menu painted
1090      */
1091     public void setBorderPainted(boolean b) {
1092         paintBorder = b;
1093         repaint();
1094     }
1095 
1096     /**
1097      * Paints the popup menu's border if the {@code borderPainted}
1098      * property is {@code true}.
1099      * @param g  the {@code Graphics} object
1100      *
1101      * @see JComponent#paint
1102      * @see JComponent#setBorder
1103      */
1104     protected void paintBorder(Graphics g) {
1105         if (isBorderPainted()) {
1106             super.paintBorder(g);
1107         }
1108     }
1109 
1110     /**
1111      * Returns the margin, in pixels, between the popup menu's border and
1112      * its containers.
1113      *
1114      * @return an {@code Insets} object containing the margin values.
1115      */
1116     public Insets getMargin() {
1117         if(margin == null) {
1118             return new Insets(0,0,0,0);
1119         } else {
1120             return margin;
1121         }
1122     }
1123 
1124 
1125     /**
1126      * Examines the list of menu items to determine whether
1127      * {@code popup} is a popup menu.
1128      *
1129      * @param popup  a {@code JPopupMenu}
1130      * @return true if {@code popup}
1131      */
1132     boolean isSubPopupMenu(JPopupMenu popup) {
1133         int ncomponents = this.getComponentCount();
1134         Component[] component = this.getComponents();
1135         for (int i = 0 ; i < ncomponents ; i++) {
1136             Component comp = component[i];
1137             if (comp instanceof JMenu) {
1138                 JMenu menu = (JMenu)comp;
1139                 JPopupMenu subPopup = menu.getPopupMenu();
1140                 if (subPopup == popup)
1141                     return true;
1142                 if (subPopup.isSubPopupMenu(popup))
1143                     return true;
1144             }
1145         }
1146         return false;
1147     }
1148 
1149 
1150     private static Frame getFrame(Component c) {
1151         Component w = c;
1152 
1153         while(!(w instanceof Frame) && (w!=null)) {
1154             w = w.getParent();
1155         }
1156         return (Frame)w;
1157     }
1158 
1159 
1160     /**
1161      * Returns a string representation of this {@code JPopupMenu}.
1162      * This method
1163      * is intended to be used only for debugging purposes, and the
1164      * content and format of the returned string may vary between
1165      * implementations. The returned string may be empty but may not
1166      * be {@code null}.
1167      *
1168      * @return  a string representation of this {@code JPopupMenu}.
1169      */
1170     protected String paramString() {
1171         String labelString = (label != null ?
1172                               label : "");
1173         String paintBorderString = (paintBorder ?
1174                                     "true" : "false");
1175         String marginString = (margin != null ?
1176                               margin.toString() : "");
1177         String lightWeightPopupEnabledString = (isLightWeightPopupEnabled() ?
1178                                                 "true" : "false");
1179         return super.paramString() +
1180             ",desiredLocationX=" + desiredLocationX +
1181             ",desiredLocationY=" + desiredLocationY +
1182         ",label=" + labelString +
1183         ",lightWeightPopupEnabled=" + lightWeightPopupEnabledString +
1184         ",margin=" + marginString +
1185         ",paintBorder=" + paintBorderString;
1186     }
1187 
1188 /////////////////


1190 ////////////////
1191 
1192     /**
1193      * Gets the AccessibleContext associated with this JPopupMenu.
1194      * For JPopupMenus, the AccessibleContext takes the form of an
1195      * AccessibleJPopupMenu.
1196      * A new AccessibleJPopupMenu instance is created if necessary.
1197      *
1198      * @return an AccessibleJPopupMenu that serves as the
1199      *         AccessibleContext of this JPopupMenu
1200      */
1201     public AccessibleContext getAccessibleContext() {
1202         if (accessibleContext == null) {
1203             accessibleContext = new AccessibleJPopupMenu();
1204         }
1205         return accessibleContext;
1206     }
1207 
1208     /**
1209      * This class implements accessibility support for the
1210      * {@code JPopupMenu} class.  It provides an implementation of the
1211      * Java Accessibility API appropriate to popup menu user-interface
1212      * elements.
1213      */
1214     @SuppressWarnings("serial")
1215     protected class AccessibleJPopupMenu extends AccessibleJComponent
1216         implements PropertyChangeListener {
1217 
1218         /**
1219          * AccessibleJPopupMenu constructor
1220          *
1221          * @since 1.5
1222          */
1223         protected AccessibleJPopupMenu() {
1224             JPopupMenu.this.addPropertyChangeListener(this);
1225         }
1226 
1227         /**
1228          * Get the role of this object.
1229          *
1230          * @return an instance of AccessibleRole describing the role of
1231          * the object
1232          */
1233         public AccessibleRole getAccessibleRole() {
1234             return AccessibleRole.POPUP_MENU;
1235         }
1236 
1237         /**
1238          * This method gets called when a bound property is changed.
1239          * @param e A {@code PropertyChangeEvent} object describing
1240          * the event source and the property that has changed. Must not be null.
1241          *
1242          * @throws NullPointerException if the parameter is null.
1243          * @since 1.5
1244          */
1245         public void propertyChange(PropertyChangeEvent e) {
1246             String propertyName = e.getPropertyName();
1247             if (propertyName == "visible") {
1248                 if (e.getOldValue() == Boolean.FALSE &&
1249                     e.getNewValue() == Boolean.TRUE) {
1250                     handlePopupIsVisibleEvent(true);
1251 
1252                 } else if (e.getOldValue() == Boolean.TRUE &&
1253                            e.getNewValue() == Boolean.FALSE) {
1254                     handlePopupIsVisibleEvent(false);
1255                 }
1256             }
1257         }
1258 
1259         /*


1362 
1363         Vector<?>          values = (Vector)s.readObject();
1364         int             indexCounter = 0;
1365         int             maxCounter = values.size();
1366 
1367         if(indexCounter < maxCounter && values.elementAt(indexCounter).
1368            equals("invoker")) {
1369             invoker = (Component)values.elementAt(++indexCounter);
1370             indexCounter++;
1371         }
1372         if(indexCounter < maxCounter && values.elementAt(indexCounter).
1373            equals("popup")) {
1374             popup = (Popup)values.elementAt(++indexCounter);
1375             indexCounter++;
1376         }
1377     }
1378 
1379 
1380     /**
1381      * This method is required to conform to the
1382      * {@code MenuElement} interface, but it not implemented.
1383      * @see MenuElement#processMouseEvent(MouseEvent, MenuElement[], MenuSelectionManager)
1384      */
1385     public void processMouseEvent(MouseEvent event,MenuElement path[],MenuSelectionManager manager) {}
1386 
1387     /**
1388      * Processes a key event forwarded from the
1389      * {@code MenuSelectionManager} and changes the menu selection,
1390      * if necessary, by using {@code MenuSelectionManager}'s API.
1391      * <p>
1392      * Note: you do not have to forward the event to sub-components.
1393      * This is done automatically by the {@code MenuSelectionManager}.
1394      *
1395      * @param e  a {@code KeyEvent}
1396      * @param path the {@code MenuElement} path array
1397      * @param manager   the {@code MenuSelectionManager}
1398      */
1399     public void processKeyEvent(KeyEvent e, MenuElement path[],
1400                                 MenuSelectionManager manager) {
1401         MenuKeyEvent mke = new MenuKeyEvent(e.getComponent(), e.getID(),
1402                                              e.getWhen(), e.getModifiers(),
1403                                              e.getKeyCode(), e.getKeyChar(),
1404                                              path, manager);
1405         processMenuKeyEvent(mke);
1406 
1407         if (mke.isConsumed())  {
1408             e.consume();
1409     }
1410     }
1411 
1412     /**
1413      * Handles a keystroke in a menu.
1414      *
1415      * @param e  a {@code MenuKeyEvent} object
1416      * @since 1.5
1417      */
1418     private void processMenuKeyEvent(MenuKeyEvent e) {
1419         switch (e.getID()) {
1420         case KeyEvent.KEY_PRESSED:
1421             fireMenuKeyPressed(e); break;
1422         case KeyEvent.KEY_RELEASED:
1423             fireMenuKeyReleased(e); break;
1424         case KeyEvent.KEY_TYPED:
1425             fireMenuKeyTyped(e); break;
1426         default:
1427             break;
1428         }
1429     }
1430 
1431     /**
1432      * Notifies all listeners that have registered interest for
1433      * notification on this event type.
1434      *
1435      * @param event a {@code MenuKeyEvent}
1436      * @see EventListenerList
1437      */
1438     private void fireMenuKeyPressed(MenuKeyEvent event) {
1439         Object[] listeners = listenerList.getListenerList();
1440         for (int i = listeners.length-2; i>=0; i-=2) {
1441             if (listeners[i]==MenuKeyListener.class) {
1442                 ((MenuKeyListener)listeners[i+1]).menuKeyPressed(event);
1443             }
1444         }
1445     }
1446 
1447     /**
1448      * Notifies all listeners that have registered interest for
1449      * notification on this event type.
1450      *
1451      * @param event a {@code MenuKeyEvent}
1452      * @see EventListenerList
1453      */
1454     private void fireMenuKeyReleased(MenuKeyEvent event) {
1455         Object[] listeners = listenerList.getListenerList();
1456         for (int i = listeners.length-2; i>=0; i-=2) {
1457             if (listeners[i]==MenuKeyListener.class) {
1458                 ((MenuKeyListener)listeners[i+1]).menuKeyReleased(event);
1459             }
1460         }
1461     }
1462 
1463     /**
1464      * Notifies all listeners that have registered interest for
1465      * notification on this event type.
1466      *
1467      * @param event a {@code MenuKeyEvent}
1468      * @see EventListenerList
1469      */
1470     private void fireMenuKeyTyped(MenuKeyEvent event) {
1471         Object[] listeners = listenerList.getListenerList();
1472         for (int i = listeners.length-2; i>=0; i-=2) {
1473             if (listeners[i]==MenuKeyListener.class) {
1474                 ((MenuKeyListener)listeners[i+1]).menuKeyTyped(event);
1475             }
1476         }
1477     }
1478 
1479     /**
1480      * Messaged when the menubar selection changes to activate or
1481      * deactivate this menu. This implements the
1482      * {@code javax.swing.MenuElement} interface.
1483      * Overrides {@code MenuElement.menuSelectionChanged}.
1484      *
1485      * @param isIncluded  true if this menu is active, false if
1486      *        it is not
1487      * @see MenuElement#menuSelectionChanged(boolean)
1488      */
1489     public void menuSelectionChanged(boolean isIncluded) {
1490         if (DEBUG) {
1491             System.out.println("In JPopupMenu.menuSelectionChanged " + isIncluded);
1492         }
1493         if(invoker instanceof JMenu) {
1494             JMenu m = (JMenu) invoker;
1495             if(isIncluded)
1496                 m.setPopupMenuVisible(true);
1497             else
1498                 m.setPopupMenuVisible(false);
1499         }
1500         if (isPopupMenu() && !isIncluded)
1501           setVisible(false);
1502     }
1503 
1504     /**
1505      * Returns an array of {@code MenuElement}s containing the submenu
1506      * for this menu component.  It will only return items conforming to
1507      * the {@code JMenuElement} interface.
1508      * If popup menu is {@code null} returns
1509      * an empty array.  This method is required to conform to the
1510      * {@code MenuElement} interface.
1511      *
1512      * @return an array of {@code MenuElement} objects
1513      * @see MenuElement#getSubElements
1514      */
1515     public MenuElement[] getSubElements() {
1516         MenuElement result[];
1517         Vector<MenuElement> tmp = new Vector<MenuElement>();
1518         int c = getComponentCount();
1519         int i;
1520         Component m;
1521 
1522         for(i=0 ; i < c ; i++) {
1523             m = getComponent(i);
1524             if(m instanceof MenuElement)
1525                 tmp.addElement((MenuElement) m);
1526         }
1527 
1528         result = new MenuElement[tmp.size()];
1529         for(i=0,c=tmp.size() ; i < c ; i++)
1530             result[i] = tmp.elementAt(i);
1531         return result;
1532     }
1533 
1534     /**
1535      * Returns this {@code JPopupMenu} component.
1536      * @return this {@code JPopupMenu} object
1537      * @see MenuElement#getComponent
1538      */
1539     public Component getComponent() {
1540         return this;
1541     }
1542 
1543 
1544     /**
1545      * A popup menu-specific separator.
1546      */
1547     @SuppressWarnings("serial")
1548     public static class Separator extends JSeparator
1549     {
1550         /**
1551          * Constructs a popup menu-specific Separator.
1552          */
1553         public Separator( )
1554         {
1555             super( JSeparator.HORIZONTAL );
1556         }
1557 
1558         /**
1559          * Returns the name of the L&amp;F class that renders this component.
1560          *
1561          * @return the string "PopupMenuSeparatorUI"
1562          * @see JComponent#getUIClassID
1563          * @see UIDefaults#getUI
1564          */
1565         public String getUIClassID()
1566         {
1567             return "PopupMenuSeparatorUI";
1568 
1569         }
1570     }
1571 
1572     /**
1573      * Returns true if the {@code MouseEvent} is considered a popup trigger
1574      * by the {@code JPopupMenu}'s currently installed UI.
1575      *
1576      * @param e a {@code MouseEvent}
1577      * @return true if the mouse event is a popup trigger
1578      * @since 1.3
1579      */
1580     public boolean isPopupTrigger(MouseEvent e) {
1581         return getUI().isPopupTrigger(e);
1582     }
1583 }
< prev index next >