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