1 /* 2 * Copyright (c) 1996, 2015, Oracle and/or its affiliates. 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.awt; 27 28 import java.awt.peer.PopupMenuPeer; 29 import javax.accessibility.*; 30 31 32 import sun.awt.AWTAccessor; 33 34 /** 35 * A class that implements a menu which can be dynamically popped up 36 * at a specified position within a component. 37 * <p> 38 * As the inheritance hierarchy implies, a <code>PopupMenu</code> 39 * can be used anywhere a <code>Menu</code> can be used. 40 * However, if you use a <code>PopupMenu</code> like a <code>Menu</code> 41 * (e.g., you add it to a <code>MenuBar</code>), then you <b>cannot</b> 42 * call <code>show</code> on that <code>PopupMenu</code>. 43 * 44 * @author Amy Fowler 45 */ 46 public class PopupMenu extends Menu { 47 48 private static final String base = "popup"; 49 static int nameCounter = 0; 50 51 transient boolean isTrayIconPopup = false; 52 53 static { 54 AWTAccessor.setPopupMenuAccessor( 55 new AWTAccessor.PopupMenuAccessor() { 56 public boolean isTrayIconPopup(PopupMenu popupMenu) { 57 return popupMenu.isTrayIconPopup; 58 } 59 }); 60 } 61 62 /* 63 * JDK 1.1 serialVersionUID 64 */ 65 private static final long serialVersionUID = -4620452533522760060L; 66 67 /** 68 * Creates a new popup menu with an empty name. 69 * @exception HeadlessException if GraphicsEnvironment.isHeadless() 70 * returns true. 71 * @see java.awt.GraphicsEnvironment#isHeadless 72 */ 73 public PopupMenu() throws HeadlessException { 74 this(""); 75 } 76 77 /** 78 * Creates a new popup menu with the specified name. 79 * 80 * @param label a non-<code>null</code> string specifying 81 * the popup menu's label 82 * @exception HeadlessException if GraphicsEnvironment.isHeadless() 83 * returns true. 84 * @see java.awt.GraphicsEnvironment#isHeadless 85 */ 86 public PopupMenu(String label) throws HeadlessException { 87 super(label); 88 } 89 90 /** 91 * {@inheritDoc} 92 */ 93 public MenuContainer getParent() { 94 if (isTrayIconPopup) { 95 return null; 96 } 97 return super.getParent(); 98 } 99 100 /** 101 * Constructs a name for this <code>MenuComponent</code>. 102 * Called by <code>getName</code> when the name is <code>null</code>. 103 */ 104 String constructComponentName() { 105 synchronized (PopupMenu.class) { 106 return base + nameCounter++; 107 } 108 } 109 110 /** 111 * Creates the popup menu's peer. 112 * The peer allows us to change the appearance of the popup menu without 113 * changing any of the popup menu's functionality. 114 */ 115 public void addNotify() { 116 synchronized (getTreeLock()) { 117 // If our parent is not a Component, then this PopupMenu is 118 // really just a plain, old Menu. 119 if (parent != null && !(parent instanceof Component)) { 120 super.addNotify(); 121 } 122 else { 123 if (peer == null) 124 peer = Toolkit.getDefaultToolkit().createPopupMenu(this); 125 int nitems = getItemCount(); 126 for (int i = 0 ; i < nitems ; i++) { 127 MenuItem mi = getItem(i); 128 mi.parent = this; 129 mi.addNotify(); 130 } 131 } 132 } 133 } 134 135 /** 136 * Shows the popup menu at the x, y position relative to an origin 137 * component. 138 * The origin component must be contained within the component 139 * hierarchy of the popup menu's parent. Both the origin and the parent 140 * must be showing on the screen for this method to be valid. 141 * <p> 142 * If this <code>PopupMenu</code> is being used as a <code>Menu</code> 143 * (i.e., it has a non-<code>Component</code> parent), 144 * then you cannot call this method on the <code>PopupMenu</code>. 145 * 146 * @param origin the component which defines the coordinate space 147 * @param x the x coordinate position to popup the menu 148 * @param y the y coordinate position to popup the menu 149 * @exception NullPointerException if the parent is <code>null</code> 150 * @exception IllegalArgumentException if this <code>PopupMenu</code> 151 * has a non-<code>Component</code> parent 152 * @exception IllegalArgumentException if the origin is not in the 153 * parent's hierarchy 154 * @exception RuntimeException if the parent is not showing on screen 155 */ 156 public void show(Component origin, int x, int y) { 157 // Use localParent for thread safety. 158 MenuContainer localParent = parent; 159 if (localParent == null) { 160 throw new NullPointerException("parent is null"); 161 } 162 if (!(localParent instanceof Component)) { 163 throw new IllegalArgumentException( 164 "PopupMenus with non-Component parents cannot be shown"); 165 } 166 Component compParent = (Component)localParent; 167 //Fixed 6278745: Incorrect exception throwing in PopupMenu.show() method 168 //Exception was not thrown if compParent was not equal to origin and 169 //was not Container 170 if (compParent != origin) { 171 if (compParent instanceof Container) { 172 if (!((Container)compParent).isAncestorOf(origin)) { 173 throw new IllegalArgumentException("origin not in parent's hierarchy"); 174 } 175 } else { 176 throw new IllegalArgumentException("origin not in parent's hierarchy"); 177 } 178 } 179 if (compParent.peer == null || !compParent.isShowing()) { 180 throw new RuntimeException("parent not showing on screen"); 181 } 182 if (peer == null) { 183 addNotify(); 184 } 185 synchronized (getTreeLock()) { 186 if (peer != null) { 187 ((PopupMenuPeer)peer).show( 188 new Event(origin, 0, Event.MOUSE_DOWN, x, y, 0, 0)); 189 } 190 } 191 } 192 193 194 ///////////////// 195 // Accessibility support 196 //////////////// 197 198 /** 199 * Gets the <code>AccessibleContext</code> associated with this 200 * <code>PopupMenu</code>. 201 * 202 * @return the <code>AccessibleContext</code> of this 203 * <code>PopupMenu</code> 204 * @since 1.3 205 */ 206 public AccessibleContext getAccessibleContext() { 207 if (accessibleContext == null) { 208 accessibleContext = new AccessibleAWTPopupMenu(); 209 } 210 return accessibleContext; 211 } 212 213 /** 214 * Inner class of PopupMenu used to provide default support for 215 * accessibility. This class is not meant to be used directly by 216 * application developers, but is instead meant only to be 217 * subclassed by menu component developers. 218 * <p> 219 * The class used to obtain the accessible role for this object. 220 * @since 1.3 221 */ 222 protected class AccessibleAWTPopupMenu extends AccessibleAWTMenu 223 { 224 /* 225 * JDK 1.3 serialVersionUID 226 */ 227 private static final long serialVersionUID = -4282044795947239955L; 228 229 /** 230 * Get the role of this object. 231 * 232 * @return an instance of AccessibleRole describing the role of the 233 * object 234 */ 235 public AccessibleRole getAccessibleRole() { 236 return AccessibleRole.POPUP_MENU; 237 } 238 239 } // class AccessibleAWTPopupMenu 240 241 }