1 /* 2 * Copyright (c) 1996, 2014, 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 @SuppressWarnings("deprecation") 157 public void show(Component origin, int x, int y) { 158 // Use localParent for thread safety. 159 MenuContainer localParent = parent; 160 if (localParent == null) { 161 throw new NullPointerException("parent is null"); 162 } 163 if (!(localParent instanceof Component)) { 164 throw new IllegalArgumentException( 165 "PopupMenus with non-Component parents cannot be shown"); 166 } 167 Component compParent = (Component)localParent; 168 //Fixed 6278745: Incorrect exception throwing in PopupMenu.show() method 169 //Exception was not thrown if compParent was not equal to origin and 170 //was not Container 171 if (compParent != origin) { 172 if (compParent instanceof Container) { 173 if (!((Container)compParent).isAncestorOf(origin)) { 174 throw new IllegalArgumentException("origin not in parent's hierarchy"); 175 } 176 } else { 177 throw new IllegalArgumentException("origin not in parent's hierarchy"); 178 } 179 } 180 if (compParent.getPeer() == null || !compParent.isShowing()) { 181 throw new RuntimeException("parent not showing on screen"); 182 } 183 if (peer == null) { 184 addNotify(); 185 } 186 synchronized (getTreeLock()) { 187 if (peer != null) { 188 ((PopupMenuPeer)peer).show( 189 new Event(origin, 0, Event.MOUSE_DOWN, x, y, 0, 0)); 190 } 191 } 192 } 193 194 195 ///////////////// 196 // Accessibility support 197 //////////////// 198 199 /** 200 * Gets the <code>AccessibleContext</code> associated with this 201 * <code>PopupMenu</code>. 202 * 203 * @return the <code>AccessibleContext</code> of this 204 * <code>PopupMenu</code> 205 * @since 1.3 206 */ 207 public AccessibleContext getAccessibleContext() { 208 if (accessibleContext == null) { 209 accessibleContext = new AccessibleAWTPopupMenu(); 210 } 211 return accessibleContext; 212 } 213 214 /** 215 * Inner class of PopupMenu used to provide default support for 216 * accessibility. This class is not meant to be used directly by 217 * application developers, but is instead meant only to be 218 * subclassed by menu component developers. 219 * <p> 220 * The class used to obtain the accessible role for this object. 221 * @since 1.3 222 */ 223 protected class AccessibleAWTPopupMenu extends AccessibleAWTMenu 224 { 225 /* 226 * JDK 1.3 serialVersionUID 227 */ 228 private static final long serialVersionUID = -4282044795947239955L; 229 230 /** 231 * Get the role of this object. 232 * 233 * @return an instance of AccessibleRole describing the role of the 234 * object 235 */ 236 public AccessibleRole getAccessibleRole() { 237 return AccessibleRole.POPUP_MENU; 238 } 239 240 } // class AccessibleAWTPopupMenu 241 242 }