001: /*
002: * Copyright 1996-2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package java.awt;
027:
028: import java.awt.peer.PopupMenuPeer;
029: import javax.accessibility.*;
030:
031: /**
032: * A class that implements a menu which can be dynamically popped up
033: * at a specified position within a component.
034: * <p>
035: * As the inheritance hierarchy implies, a <code>PopupMenu</code>
036: * can be used anywhere a <code>Menu</code> can be used.
037: * However, if you use a <code>PopupMenu</code> like a <code>Menu</code>
038: * (e.g., you add it to a <code>MenuBar</code>), then you <b>cannot</b>
039: * call <code>show</code> on that <code>PopupMenu</code>.
040: *
041: * @version 1.41 05/05/07
042: * @author Amy Fowler
043: */
044: public class PopupMenu extends Menu {
045:
046: private static final String base = "popup";
047: static int nameCounter = 0;
048:
049: transient boolean isTrayIconPopup = false;
050:
051: /*
052: * JDK 1.1 serialVersionUID
053: */
054: private static final long serialVersionUID = -4620452533522760060L;
055:
056: /**
057: * Creates a new popup menu with an empty name.
058: * @exception HeadlessException if GraphicsEnvironment.isHeadless()
059: * returns true.
060: * @see java.awt.GraphicsEnvironment#isHeadless
061: */
062: public PopupMenu() throws HeadlessException {
063: this ("");
064: }
065:
066: /**
067: * Creates a new popup menu with the specified name.
068: *
069: * @param label a non-<code>null</code> string specifying
070: * the popup menu's label
071: * @exception HeadlessException if GraphicsEnvironment.isHeadless()
072: * returns true.
073: * @see java.awt.GraphicsEnvironment#isHeadless
074: */
075: public PopupMenu(String label) throws HeadlessException {
076: super (label);
077: }
078:
079: /**
080: * {@inheritDoc}
081: */
082: public MenuContainer getParent() {
083: if (isTrayIconPopup) {
084: return null;
085: }
086: return super .getParent();
087: }
088:
089: /**
090: * Constructs a name for this <code>MenuComponent</code>.
091: * Called by <code>getName</code> when the name is <code>null</code>.
092: */
093: String constructComponentName() {
094: synchronized (PopupMenu.class) {
095: return base + nameCounter++;
096: }
097: }
098:
099: /**
100: * Creates the popup menu's peer.
101: * The peer allows us to change the appearance of the popup menu without
102: * changing any of the popup menu's functionality.
103: */
104: public void addNotify() {
105: synchronized (getTreeLock()) {
106: // If our parent is not a Component, then this PopupMenu is
107: // really just a plain, old Menu.
108: if (parent != null && !(parent instanceof Component)) {
109: super .addNotify();
110: } else {
111: if (peer == null)
112: peer = Toolkit.getDefaultToolkit().createPopupMenu(
113: this );
114: int nitems = getItemCount();
115: for (int i = 0; i < nitems; i++) {
116: MenuItem mi = getItem(i);
117: mi.parent = this ;
118: mi.addNotify();
119: }
120: }
121: }
122: }
123:
124: /**
125: * Shows the popup menu at the x, y position relative to an origin
126: * component.
127: * The origin component must be contained within the component
128: * hierarchy of the popup menu's parent. Both the origin and the parent
129: * must be showing on the screen for this method to be valid.
130: * <p>
131: * If this <code>PopupMenu</code> is being used as a <code>Menu</code>
132: * (i.e., it has a non-<code>Component</code> parent),
133: * then you cannot call this method on the <code>PopupMenu</code>.
134: *
135: * @param origin the component which defines the coordinate space
136: * @param x the x coordinate position to popup the menu
137: * @param y the y coordinate position to popup the menu
138: * @exception NullPointerException if the parent is <code>null</code>
139: * @exception IllegalArgumentException if this <code>PopupMenu</code>
140: * has a non-<code>Component</code> parent
141: * @exception IllegalArgumentException if the origin is not in the
142: * parent's heirarchy
143: * @exception RuntimeException if the parent is not showing on screen
144: */
145: public void show(Component origin, int x, int y) {
146: // Use localParent for thread safety.
147: MenuContainer localParent = parent;
148: if (localParent == null) {
149: throw new NullPointerException("parent is null");
150: }
151: if (!(localParent instanceof Component)) {
152: throw new IllegalArgumentException(
153: "PopupMenus with non-Component parents cannot be shown");
154: }
155: Component compParent = (Component) localParent;
156: //Fixed 6278745: Incorrect exception throwing in PopupMenu.show() method
157: //Exception was not thrown if compParent was not equal to origin and
158: //was not Container
159: if (compParent != origin) {
160: if (compParent instanceof Container) {
161: if (!((Container) compParent).isAncestorOf(origin)) {
162: throw new IllegalArgumentException(
163: "origin not in parent's hierarchy");
164: }
165: } else {
166: throw new IllegalArgumentException(
167: "origin not in parent's hierarchy");
168: }
169: }
170: if (compParent.getPeer() == null || !compParent.isShowing()) {
171: throw new RuntimeException("parent not showing on screen");
172: }
173: if (peer == null) {
174: addNotify();
175: }
176: synchronized (getTreeLock()) {
177: if (peer != null) {
178: ((PopupMenuPeer) peer).show(new Event(origin, 0,
179: Event.MOUSE_DOWN, x, y, 0, 0));
180: }
181: }
182: }
183:
184: /////////////////
185: // Accessibility support
186: ////////////////
187:
188: /**
189: * Gets the <code>AccessibleContext</code> associated with this
190: * <code>PopupMenu</code>.
191: *
192: * @return the <code>AccessibleContext</code> of this
193: * <code>PopupMenu</code>
194: * @since 1.3
195: */
196: public AccessibleContext getAccessibleContext() {
197: if (accessibleContext == null) {
198: accessibleContext = new AccessibleAWTPopupMenu();
199: }
200: return accessibleContext;
201: }
202:
203: /**
204: * Inner class of PopupMenu used to provide default support for
205: * accessibility. This class is not meant to be used directly by
206: * application developers, but is instead meant only to be
207: * subclassed by menu component developers.
208: * <p>
209: * The class used to obtain the accessible role for this object.
210: * @since 1.3
211: */
212: protected class AccessibleAWTPopupMenu extends AccessibleAWTMenu {
213: /*
214: * JDK 1.3 serialVersionUID
215: */
216: private static final long serialVersionUID = -4282044795947239955L;
217:
218: /**
219: * Get the role of this object.
220: *
221: * @return an instance of AccessibleRole describing the role of the
222: * object
223: */
224: public AccessibleRole getAccessibleRole() {
225: return AccessibleRole.POPUP_MENU;
226: }
227:
228: } // class AccessibleAWTPopupMenu
229:
230: }
|