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