1/*
2 * Copyright (c) 2011, 2016, 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
26package sun.lwawt.macosx;
27
28import java.awt.MenuItem;
29import java.awt.MenuShortcut;
30import java.awt.event.ActionEvent;
31import java.awt.event.InputEvent;
32import java.awt.event.KeyEvent;
33import java.awt.peer.MenuItemPeer;
34import java.util.concurrent.atomic.AtomicBoolean;
35
36import sun.awt.SunToolkit;
37import sun.lwawt.LWToolkit;
38
39public 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//    @Override
133    public void enable() {
134        setEnabled(true);
135    }
136
137//    @Override
138    public void disable() {
139        setEnabled(false);
140    }
141
142    public final boolean isEnabled() {
143        return enabled.get();
144    }
145
146    @Override
147    public void setEnabled(boolean b) {
148        final Object parent = LWToolkit.targetToPeer(getTarget().getParent());
149        if (parent instanceof CMenuItem) {
150            b &= ((CMenuItem) parent).isEnabled();
151        }
152        if (enabled.compareAndSet(!b, b)) {
153            final boolean finalB = b;
154            execute(ptr->nativeSetEnabled(ptr, finalB));
155        }
156    }
157
158    private native long nativeCreate(long parentMenu, boolean isSeparator);
159    private native void nativeSetLabel(long modelPtr, String label, char keyChar, int keyCode, int modifiers);
160    private native void nativeSetImage(long modelPtr, long image);
161    private native void nativeSetTooltip(long modelPtr, String text);
162    private native void nativeSetEnabled(long modelPtr, boolean b);
163
164    // native callbacks
165    void handleAction(final long when, final int modifiers) {
166        SunToolkit.executeOnEventHandlerThread(getTarget(), new Runnable() {
167            public void run() {
168                final String cmd = ((MenuItem)getTarget()).getActionCommand();
169                final ActionEvent event = new ActionEvent(getTarget(), ActionEvent.ACTION_PERFORMED, cmd, when, modifiers);
170                SunToolkit.postEvent(SunToolkit.targetToAppContext(getTarget()), event);
171            }
172        });
173    }
174}
175