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 public void setPressed(boolean b) { 243 if((isPressed() == b) || !isEnabled()) { 244 return; 245 } 246 247 if (b) { 248 stateMask |= PRESSED; 249 } else { 250 stateMask &= ~PRESSED; 251 } 252 253 if(!isPressed() && isArmed()) { 254 int modifiers = 0; 255 AWTEvent currentEvent = EventQueue.getCurrentEvent(); 256 if (currentEvent instanceof InputEvent) { 257 modifiers = ((InputEvent)currentEvent).getModifiers(); 258 } else if (currentEvent instanceof ActionEvent) { 259 modifiers = ((ActionEvent)currentEvent).getModifiers(); 260 } 261 fireActionPerformed( 262 new ActionEvent(this, ActionEvent.ACTION_PERFORMED, 263 getActionCommand(), 264 EventQueue.getMostRecentEventTime(), 265 modifiers)); 266 } 267 268 fireStateChanged(); 269 } 270 271 /** 272 * {@inheritDoc} 273 */ 274 public void setRollover(boolean b) { 275 if((isRollover() == b) || !isEnabled()) { 276 return; 277 } 278 279 if (b) { 280 stateMask |= ROLLOVER; 281 } else { 282 stateMask &= ~ROLLOVER; 283 } 284 285 fireStateChanged(); 286 } 287 288 /** 289 * {@inheritDoc} 290 */ 291 public void setMnemonic(int key) { 292 mnemonic = key; 293 fireStateChanged(); 294 } 295 296 /** 297 * {@inheritDoc} 298 */ 299 public int getMnemonic() { 300 return mnemonic; 301 } 302 303 /** 304 * {@inheritDoc} 305 */ 306 public void addChangeListener(ChangeListener l) { 307 listenerList.add(ChangeListener.class, l); 308 } 309 310 /** 311 * {@inheritDoc} 312 */ 313 public void removeChangeListener(ChangeListener l) { 314 listenerList.remove(ChangeListener.class, l); 315 } 316 317 /** 318 * Returns an array of all the change listeners 319 * registered on this <code>DefaultButtonModel</code>. 320 * 321 * @return all of this model's <code>ChangeListener</code>s 322 * or an empty 323 * array if no change listeners are currently registered 324 * 325 * @see #addChangeListener 326 * @see #removeChangeListener 327 * 328 * @since 1.4 329 */ 330 public ChangeListener[] getChangeListeners() { 331 return listenerList.getListeners(ChangeListener.class); 332 } 333 334 /** 335 * Notifies all listeners that have registered interest for 336 * notification on this event type. The event instance 337 * is created lazily. 338 * 339 * @see EventListenerList 340 */ 341 protected void fireStateChanged() { 342 // Guaranteed to return a non-null array 343 Object[] listeners = listenerList.getListenerList(); 344 // Process the listeners last to first, notifying 345 // those that are interested in this event 346 for (int i = listeners.length-2; i>=0; i-=2) { 347 if (listeners[i]==ChangeListener.class) { 348 // Lazily create the event: 349 if (changeEvent == null) 350 changeEvent = new ChangeEvent(this); 351 ((ChangeListener)listeners[i+1]).stateChanged(changeEvent); 352 } 353 } 354 } 355 356 /** 357 * {@inheritDoc} 358 */ 359 public void addActionListener(ActionListener l) { 360 listenerList.add(ActionListener.class, l); 361 } 362 363 /** 364 * {@inheritDoc} 365 */ 366 public void removeActionListener(ActionListener l) { 367 listenerList.remove(ActionListener.class, l); 368 } 369 370 /** 371 * Returns an array of all the action listeners 372 * registered on this <code>DefaultButtonModel</code>. 373 * 374 * @return all of this model's <code>ActionListener</code>s 375 * or an empty 376 * array if no action listeners are currently registered 377 * 378 * @see #addActionListener 379 * @see #removeActionListener 380 * 381 * @since 1.4 382 */ 383 public ActionListener[] getActionListeners() { 384 return listenerList.getListeners(ActionListener.class); 385 } 386 387 /** 388 * Notifies all listeners that have registered interest for 389 * notification on this event type. 390 * 391 * @param e the <code>ActionEvent</code> to deliver to listeners 392 * @see EventListenerList 393 */ 394 protected void fireActionPerformed(ActionEvent e) { 395 // Guaranteed to return a non-null array 396 Object[] listeners = listenerList.getListenerList(); 397 // Process the listeners last to first, notifying 398 // those that are interested in this event 399 for (int i = listeners.length-2; i>=0; i-=2) { 400 if (listeners[i]==ActionListener.class) { 401 // Lazily create the event: 402 // if (changeEvent == null) 403 // changeEvent = new ChangeEvent(this); 404 ((ActionListener)listeners[i+1]).actionPerformed(e); 405 } 406 } 407 } 408 409 /** 410 * {@inheritDoc} 411 */ 412 public void addItemListener(ItemListener l) { 413 listenerList.add(ItemListener.class, l); 414 } 415 416 /** 417 * {@inheritDoc} 418 */ 419 public void removeItemListener(ItemListener l) { 420 listenerList.remove(ItemListener.class, l); 421 } 422 423 /** 424 * Returns an array of all the item listeners 425 * registered on this <code>DefaultButtonModel</code>. 426 * 427 * @return all of this model's <code>ItemListener</code>s 428 * or an empty 429 * array if no item listeners are currently registered 430 * 431 * @see #addItemListener 432 * @see #removeItemListener 433 * 434 * @since 1.4 435 */ 436 public ItemListener[] getItemListeners() { 437 return listenerList.getListeners(ItemListener.class); 438 } 439 440 /** 441 * Notifies all listeners that have registered interest for 442 * notification on this event type. 443 * 444 * @param e the <code>ItemEvent</code> to deliver to listeners 445 * @see EventListenerList 446 */ 447 protected void fireItemStateChanged(ItemEvent e) { 448 // Guaranteed to return a non-null array 449 Object[] listeners = listenerList.getListenerList(); 450 // Process the listeners last to first, notifying 451 // those that are interested in this event 452 for (int i = listeners.length-2; i>=0; i-=2) { 453 if (listeners[i]==ItemListener.class) { 454 // Lazily create the event: 455 // if (changeEvent == null) 456 // changeEvent = new ChangeEvent(this); 457 ((ItemListener)listeners[i+1]).itemStateChanged(e); 458 } 459 } 460 } 461 462 /** 463 * Returns an array of all the objects currently registered as 464 * <code><em>Foo</em>Listener</code>s 465 * upon this model. 466 * <code><em>Foo</em>Listener</code>s 467 * are registered using the <code>add<em>Foo</em>Listener</code> method. 468 * <p> 469 * You can specify the <code>listenerType</code> argument 470 * with a class literal, such as <code><em>Foo</em>Listener.class</code>. 471 * For example, you can query a <code>DefaultButtonModel</code> 472 * instance <code>m</code> 473 * for its action listeners 474 * with the following code: 475 * 476 * <pre>ActionListener[] als = (ActionListener[])(m.getListeners(ActionListener.class));</pre> 477 * 478 * If no such listeners exist, 479 * this method returns an empty array. 480 * 481 * @param <T> the type of requested listeners 482 * @param listenerType the type of listeners requested; 483 * this parameter should specify an interface 484 * that descends from <code>java.util.EventListener</code> 485 * @return an array of all objects registered as 486 * <code><em>Foo</em>Listener</code>s 487 * on this model, 488 * or an empty array if no such 489 * listeners have been added 490 * @exception ClassCastException if <code>listenerType</code> doesn't 491 * specify a class or interface that implements 492 * <code>java.util.EventListener</code> 493 * 494 * @see #getActionListeners 495 * @see #getChangeListeners 496 * @see #getItemListeners 497 * 498 * @since 1.3 499 */ 500 public <T extends EventListener> T[] getListeners(Class<T> listenerType) { 501 return listenerList.getListeners(listenerType); 502 } 503 504 /** Overridden to return <code>null</code>. */ 505 public Object[] getSelectedObjects() { 506 return null; 507 } 508 509 /** 510 * {@inheritDoc} 511 */ 512 public void setGroup(ButtonGroup group) { 513 this.group = group; 514 } 515 516 /** 517 * Returns the group that the button belongs to. 518 * Normally used with radio buttons, which are mutually 519 * exclusive within their group. 520 * 521 * @return the <code>ButtonGroup</code> that the button belongs to 522 * 523 * @since 1.3 524 */ 525 public ButtonGroup getGroup() { 526 return group; 527 } 528 529 boolean isMenuItem() { 530 return menuItem; 531 } 532 533 void setMenuItem(boolean menuItem) { 534 this.menuItem = menuItem; 535 } 536 }