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 import java.awt.image.*; 30 import java.io.Serializable; 31 import java.util.EventListener; 32 import javax.swing.event.*; 33 34 /** 35 * The default implementation of a <code>Button</code> component's data model. 36 * <p> 37 * <strong>Warning:</strong> 38 * Serialized objects of this class will not be compatible with 39 * future Swing releases. The current serialization support is 40 * appropriate for short term storage or RMI between applications running 41 * the same version of Swing. As of 1.4, support for long term storage 42 * of all JavaBeans 43 * has been added to the <code>java.beans</code> package. 44 * Please see {@link java.beans.XMLEncoder}. 45 * 46 * @author Jeff Dinkins 47 * @since 1.2 48 */ 49 @SuppressWarnings("serial") // Same-version serialization only 50 public class DefaultButtonModel implements ButtonModel, Serializable { 51 52 /** The bitmask used to store the state of the button. */ 53 protected int stateMask = 0; 54 55 /** The action command string fired by the button. */ 56 protected String actionCommand = null; 57 58 /** The button group that the button belongs to. */ 59 protected ButtonGroup group = null; 60 61 /** The button's mnemonic. */ 62 protected int mnemonic = 0; 63 64 /** 65 * Only one <code>ChangeEvent</code> is needed per button model 66 * instance since the event's only state is the source property. 67 * The source of events generated is always "this". 68 */ 69 protected transient ChangeEvent changeEvent = null; 70 71 /** Stores the listeners on this model. */ 72 protected EventListenerList listenerList = new EventListenerList(); 73 74 // controls the usage of the MenuItem.disabledAreNavigable UIDefaults 75 // property in the setArmed() method 76 private boolean menuItem = false; 77 78 /** 79 * Constructs a <code>DefaultButtonModel</code>. 80 * 81 */ 82 public DefaultButtonModel() { 83 stateMask = 0; 84 setEnabled(true); 85 } 86 87 /** 88 * Identifies the "armed" bit in the bitmask, which 89 * indicates partial commitment towards choosing/triggering 90 * the button. 91 */ 92 public static final int ARMED = 1 << 0; 93 94 /** 95 * Identifies the "selected" bit in the bitmask, which 96 * indicates that the button has been selected. Only needed for 97 * certain types of buttons - such as radio button or check box. 98 */ 99 public static final int SELECTED = 1 << 1; 100 101 /** 102 * Identifies the "pressed" bit in the bitmask, which 103 * indicates that the button is pressed. 104 */ 105 public static final int PRESSED = 1 << 2; 106 107 /** 108 * Identifies the "enabled" bit in the bitmask, which 109 * indicates that the button can be selected by 110 * an input device (such as a mouse pointer). 111 */ 112 public static final int ENABLED = 1 << 3; 113 114 /** 115 * Identifies the "rollover" bit in the bitmask, which 116 * indicates that the mouse is over the button. 117 */ 118 public static final int ROLLOVER = 1 << 4; 119 120 /** 121 * {@inheritDoc} 122 */ 123 public void setActionCommand(String actionCommand) { 124 this.actionCommand = actionCommand; 125 } 126 127 /** 128 * {@inheritDoc} 129 */ 130 public String getActionCommand() { 131 return actionCommand; 132 } 133 134 /** 135 * {@inheritDoc} 136 */ 137 public boolean isArmed() { 138 return (stateMask & ARMED) != 0; 139 } 140 141 /** 142 * {@inheritDoc} 143 */ 144 public boolean isSelected() { 145 return (stateMask & SELECTED) != 0; 146 } 147 148 /** 149 * {@inheritDoc} 150 */ 151 public boolean isEnabled() { 152 return (stateMask & ENABLED) != 0; 153 } 154 155 /** 156 * {@inheritDoc} 157 */ 158 public boolean isPressed() { 159 return (stateMask & PRESSED) != 0; 160 } 161 162 /** 163 * {@inheritDoc} 164 */ 165 public boolean isRollover() { 166 return (stateMask & ROLLOVER) != 0; 167 } 168 169 /** 170 * {@inheritDoc} 171 */ 172 public void setArmed(boolean b) { 173 if(isMenuItem() && 174 UIManager.getBoolean("MenuItem.disabledAreNavigable")) { 175 if ((isArmed() == b)) { 176 return; 177 } 178 } else { 179 if ((isArmed() == b) || !isEnabled()) { 180 return; 181 } 182 } 183 184 if (b) { 185 stateMask |= ARMED; 186 } else { 187 stateMask &= ~ARMED; 188 } 189 190 fireStateChanged(); 191 } 192 193 /** 194 * {@inheritDoc} 195 */ 196 public void setEnabled(boolean b) { 197 if(isEnabled() == b) { 198 return; 199 } 200 201 if (b) { 202 stateMask |= ENABLED; 203 } else { 204 stateMask &= ~ENABLED; 205 // unarm and unpress, just in case 206 stateMask &= ~ARMED; 207 stateMask &= ~PRESSED; 208 } 209 210 211 fireStateChanged(); 212 } 213 214 /** 215 * {@inheritDoc} 216 */ 217 public void setSelected(boolean b) { 218 if (this.isSelected() == b) { 219 return; 220 } 221 222 if (b) { 223 stateMask |= SELECTED; 224 } else { 225 stateMask &= ~SELECTED; 226 } 227 228 fireItemStateChanged( 229 new ItemEvent(this, 230 ItemEvent.ITEM_STATE_CHANGED, 231 this, 232 b ? ItemEvent.SELECTED : ItemEvent.DESELECTED)); 233 234 fireStateChanged(); 235 236 } 237 238 239 /** 240 * {@inheritDoc} 241 */ 242 @SuppressWarnings("deprecation") 243 public void setPressed(boolean b) { 244 if((isPressed() == b) || !isEnabled()) { 245 return; 246 } 247 248 if (b) { 249 stateMask |= PRESSED; 250 } else { 251 stateMask &= ~PRESSED; 252 } 253 254 if(!isPressed() && isArmed()) { 255 int modifiers = 0; 256 AWTEvent currentEvent = EventQueue.getCurrentEvent(); 257 if (currentEvent instanceof InputEvent) { 258 modifiers = ((InputEvent)currentEvent).getModifiers(); 259 } else if (currentEvent instanceof ActionEvent) { 260 modifiers = ((ActionEvent)currentEvent).getModifiers(); 261 } 262 fireActionPerformed( 263 new ActionEvent(this, ActionEvent.ACTION_PERFORMED, 264 getActionCommand(), 265 EventQueue.getMostRecentEventTime(), 266 modifiers)); 267 } 268 269 fireStateChanged(); 270 } 271 272 /** 273 * {@inheritDoc} 274 */ 275 public void setRollover(boolean b) { 276 if((isRollover() == b) || !isEnabled()) { 277 return; 278 } 279 280 if (b) { 281 stateMask |= ROLLOVER; 282 } else { 283 stateMask &= ~ROLLOVER; 284 } 285 286 fireStateChanged(); 287 } 288 289 /** 290 * {@inheritDoc} 291 */ 292 public void setMnemonic(int key) { 293 mnemonic = key; 294 fireStateChanged(); 295 } 296 297 /** 298 * {@inheritDoc} 299 */ 300 public int getMnemonic() { 301 return mnemonic; 302 } 303 304 /** 305 * {@inheritDoc} 306 */ 307 public void addChangeListener(ChangeListener l) { 308 listenerList.add(ChangeListener.class, l); 309 } 310 311 /** 312 * {@inheritDoc} 313 */ 314 public void removeChangeListener(ChangeListener l) { 315 listenerList.remove(ChangeListener.class, l); 316 } 317 318 /** 319 * Returns an array of all the change listeners 320 * registered on this <code>DefaultButtonModel</code>. 321 * 322 * @return all of this model's <code>ChangeListener</code>s 323 * or an empty 324 * array if no change listeners are currently registered 325 * 326 * @see #addChangeListener 327 * @see #removeChangeListener 328 * 329 * @since 1.4 330 */ 331 public ChangeListener[] getChangeListeners() { 332 return listenerList.getListeners(ChangeListener.class); 333 } 334 335 /** 336 * Notifies all listeners that have registered interest for 337 * notification on this event type. The event instance 338 * is created lazily. 339 * 340 * @see EventListenerList 341 */ 342 protected void fireStateChanged() { 343 // Guaranteed to return a non-null array 344 Object[] listeners = listenerList.getListenerList(); 345 // Process the listeners last to first, notifying 346 // those that are interested in this event 347 for (int i = listeners.length-2; i>=0; i-=2) { 348 if (listeners[i]==ChangeListener.class) { 349 // Lazily create the event: 350 if (changeEvent == null) 351 changeEvent = new ChangeEvent(this); 352 ((ChangeListener)listeners[i+1]).stateChanged(changeEvent); 353 } 354 } 355 } 356 357 /** 358 * {@inheritDoc} 359 */ 360 public void addActionListener(ActionListener l) { 361 listenerList.add(ActionListener.class, l); 362 } 363 364 /** 365 * {@inheritDoc} 366 */ 367 public void removeActionListener(ActionListener l) { 368 listenerList.remove(ActionListener.class, l); 369 } 370 371 /** 372 * Returns an array of all the action listeners 373 * registered on this <code>DefaultButtonModel</code>. 374 * 375 * @return all of this model's <code>ActionListener</code>s 376 * or an empty 377 * array if no action listeners are currently registered 378 * 379 * @see #addActionListener 380 * @see #removeActionListener 381 * 382 * @since 1.4 383 */ 384 public ActionListener[] getActionListeners() { 385 return listenerList.getListeners(ActionListener.class); 386 } 387 388 /** 389 * Notifies all listeners that have registered interest for 390 * notification on this event type. 391 * 392 * @param e the <code>ActionEvent</code> to deliver to listeners 393 * @see EventListenerList 394 */ 395 protected void fireActionPerformed(ActionEvent e) { 396 // Guaranteed to return a non-null array 397 Object[] listeners = listenerList.getListenerList(); 398 // Process the listeners last to first, notifying 399 // those that are interested in this event 400 for (int i = listeners.length-2; i>=0; i-=2) { 401 if (listeners[i]==ActionListener.class) { 402 // Lazily create the event: 403 // if (changeEvent == null) 404 // changeEvent = new ChangeEvent(this); 405 ((ActionListener)listeners[i+1]).actionPerformed(e); 406 } 407 } 408 } 409 410 /** 411 * {@inheritDoc} 412 */ 413 public void addItemListener(ItemListener l) { 414 listenerList.add(ItemListener.class, l); 415 } 416 417 /** 418 * {@inheritDoc} 419 */ 420 public void removeItemListener(ItemListener l) { 421 listenerList.remove(ItemListener.class, l); 422 } 423 424 /** 425 * Returns an array of all the item listeners 426 * registered on this <code>DefaultButtonModel</code>. 427 * 428 * @return all of this model's <code>ItemListener</code>s 429 * or an empty 430 * array if no item listeners are currently registered 431 * 432 * @see #addItemListener 433 * @see #removeItemListener 434 * 435 * @since 1.4 436 */ 437 public ItemListener[] getItemListeners() { 438 return listenerList.getListeners(ItemListener.class); 439 } 440 441 /** 442 * Notifies all listeners that have registered interest for 443 * notification on this event type. 444 * 445 * @param e the <code>ItemEvent</code> to deliver to listeners 446 * @see EventListenerList 447 */ 448 protected void fireItemStateChanged(ItemEvent e) { 449 // Guaranteed to return a non-null array 450 Object[] listeners = listenerList.getListenerList(); 451 // Process the listeners last to first, notifying 452 // those that are interested in this event 453 for (int i = listeners.length-2; i>=0; i-=2) { 454 if (listeners[i]==ItemListener.class) { 455 // Lazily create the event: 456 // if (changeEvent == null) 457 // changeEvent = new ChangeEvent(this); 458 ((ItemListener)listeners[i+1]).itemStateChanged(e); 459 } 460 } 461 } 462 463 /** 464 * Returns an array of all the objects currently registered as 465 * <code><em>Foo</em>Listener</code>s 466 * upon this model. 467 * <code><em>Foo</em>Listener</code>s 468 * are registered using the <code>add<em>Foo</em>Listener</code> method. 469 * <p> 470 * You can specify the <code>listenerType</code> argument 471 * with a class literal, such as <code><em>Foo</em>Listener.class</code>. 472 * For example, you can query a <code>DefaultButtonModel</code> 473 * instance <code>m</code> 474 * for its action listeners 475 * with the following code: 476 * 477 * <pre>ActionListener[] als = (ActionListener[])(m.getListeners(ActionListener.class));</pre> 478 * 479 * If no such listeners exist, 480 * this method returns an empty array. 481 * 482 * @param <T> the type of requested listeners 483 * @param listenerType the type of listeners requested; 484 * this parameter should specify an interface 485 * that descends from <code>java.util.EventListener</code> 486 * @return an array of all objects registered as 487 * <code><em>Foo</em>Listener</code>s 488 * on this model, 489 * or an empty array if no such 490 * listeners have been added 491 * @exception ClassCastException if <code>listenerType</code> doesn't 492 * specify a class or interface that implements 493 * <code>java.util.EventListener</code> 494 * 495 * @see #getActionListeners 496 * @see #getChangeListeners 497 * @see #getItemListeners 498 * 499 * @since 1.3 500 */ 501 public <T extends EventListener> T[] getListeners(Class<T> listenerType) { 502 return listenerList.getListeners(listenerType); 503 } 504 505 /** Overridden to return <code>null</code>. */ 506 public Object[] getSelectedObjects() { 507 return null; 508 } 509 510 /** 511 * {@inheritDoc} 512 */ 513 public void setGroup(ButtonGroup group) { 514 this.group = group; 515 } 516 517 /** 518 * Returns the group that the button belongs to. 519 * Normally used with radio buttons, which are mutually 520 * exclusive within their group. 521 * 522 * @return the <code>ButtonGroup</code> that the button belongs to 523 * 524 * @since 1.3 525 */ 526 public ButtonGroup getGroup() { 527 return group; 528 } 529 530 boolean isMenuItem() { 531 return menuItem; 532 } 533 534 void setMenuItem(boolean menuItem) { 535 this.menuItem = menuItem; 536 } 537 }