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 26package com.apple.laf; 27 28import java.awt.*; 29import java.beans.*; 30 31import javax.swing.*; 32import javax.swing.plaf.*; 33import javax.swing.plaf.basic.BasicMenuItemUI; 34 35import apple.laf.JRSUIConstants.Size; 36 37// TODO: no screen menu bar for now 38public 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 46 AquaMenuItemUI(final int type) { 47 super(); 48 fType = type; 49 } 50 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! 60 protected String getPropertyPrefix() { 61 return sPropertyPrefixes[fType]; 62 } 63 64 @Override 65 protected void installListeners() { 66 super.installListeners(); 67 IndeterminateListener.install(menuItem); 68 } 69 70 @Override 71 protected void uninstallListeners() { 72 IndeterminateListener.uninstall(menuItem); 73 super.uninstallListeners(); 74 } 75 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 82 protected void setIsScreenMenu(final boolean isScreenMenuItem) { 83 if (fIsScreenMenuItem != isScreenMenuItem) { 84 fIsScreenMenuItem = isScreenMenuItem; 85 if (fIsScreenMenuItem) removeListeners(); 86 else addListeners(); 87 } 88 } 89 90 protected void removeListeners() { 91 menuItem.removeMouseListener(mouseInputListener); 92 menuItem.removeMouseMotionListener(mouseInputListener); 93 menuItem.removeMenuDragMouseListener(menuDragMouseListener); 94 } 95 96 protected void addListeners() { 97 menuItem.addMouseListener(mouseInputListener); 98 menuItem.addMouseMotionListener(mouseInputListener); 99 menuItem.addMenuDragMouseListener(menuDragMouseListener); 100 } 101 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 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 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 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 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 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 169 static void uninstall(final JMenuItem menuItem) { 170 menuItem.removePropertyChangeListener(CLIENT_PROPERTY_KEY, INDETERMINATE_LISTENER); 171 } 172 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 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 197 public static boolean isIndeterminate(final JMenuItem menuItem) { 198 return "indeterminate".equals(menuItem.getClientProperty(CLIENT_PROPERTY_KEY)); 199 } 200 } 201} 202