1 /*
2  * Copyright (c) 2011, 2012, 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 com.apple.laf;
27 
28 import java.awt.*;
29 import java.beans.*;
30 
31 import javax.swing.*;
32 import javax.swing.plaf.*;
33 import javax.swing.plaf.basic.BasicMenuItemUI;
34 
35 import apple.laf.JRSUIConstants.Size;
36 
37 // TODO: no screen menu bar for now
38 public class AquaMenuItemUI extends BasicMenuItemUI implements AquaMenuPainter.Client/*, ScreenMenuItemUI*/ {
39     static final int kPlain = 0, kCheckBox = 1, kRadioButton = 2;
40     static final String sPropertyPrefixes[] = { "MenuItem", "CheckBoxMenuItem", "RadioButtonMenuItem" };
41 
42     boolean fIsScreenMenuItem = false;
43     boolean fIsIndeterminate = false;
44     int fType;
45 
AquaMenuItemUI(final int type)46     AquaMenuItemUI(final int type) {
47         super();
48         fType = type;
49     }
50 
createUI(final JComponent c)51     public static ComponentUI createUI(final JComponent c) {
52         int type = kPlain;
53         if (c instanceof JCheckBoxMenuItem) type = kCheckBox;
54         if (c instanceof JRadioButtonMenuItem) type = kRadioButton;
55         return new AquaMenuItemUI(type);
56     }
57 
58     // The only real difference between the three is which property prefix it returns
59     // and therefore which icons!
getPropertyPrefix()60     protected String getPropertyPrefix() {
61         return sPropertyPrefixes[fType];
62     }
63 
64     @Override
installListeners()65     protected void installListeners() {
66         super.installListeners();
67         IndeterminateListener.install(menuItem);
68     }
69 
70     @Override
uninstallListeners()71     protected void uninstallListeners() {
72         IndeterminateListener.uninstall(menuItem);
73         super.uninstallListeners();
74     }
75 
updateListenersForScreenMenuItem()76     public void updateListenersForScreenMenuItem() {
77         setIsScreenMenu(true);
78     }
79 
80     // Users can dynamically change the kind of menu we're on by calling JPopupMenu.setInvoker
81     // so we need to be prepared to put the listeners back on
setIsScreenMenu(final boolean isScreenMenuItem)82     protected void setIsScreenMenu(final boolean isScreenMenuItem) {
83         if (fIsScreenMenuItem != isScreenMenuItem) {
84             fIsScreenMenuItem = isScreenMenuItem;
85             if (fIsScreenMenuItem) removeListeners();
86             else addListeners();
87         }
88     }
89 
removeListeners()90     protected void removeListeners() {
91         menuItem.removeMouseListener(mouseInputListener);
92         menuItem.removeMouseMotionListener(mouseInputListener);
93         menuItem.removeMenuDragMouseListener(menuDragMouseListener);
94     }
95 
addListeners()96     protected void addListeners() {
97         menuItem.addMouseListener(mouseInputListener);
98         menuItem.addMouseMotionListener(mouseInputListener);
99         menuItem.addMenuDragMouseListener(menuDragMouseListener);
100     }
101 
paintMenuItem(final Graphics g, final JComponent c, final Icon localCheckIcon, final Icon localArrowIcon, final Color background, final Color foreground, final int localDefaultTextIconGap)102     protected void paintMenuItem(final Graphics g, final JComponent c, final Icon localCheckIcon, final Icon localArrowIcon, final Color background, final Color foreground, final int localDefaultTextIconGap) {
103         AquaMenuPainter.instance().paintMenuItem(this, g, c, localCheckIcon, localArrowIcon, background, foreground, disabledForeground, selectionForeground, localDefaultTextIconGap, acceleratorFont);
104     }
105 
getPreferredMenuItemSize(final JComponent c, final Icon localCheckIcon, final Icon localArrowIcon, final int localDefaultTextIconGap)106     protected Dimension getPreferredMenuItemSize(final JComponent c, final Icon localCheckIcon, final Icon localArrowIcon, final int localDefaultTextIconGap) {
107         return AquaMenuPainter.instance().getPreferredMenuItemSize(c, localCheckIcon, localArrowIcon, localDefaultTextIconGap, acceleratorFont);
108     }
109 
update(final Graphics g, final JComponent c)110     public void update(final Graphics g, final JComponent c) {
111         if (c.isOpaque()) {
112             // sja fix ((PenGraphics)g).alphaClearRect(0,0,c.getWidth(),c.getHeight());
113             final Color oldColor = g.getColor();
114             g.setColor(c.getBackground());
115             g.fillRect(0, 0, c.getWidth(), c.getHeight());
116             g.setColor(oldColor);
117         }
118 
119         paint(g, c);
120     }
121 
paintBackground(final Graphics g, final JComponent c, final int menuWidth, final int menuHeight)122     public void paintBackground(final Graphics g, final JComponent c, final int menuWidth, final int menuHeight) {
123         if ((c.getParent() instanceof JMenuBar)) return;
124         final Color oldColor = g.getColor();
125 
126         g.setColor(c.getBackground());
127         g.fillRect(0, 0, menuWidth, menuHeight);
128         if (((JMenuItem)c).isBorderPainted()) {
129             if (((JMenuItem)c).getModel().isArmed()) {
130                 AquaMenuPainter.instance().paintSelectedMenuItemBackground(g, menuWidth, menuHeight);
131             }
132             //getTheme().drawMenuItem(c, g, 0, 0, menuWidth, menuHeight);
133         } else {
134             // If selected, use black (see AquaLookAndFeel "Menu.selectionBackground")
135             if (((JMenuItem)c).getModel().isArmed()) {
136                 final Color holdc = g.getColor();
137                 g.setColor(Color.black);
138                 g.fillRect(0, 0, menuWidth, menuHeight);
139                 g.setColor(holdc);
140             } else {
141                 g.setColor(Color.green);
142                 g.fillRect(0, 0, menuWidth, menuHeight);
143                 //super.paintBackground(g,c,menuWidth, menuHeight); //getTheme().drawMenuBackground((Component)c, g, (short)1, 0, 0, menuWidth, menuHeight);
144             }
145         }
146         g.setColor(oldColor);
147     }
148 
doClick(final MenuSelectionManager msm)149     protected void doClick(final MenuSelectionManager msm) {
150         final Dimension size = menuItem.getSize();
151         AquaUtils.blinkMenu(new AquaUtils.Selectable() {
152             public void paintSelected(final boolean selected) {
153                 menuItem.setArmed(selected);
154                 menuItem.paintImmediately(0, 0, size.width, size.height);
155             }
156         });
157         super.doClick(msm);
158     }
159 
160     static final IndeterminateListener INDETERMINATE_LISTENER = new IndeterminateListener();
161     static class IndeterminateListener implements PropertyChangeListener {
162         static final String CLIENT_PROPERTY_KEY = "JMenuItem.selectedState";
163 
install(final JMenuItem menuItem)164         static void install(final JMenuItem menuItem) {
165             menuItem.addPropertyChangeListener(CLIENT_PROPERTY_KEY, INDETERMINATE_LISTENER);
166             apply(menuItem, menuItem.getClientProperty(CLIENT_PROPERTY_KEY));
167         }
168 
uninstall(final JMenuItem menuItem)169         static void uninstall(final JMenuItem menuItem) {
170             menuItem.removePropertyChangeListener(CLIENT_PROPERTY_KEY, INDETERMINATE_LISTENER);
171         }
172 
propertyChange(final PropertyChangeEvent evt)173         public void propertyChange(final PropertyChangeEvent evt) {
174             final String key = evt.getPropertyName();
175             if (!CLIENT_PROPERTY_KEY.equalsIgnoreCase(key)) return;
176 
177             final Object source = evt.getSource();
178             if (!(source instanceof JMenuItem)) return;
179 
180             final JMenuItem c = (JMenuItem)source;
181             apply(c, evt.getNewValue());
182         }
183 
apply(final JMenuItem menuItem, final Object value)184         static void apply(final JMenuItem menuItem, final Object value) {
185             final ButtonUI ui = menuItem.getUI();
186             if (!(ui instanceof AquaMenuItemUI)) return;
187 
188             final AquaMenuItemUI aquaUI = (AquaMenuItemUI)ui;
189 
190             if (aquaUI.fIsIndeterminate = "indeterminate".equals(value)) {
191                 aquaUI.checkIcon = UIManager.getIcon(aquaUI.getPropertyPrefix() + ".dashIcon");
192             } else {
193                 aquaUI.checkIcon = UIManager.getIcon(aquaUI.getPropertyPrefix() + ".checkIcon");
194             }
195         }
196 
isIndeterminate(final JMenuItem menuItem)197         public static boolean isIndeterminate(final JMenuItem menuItem) {
198             return "indeterminate".equals(menuItem.getClientProperty(CLIENT_PROPERTY_KEY));
199         }
200     }
201 }
202