/* * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package java.awt; import java.awt.peer.PopupMenuPeer; import javax.accessibility.*; import sun.awt.AWTAccessor; /** * A class that implements a menu which can be dynamically popped up * at a specified position within a component. * <p> * As the inheritance hierarchy implies, a <code>PopupMenu</code> * can be used anywhere a <code>Menu</code> can be used. * However, if you use a <code>PopupMenu</code> like a <code>Menu</code> * (e.g., you add it to a <code>MenuBar</code>), then you <b>cannot</b> * call <code>show</code> on that <code>PopupMenu</code>. * * @author Amy Fowler */ public class PopupMenu extends Menu { private static final String base = "popup"; static int nameCounter = 0; transient boolean isTrayIconPopup = false; static { AWTAccessor.setPopupMenuAccessor( new AWTAccessor.PopupMenuAccessor() { public boolean isTrayIconPopup(PopupMenu popupMenu) { return popupMenu.isTrayIconPopup; } }); } /* * JDK 1.1 serialVersionUID */ private static final long serialVersionUID = -4620452533522760060L; /** * Creates a new popup menu with an empty name. * @exception HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ public PopupMenu() throws HeadlessException { this(""); } /** * Creates a new popup menu with the specified name. * * @param label a non-<code>null</code> string specifying * the popup menu's label * @exception HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ public PopupMenu(String label) throws HeadlessException { super(label); } /** * {@inheritDoc} */ public MenuContainer getParent() { if (isTrayIconPopup) { return null; } return super.getParent(); } /** * Constructs a name for this <code>MenuComponent</code>. * Called by <code>getName</code> when the name is <code>null</code>. */ String constructComponentName() { synchronized (PopupMenu.class) { return base + nameCounter++; } } /** * Creates the popup menu's peer. * The peer allows us to change the appearance of the popup menu without * changing any of the popup menu's functionality. */ public void addNotify() { synchronized (getTreeLock()) { // If our parent is not a Component, then this PopupMenu is // really just a plain, old Menu. if (parent != null && !(parent instanceof Component)) { super.addNotify(); } else { if (peer == null) peer = Toolkit.getDefaultToolkit().createPopupMenu(this); int nitems = getItemCount(); for (int i = 0 ; i < nitems ; i++) { MenuItem mi = getItem(i); mi.parent = this; mi.addNotify(); } } } } /** * Shows the popup menu at the x, y position relative to an origin * component. * The origin component must be contained within the component * hierarchy of the popup menu's parent. Both the origin and the parent * must be showing on the screen for this method to be valid. * <p> * If this <code>PopupMenu</code> is being used as a <code>Menu</code> * (i.e., it has a non-<code>Component</code> parent), * then you cannot call this method on the <code>PopupMenu</code>. * * @param origin the component which defines the coordinate space * @param x the x coordinate position to popup the menu * @param y the y coordinate position to popup the menu * @exception NullPointerException if the parent is <code>null</code> * @exception IllegalArgumentException if this <code>PopupMenu</code> * has a non-<code>Component</code> parent * @exception IllegalArgumentException if the origin is not in the * parent's heirarchy * @exception RuntimeException if the parent is not showing on screen */ public void show(Component origin, int x, int y) { // Use localParent for thread safety. MenuContainer localParent = parent; if (localParent == null) { throw new NullPointerException("parent is null"); } if (!(localParent instanceof Component)) { throw new IllegalArgumentException( "PopupMenus with non-Component parents cannot be shown"); } Component compParent = (Component)localParent; //Fixed 6278745: Incorrect exception throwing in PopupMenu.show() method //Exception was not thrown if compParent was not equal to origin and //was not Container if (compParent != origin) { if (compParent instanceof Container) { if (!((Container)compParent).isAncestorOf(origin)) { throw new IllegalArgumentException("origin not in parent's hierarchy"); } } else { throw new IllegalArgumentException("origin not in parent's hierarchy"); } } if (compParent.getPeer() == null || !compParent.isShowing()) { throw new RuntimeException("parent not showing on screen"); } if (peer == null) { addNotify(); } synchronized (getTreeLock()) { if (peer != null) { ((PopupMenuPeer)peer).show( new Event(origin, 0, Event.MOUSE_DOWN, x, y, 0, 0)); } } } ///////////////// // Accessibility support //////////////// /** * Gets the <code>AccessibleContext</code> associated with this * <code>PopupMenu</code>. * * @return the <code>AccessibleContext</code> of this * <code>PopupMenu</code> * @since 1.3 */ public AccessibleContext getAccessibleContext() { if (accessibleContext == null) { accessibleContext = new AccessibleAWTPopupMenu(); } return accessibleContext; } /** * Inner class of PopupMenu used to provide default support for * accessibility. This class is not meant to be used directly by * application developers, but is instead meant only to be * subclassed by menu component developers. * <p> * The class used to obtain the accessible role for this object. * @since 1.3 */ protected class AccessibleAWTPopupMenu extends AccessibleAWTMenu { /* * JDK 1.3 serialVersionUID */ private static final long serialVersionUID = -4282044795947239955L; /** * Get the role of this object. * * @return an instance of AccessibleRole describing the role of the * object */ public AccessibleRole getAccessibleRole() { return AccessibleRole.POPUP_MENU; } } // class AccessibleAWTPopupMenu }