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