blob: 64ebe75c2ccf0266b32f1eb65c0a153a34e90131 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1996-2006 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package java.awt;
27
28import java.awt.peer.PopupMenuPeer;
29import javax.accessibility.*;
30
31
32/**
33 * A class that implements a menu which can be dynamically popped up
34 * at a specified position within a component.
35 * <p>
36 * As the inheritance hierarchy implies, a <code>PopupMenu</code>
37 * can be used anywhere a <code>Menu</code> can be used.
38 * However, if you use a <code>PopupMenu</code> like a <code>Menu</code>
39 * (e.g., you add it to a <code>MenuBar</code>), then you <b>cannot</b>
40 * call <code>show</code> on that <code>PopupMenu</code>.
41 *
42 * @author Amy Fowler
43 */
44public class PopupMenu extends Menu {
45
46 private static final String base = "popup";
47 static int nameCounter = 0;
48
49 transient boolean isTrayIconPopup = false;
50
51 /*
52 * JDK 1.1 serialVersionUID
53 */
54 private static final long serialVersionUID = -4620452533522760060L;
55
56 /**
57 * Creates a new popup menu with an empty name.
58 * @exception HeadlessException if GraphicsEnvironment.isHeadless()
59 * returns true.
60 * @see java.awt.GraphicsEnvironment#isHeadless
61 */
62 public PopupMenu() throws HeadlessException {
63 this("");
64 }
65
66 /**
67 * Creates a new popup menu with the specified name.
68 *
69 * @param label a non-<code>null</code> string specifying
70 * the popup menu's label
71 * @exception HeadlessException if GraphicsEnvironment.isHeadless()
72 * returns true.
73 * @see java.awt.GraphicsEnvironment#isHeadless
74 */
75 public PopupMenu(String label) throws HeadlessException {
76 super(label);
77 }
78
79 /**
80 * {@inheritDoc}
81 */
82 public MenuContainer getParent() {
83 if (isTrayIconPopup) {
84 return null;
85 }
86 return super.getParent();
87 }
88
89 /**
90 * Constructs a name for this <code>MenuComponent</code>.
91 * Called by <code>getName</code> when the name is <code>null</code>.
92 */
93 String constructComponentName() {
94 synchronized (PopupMenu.class) {
95 return base + nameCounter++;
96 }
97 }
98
99 /**
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 }
111 else {
112 if (peer == null)
113 peer = Toolkit.getDefaultToolkit().createPopupMenu(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("origin not in parent's hierarchy");
163 }
164 } else {
165 throw new IllegalArgumentException("origin not in parent's hierarchy");
166 }
167 }
168 if (compParent.getPeer() == null || !compParent.isShowing()) {
169 throw new RuntimeException("parent not showing on screen");
170 }
171 if (peer == null) {
172 addNotify();
173 }
174 synchronized (getTreeLock()) {
175 if (peer != null) {
176 ((PopupMenuPeer)peer).show(
177 new Event(origin, 0, Event.MOUSE_DOWN, x, y, 0, 0));
178 }
179 }
180 }
181
182
183/////////////////
184// Accessibility support
185////////////////
186
187 /**
188 * Gets the <code>AccessibleContext</code> associated with this
189 * <code>PopupMenu</code>.
190 *
191 * @return the <code>AccessibleContext</code> of this
192 * <code>PopupMenu</code>
193 * @since 1.3
194 */
195 public AccessibleContext getAccessibleContext() {
196 if (accessibleContext == null) {
197 accessibleContext = new AccessibleAWTPopupMenu();
198 }
199 return accessibleContext;
200 }
201
202 /**
203 * Inner class of PopupMenu used to provide default support for
204 * accessibility. This class is not meant to be used directly by
205 * application developers, but is instead meant only to be
206 * subclassed by menu component developers.
207 * <p>
208 * The class used to obtain the accessible role for this object.
209 * @since 1.3
210 */
211 protected class AccessibleAWTPopupMenu extends AccessibleAWTMenu
212 {
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}