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