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 }
|