1 /* 2 * Copyright (c) 1997, 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 package javax.swing; 26 27 import java.awt.*; 28 import java.awt.event.*; 29 30 import javax.swing.event.*; 31 import javax.swing.plaf.*; 32 import javax.accessibility.*; 33 34 import java.io.ObjectOutputStream; 35 import java.io.ObjectInputStream; 36 import java.io.IOException; 37 38 39 /** 40 * An implementation of a two-state button. 41 * The {@code JRadioButton} and {@code JCheckBox} classes 42 * are subclasses of this class. 43 * For information on using them see 44 * <a 45 href="http://docs.oracle.com/javase/tutorial/uiswing/components/button.html">How to Use Buttons, Check Boxes, and Radio Buttons</a>, 46 * a section in <em>The Java Tutorial</em>. 47 * <p> 48 * Buttons can be configured, and to some degree controlled, by 49 * <code><a href="Action.html">Action</a></code>s. Using an 50 * {@code Action} with a button has many benefits beyond directly 51 * configuring a button. Refer to <a href="Action.html#buttonActions"> 52 * Swing Components Supporting {@code Action}</a> for more 53 * details, and you can find more information in <a 54 * href="http://docs.oracle.com/javase/tutorial/uiswing/misc/action.html">How 55 * to Use Actions</a>, a section in <em>The Java Tutorial</em>. 56 * <p> 57 * <strong>Warning:</strong> Swing is not thread safe. For more 58 * information see <a 59 * href="package-summary.html#threading">Swing's Threading 60 * Policy</a>. 61 * <p> 62 * <strong>Warning:</strong> 63 * Serialized objects of this class will not be compatible with 64 * future Swing releases. The current serialization support is 65 * appropriate for short term storage or RMI between applications running 66 * the same version of Swing. As of 1.4, support for long term storage 67 * of all JavaBeans™ 68 * has been added to the {@code java.beans} package. 69 * Please see {@link java.beans.XMLEncoder}. 70 * 71 * @beaninfo 72 * attribute: isContainer false 73 * description: An implementation of a two-state button. 74 * 75 * @see JRadioButton 76 * @see JCheckBox 77 * @author Jeff Dinkins 78 * @since 1.2 79 */ 80 @SuppressWarnings("serial") // Same-version serialization only 81 public class JToggleButton extends AbstractButton implements Accessible { 82 83 /** 84 * @see #getUIClassID 85 * @see #readObject 86 */ 87 private static final String uiClassID = "ToggleButtonUI"; 88 89 /** 90 * Creates an initially unselected toggle button 91 * without setting the text or image. 92 */ 93 public JToggleButton () { 94 this(null, null, false); 95 } 96 97 /** 98 * Creates an initially unselected toggle button 99 * with the specified image but no text. 100 * 101 * @param icon the image that the button should display 102 */ 103 public JToggleButton(Icon icon) { 104 this(null, icon, false); 105 } 106 107 /** 108 * Creates a toggle button with the specified image 109 * and selection state, but no text. 110 * 111 * @param icon the image that the button should display 112 * @param selected if true, the button is initially selected; 113 * otherwise, the button is initially unselected 114 */ 115 public JToggleButton(Icon icon, boolean selected) { 116 this(null, icon, selected); 117 } 118 119 /** 120 * Creates an unselected toggle button with the specified text. 121 * 122 * @param text the string displayed on the toggle button 123 */ 124 public JToggleButton (String text) { 125 this(text, null, false); 126 } 127 128 /** 129 * Creates a toggle button with the specified text 130 * and selection state. 131 * 132 * @param text the string displayed on the toggle button 133 * @param selected if true, the button is initially selected; 134 * otherwise, the button is initially unselected 135 */ 136 public JToggleButton (String text, boolean selected) { 137 this(text, null, selected); 138 } 139 140 /** 141 * Creates a toggle button where properties are taken from the 142 * Action supplied. 143 * 144 * @param a an instance of an {@code Action} 145 * @since 1.3 146 */ 147 public JToggleButton(Action a) { 148 this(); 149 setAction(a); 150 } 151 152 /** 153 * Creates a toggle button that has the specified text and image, 154 * and that is initially unselected. 155 * 156 * @param text the string displayed on the button 157 * @param icon the image that the button should display 158 */ 159 public JToggleButton(String text, Icon icon) { 160 this(text, icon, false); 161 } 162 163 /** 164 * Creates a toggle button with the specified text, image, and 165 * selection state. 166 * 167 * @param text the text of the toggle button 168 * @param icon the image that the button should display 169 * @param selected if true, the button is initially selected; 170 * otherwise, the button is initially unselected 171 */ 172 public JToggleButton (String text, Icon icon, boolean selected) { 173 // Create the model 174 setModel(new ToggleButtonModel()); 175 176 model.setSelected(selected); 177 178 // initialize 179 init(text, icon); 180 } 181 182 /** 183 * Resets the UI property to a value from the current look and feel. 184 * 185 * @see JComponent#updateUI 186 */ 187 public void updateUI() { 188 setUI((ButtonUI)UIManager.getUI(this)); 189 } 190 191 /** 192 * Returns a string that specifies the name of the l&f class 193 * that renders this component. 194 * 195 * @return String "ToggleButtonUI" 196 * @see JComponent#getUIClassID 197 * @see UIDefaults#getUI 198 * @beaninfo 199 * description: A string that specifies the name of the L&F class 200 */ 201 public String getUIClassID() { 202 return uiClassID; 203 } 204 205 206 /** 207 * Overriden to return true, JToggleButton supports 208 * the selected state. 209 */ 210 boolean shouldUpdateSelectedStateFromAction() { 211 return true; 212 } 213 214 // ********************************************************************* 215 216 /** 217 * The ToggleButton model 218 * <p> 219 * <strong>Warning:</strong> 220 * Serialized objects of this class will not be compatible with 221 * future Swing releases. The current serialization support is 222 * appropriate for short term storage or RMI between applications running 223 * the same version of Swing. As of 1.4, support for long term storage 224 * of all JavaBeans™ 225 * has been added to the {@code java.beans} package. 226 * Please see {@link java.beans.XMLEncoder}. 227 */ 228 @SuppressWarnings("serial") // Same-version serialization only 229 public static class ToggleButtonModel extends DefaultButtonModel { 230 231 /** 232 * Creates a new ToggleButton Model 233 */ 234 public ToggleButtonModel () { 235 } 236 237 /** 238 * Checks if the button is selected. 239 */ 240 public boolean isSelected() { 241 // if(getGroup() != null) { 242 // return getGroup().isSelected(this); 243 // } else { 244 return (stateMask & SELECTED) != 0; 245 // } 246 } 247 248 249 /** 250 * Sets the selected state of the button. 251 * @param b true selects the toggle button, 252 * false deselects the toggle button. 253 */ 254 public void setSelected(boolean b) { 255 ButtonGroup group = getGroup(); 256 if (group != null) { 257 // use the group model instead 258 group.setSelected(this, b); 259 b = group.isSelected(this); 260 } 261 262 if (isSelected() == b) { 263 return; 264 } 265 266 if (b) { 267 stateMask |= SELECTED; 268 } else { 269 stateMask &= ~SELECTED; 270 } 271 272 // Send ChangeEvent 273 fireStateChanged(); 274 275 // Send ItemEvent 276 fireItemStateChanged( 277 new ItemEvent(this, 278 ItemEvent.ITEM_STATE_CHANGED, 279 this, 280 this.isSelected() ? ItemEvent.SELECTED : ItemEvent.DESELECTED)); 281 282 } 283 284 /** 285 * Sets the pressed state of the toggle button. 286 */ 287 public void setPressed(boolean b) { 288 if ((isPressed() == b) || !isEnabled()) { 289 return; 290 } 291 292 if (b == false && isArmed()) { 293 setSelected(!this.isSelected()); 294 } 295 296 if (b) { 297 stateMask |= PRESSED; 298 } else { 299 stateMask &= ~PRESSED; 300 } 301 302 fireStateChanged(); 303 304 if(!isPressed() && isArmed()) { 305 int modifiers = 0; 306 AWTEvent currentEvent = EventQueue.getCurrentEvent(); 307 if (currentEvent instanceof InputEvent) { 308 modifiers = ((InputEvent)currentEvent).getModifiers(); 309 } else if (currentEvent instanceof ActionEvent) { 310 modifiers = ((ActionEvent)currentEvent).getModifiers(); 311 } 312 fireActionPerformed( 313 new ActionEvent(this, ActionEvent.ACTION_PERFORMED, 314 getActionCommand(), 315 EventQueue.getMostRecentEventTime(), 316 modifiers)); 317 } 318 319 } 320 } 321 322 323 /** 324 * See readObject() and writeObject() in JComponent for more 325 * information about serialization in Swing. 326 */ 327 private void writeObject(ObjectOutputStream s) throws IOException { 328 s.defaultWriteObject(); 329 if (getUIClassID().equals(uiClassID)) { 330 byte count = JComponent.getWriteObjCounter(this); 331 JComponent.setWriteObjCounter(this, --count); 332 if (count == 0 && ui != null) { 333 ui.installUI(this); 334 } 335 } 336 } 337 338 339 /** 340 * Returns a string representation of this JToggleButton. This method 341 * is intended to be used only for debugging purposes, and the 342 * content and format of the returned string may vary between 343 * implementations. The returned string may be empty but may not 344 * be {@code null}. 345 * 346 * @return a string representation of this JToggleButton. 347 */ 348 protected String paramString() { 349 return super.paramString(); 350 } 351 352 353 ///////////////// 354 // Accessibility support 355 //////////////// 356 357 /** 358 * Gets the AccessibleContext associated with this JToggleButton. 359 * For toggle buttons, the AccessibleContext takes the form of an 360 * AccessibleJToggleButton. 361 * A new AccessibleJToggleButton instance is created if necessary. 362 * 363 * @return an AccessibleJToggleButton that serves as the 364 * AccessibleContext of this JToggleButton 365 * @beaninfo 366 * expert: true 367 * description: The AccessibleContext associated with this ToggleButton. 368 */ 369 public AccessibleContext getAccessibleContext() { 370 if (accessibleContext == null) { 371 accessibleContext = new AccessibleJToggleButton(); 372 } 373 return accessibleContext; 374 } 375 376 /** 377 * This class implements accessibility support for the 378 * {@code JToggleButton} class. It provides an implementation of the 379 * Java Accessibility API appropriate to toggle button user-interface 380 * elements. 381 * <p> 382 * <strong>Warning:</strong> 383 * Serialized objects of this class will not be compatible with 384 * future Swing releases. The current serialization support is 385 * appropriate for short term storage or RMI between applications running 386 * the same version of Swing. As of 1.4, support for long term storage 387 * of all JavaBeans™ 388 * has been added to the {@code java.beans} package. 389 * Please see {@link java.beans.XMLEncoder}. 390 */ 391 @SuppressWarnings("serial") // Same-version serialization only 392 protected class AccessibleJToggleButton extends AccessibleAbstractButton 393 implements ItemListener { 394 395 /** 396 * Constructs {@code AccessibleJToggleButton} 397 */ 398 public AccessibleJToggleButton() { 399 super(); 400 JToggleButton.this.addItemListener(this); 401 } 402 403 /** 404 * Fire accessible property change events when the state of the 405 * toggle button changes. 406 */ 407 public void itemStateChanged(ItemEvent e) { 408 JToggleButton tb = (JToggleButton) e.getSource(); 409 if (JToggleButton.this.accessibleContext != null) { 410 if (tb.isSelected()) { 411 JToggleButton.this.accessibleContext.firePropertyChange( 412 AccessibleContext.ACCESSIBLE_STATE_PROPERTY, 413 null, AccessibleState.CHECKED); 414 } else { 415 JToggleButton.this.accessibleContext.firePropertyChange( 416 AccessibleContext.ACCESSIBLE_STATE_PROPERTY, 417 AccessibleState.CHECKED, null); 418 } 419 } 420 } 421 422 /** 423 * Get the role of this object. 424 * 425 * @return an instance of AccessibleRole describing the role of the 426 * object 427 */ 428 public AccessibleRole getAccessibleRole() { 429 return AccessibleRole.TOGGLE_BUTTON; 430 } 431 } // inner class AccessibleJToggleButton 432 }