1 /* 2 * Copyright (c) 2011, 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 com.apple.laf; 27 28 import java.awt.*; 29 import java.awt.event.*; 30 import java.awt.peer.MenuComponentPeer; 31 32 import javax.swing.*; 33 import javax.swing.plaf.ButtonUI; 34 35 import com.apple.laf.AquaMenuItemUI.IndeterminateListener; 36 37 import sun.lwawt.macosx.*; 38 39 @SuppressWarnings("serial") // JDK implementation class 40 final class ScreenMenuItemCheckbox extends CheckboxMenuItem implements ActionListener, ComponentListener, ScreenMenuPropertyHandler, ItemListener { 41 JMenuItem fMenuItem; 42 MenuContainer fParent; 43 44 ScreenMenuItemCheckbox(final JCheckBoxMenuItem mi) { 45 super(mi.getText(), mi.getState()); 46 init(mi); 47 } 48 49 ScreenMenuItemCheckbox(final JRadioButtonMenuItem mi) { 50 super(mi.getText(), mi.getModel().isSelected()); 51 init(mi); 52 } 53 54 public void init(final JMenuItem mi) { 55 fMenuItem = mi; 56 setEnabled(fMenuItem.isEnabled()); 57 } 58 59 ScreenMenuPropertyListener fPropertyListener; 60 @SuppressWarnings("deprecation") 61 public void addNotify() { 62 super.addNotify(); 63 64 // Avoid the Auto toggle behavior of AWT CheckBoxMenuItem 65 CCheckboxMenuItem ccb = (CCheckboxMenuItem) getPeer(); 66 ccb.setAutoToggle(false); 67 68 fMenuItem.addComponentListener(this); 69 fPropertyListener = new ScreenMenuPropertyListener(this); 70 fMenuItem.addPropertyChangeListener(fPropertyListener); 71 addActionListener(this); 72 addItemListener(this); 73 fMenuItem.addItemListener(this); 74 setIndeterminate(IndeterminateListener.isIndeterminate(fMenuItem)); 75 76 // can't setState or setAccelerator or setIcon till we have a peer 77 setAccelerator(fMenuItem.getAccelerator()); 78 79 final Icon icon = fMenuItem.getIcon(); 80 if (icon != null) { 81 this.setIcon(icon); 82 } 83 84 final String tooltipText = fMenuItem.getToolTipText(); 85 if (tooltipText != null) { 86 this.setToolTipText(tooltipText); 87 } 88 89 // sja fix is this needed? 90 fMenuItem.addItemListener(this); 91 92 final ButtonUI ui = fMenuItem.getUI(); 93 if (ui instanceof ScreenMenuItemUI) { 94 ((ScreenMenuItemUI)ui).updateListenersForScreenMenuItem(); 95 } 96 97 if (fMenuItem instanceof JCheckBoxMenuItem) { 98 forceSetState(fMenuItem.isSelected()); 99 } else { 100 forceSetState(fMenuItem.getModel().isSelected()); 101 } 102 } 103 104 public void removeNotify() { 105 fMenuItem.removeComponentListener(this); 106 fMenuItem.removePropertyChangeListener(fPropertyListener); 107 fPropertyListener = null; 108 removeActionListener(this); 109 removeItemListener(this); 110 fMenuItem.removeItemListener(this); 111 112 super.removeNotify(); 113 } 114 115 @Override 116 public synchronized void setLabel(final String label) { 117 ScreenMenuItem.syncLabelAndKS(this, label, fMenuItem.getAccelerator()); 118 } 119 120 @Override 121 public void setAccelerator(final KeyStroke ks) { 122 ScreenMenuItem.syncLabelAndKS(this, fMenuItem.getText(), ks); 123 } 124 125 public void actionPerformed(final ActionEvent e) { 126 fMenuItem.doClick(0); // This takes care of all the different events 127 } 128 129 /** 130 * Invoked when the component's size changes. 131 */ 132 public void componentResized(final ComponentEvent e) {} 133 134 /** 135 * Invoked when the component's position changes. 136 */ 137 public void componentMoved(final ComponentEvent e) {} 138 139 /** 140 * Invoked when the component has been made visible. 141 * See componentHidden - we should still have a MenuItem 142 * it just isn't inserted 143 */ 144 public void componentShown(final ComponentEvent e) { 145 setVisible(true); 146 } 147 148 /** 149 * Invoked when the component has been made invisible. 150 * MenuComponent.setVisible does nothing, 151 * so we remove the ScreenMenuItem from the ScreenMenu 152 * but leave it in fItems 153 */ 154 public void componentHidden(final ComponentEvent e) { 155 setVisible(false); 156 } 157 158 @SuppressWarnings("deprecation") 159 public void setToolTipText(final String text) { 160 final MenuComponentPeer peer = getPeer(); 161 if (!(peer instanceof CMenuItem)) return; 162 163 ((CMenuItem)peer).setToolTipText(text); 164 } 165 166 @SuppressWarnings("deprecation") 167 public void setIcon(final Icon i) { 168 final MenuComponentPeer peer = getPeer(); 169 if (!(peer instanceof CMenuItem)) return; 170 171 final CMenuItem cmi = (CMenuItem)peer; 172 Image img = null; 173 174 if (i != null) { 175 if (i.getIconWidth() > 0 && i.getIconHeight() > 0) { 176 img = AquaIcon.getImageForIcon(i); 177 } 178 } 179 cmi.setImage(img); 180 } 181 182 public void setVisible(final boolean b) { 183 // Tell our parent to add/remove us 184 // Hang on to our parent 185 if (fParent == null) fParent = getParent(); 186 ((ScreenMenuPropertyHandler)fParent).setChildVisible(fMenuItem, b); 187 } 188 189 // we have no children 190 public void setChildVisible(final JMenuItem child, final boolean b) {} 191 192 /** 193 * Invoked when an item's state has been changed. 194 */ 195 public void itemStateChanged(final ItemEvent e) { 196 if (e.getSource() == this) { 197 fMenuItem.doClick(0); 198 return; 199 } 200 201 switch (e.getStateChange()) { 202 case ItemEvent.SELECTED: 203 forceSetState(true); 204 break; 205 case ItemEvent.DESELECTED: 206 forceSetState(false); 207 break; 208 } 209 } 210 211 @SuppressWarnings("deprecation") 212 public void setIndeterminate(final boolean indeterminate) { 213 final MenuComponentPeer peer = getPeer(); 214 if (peer instanceof CCheckboxMenuItem) { 215 ((CCheckboxMenuItem)peer).setIsIndeterminate(indeterminate); 216 } 217 } 218 219 /* 220 * The CCheckboxMenuItem peer is calling setState unconditionally every time user clicks the menu 221 * However for Swing controls in the screen menu bar it is wrong - the state should be changed only 222 * in response to the ITEM_STATE_CHANGED event. So the setState is overridden to no-op and all the 223 * correct state changes are made with forceSetState 224 */ 225 226 @Override 227 public synchronized void setState(boolean b) { 228 // No Op 229 } 230 231 private void forceSetState(boolean b) { 232 super.setState(b); 233 } 234 }