1 /* 2 * Copyright (c) 2011, 2018, 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 sun.lwawt.macosx; 27 28 import java.awt.MenuItem; 29 import java.awt.MenuShortcut; 30 import java.awt.event.ActionEvent; 31 import java.awt.event.InputEvent; 32 import java.awt.event.KeyEvent; 33 import java.awt.peer.MenuItemPeer; 34 import java.util.concurrent.atomic.AtomicBoolean; 35 36 import sun.awt.SunToolkit; 37 import sun.lwawt.LWToolkit; 38 39 public class CMenuItem extends CMenuComponent implements MenuItemPeer { 40 41 private final AtomicBoolean enabled = new AtomicBoolean(true); 42 43 public CMenuItem(MenuItem target) { 44 super(target); 45 initialize(target); 46 } 47 48 // This way we avoiding invocation of the setters twice 49 protected void initialize(MenuItem target) { 50 if (!isSeparator()) { 51 setLabel(target.getLabel()); 52 setEnabled(target.isEnabled()); 53 } 54 } 55 56 private boolean isSeparator() { 57 String label = ((MenuItem)getTarget()).getLabel(); 58 return (label != null && label.equals("-")); 59 } 60 61 @Override 62 long createModel() { 63 CMenuComponent parent = (CMenuComponent)LWToolkit.targetToPeer(getTarget().getParent()); 64 return parent.executeGet(ptr->nativeCreate(ptr, isSeparator())); 65 } 66 @SuppressWarnings("deprecation") 67 public void setLabel(String label, char keyChar, int keyCode, int modifiers) { 68 int keyMask = modifiers; 69 if (keyCode == KeyEvent.VK_UNDEFINED) { 70 MenuShortcut shortcut = ((MenuItem)getTarget()).getShortcut(); 71 72 if (shortcut != null) { 73 keyCode = shortcut.getKey(); 74 keyMask |= InputEvent.META_MASK; 75 76 if (shortcut.usesShiftModifier()) { 77 keyMask |= InputEvent.SHIFT_MASK; 78 } 79 } 80 } 81 82 if (label == null) { 83 label = ""; 84 } 85 86 // <rdar://problem/3654824> 87 // Native code uses a keyChar of 0 to indicate that the 88 // keyCode should be used to generate the shortcut. Translate 89 // CHAR_UNDEFINED into 0. 90 if (keyChar == KeyEvent.CHAR_UNDEFINED) { 91 keyChar = 0; 92 } 93 94 final String finalLabel = label; 95 final char finalKeyChar = keyChar; 96 final int finalKeyCode = keyCode; 97 final int finalKeyMask = keyMask; 98 execute(ptr -> nativeSetLabel(ptr, finalLabel, finalKeyChar, 99 finalKeyCode, finalKeyMask)); 100 } 101 102 @Override 103 public void setLabel(String label) { 104 setLabel(label, (char)0, KeyEvent.VK_UNDEFINED, 0); 105 } 106 107 /** 108 * This is new API that we've added to AWT menu items 109 * because AWT menu items are used for Swing screen menu bars 110 * and we want to support the NSMenuItem image apis. 111 * There isn't a need to expose this except in a instanceof because 112 * it isn't defined in the peer api. 113 */ 114 public final void setImage(final java.awt.Image img) { 115 CImage cimg = CImage.getCreator().createFromImage(img); 116 execute(ptr -> { 117 if (cimg == null) { 118 nativeSetImage(ptr, 0L); 119 } else { 120 cimg.execute(imgPtr -> nativeSetImage(ptr, imgPtr)); 121 } 122 }); 123 } 124 125 /** 126 * New API for tooltips 127 */ 128 public final void setToolTipText(final String text) { 129 execute(ptr -> nativeSetTooltip(ptr, text)); 130 } 131 132 public final boolean isEnabled() { 133 return enabled.get(); 134 } 135 136 @Override 137 public void setEnabled(boolean b) { 138 final Object parent = LWToolkit.targetToPeer(getTarget().getParent()); 139 if (parent instanceof CMenuItem) { 140 b &= ((CMenuItem) parent).isEnabled(); 141 } 142 if (enabled.compareAndSet(!b, b)) { 143 final boolean finalB = b; 144 execute(ptr->nativeSetEnabled(ptr, finalB)); 145 } 146 } 147 148 private native long nativeCreate(long parentMenu, boolean isSeparator); 149 private native void nativeSetLabel(long modelPtr, String label, char keyChar, int keyCode, int modifiers); 150 private native void nativeSetImage(long modelPtr, long image); 151 private native void nativeSetTooltip(long modelPtr, String text); 152 private native void nativeSetEnabled(long modelPtr, boolean b); 153 154 // native callbacks 155 void handleAction(final long when, final int modifiers) { 156 SunToolkit.executeOnEventHandlerThread(getTarget(), new Runnable() { 157 public void run() { 158 final String cmd = ((MenuItem)getTarget()).getActionCommand(); 159 final ActionEvent event = new ActionEvent(getTarget(), ActionEvent.ACTION_PERFORMED, cmd, when, modifiers); 160 SunToolkit.postEvent(SunToolkit.targetToAppContext(getTarget()), event); 161 } 162 }); 163 } 164 }