Source for javax.swing.DefaultButtonModel

   1: /* DefaultButtonModel.java --
   2:    Copyright (C) 2002, 2004 Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package javax.swing;
  40: 
  41: import java.awt.event.ActionEvent;
  42: import java.awt.event.ActionListener;
  43: import java.awt.event.ItemEvent;
  44: import java.awt.event.ItemListener;
  45: import java.awt.event.KeyEvent;
  46: import java.io.Serializable;
  47: import java.util.EventListener;
  48: 
  49: import javax.swing.event.ChangeEvent;
  50: import javax.swing.event.ChangeListener;
  51: import javax.swing.event.EventListenerList;
  52: 
  53: /**
  54:  * The pUrpose of this class is to model the dynamic state of an abstract
  55:  * button. The concrete button type holding this state may be a a "toggle"
  56:  * button (checkbox, radio button) or a "push" button (menu button, button).
  57:  * If the model is disabled, only the "selected" property can be changed. An
  58:  * attempt to change the "armed", "rollover" or "pressed" properties  while
  59:  * the model is disabled will be blocked. Any successful (non-blocked) change
  60:  * to the model's properties will trigger the firing of a ChangeEvent. Any
  61:  * change to the "selected" property will trigger the firing of an ItemEvent
  62:  * in addition to ChangeEvent. This is true whether the model is enabled or
  63:  * not. One other state change is special: the transition from "enabled,
  64:  * armed and pressd" to "enabled, armed and not-pressed". This is considered
  65:  * the "trailing edge" of a successful mouse click, and therefore fires an
  66:  * ActionEvent in addition to a ChangeEvent. In all other respects this class
  67:  * is just a container of boolean flags.
  68:  *
  69:  * @author Graydon Hoare (graydon_at_redhat.com)
  70:  */
  71: public class DefaultButtonModel implements ButtonModel, Serializable
  72: {
  73:   /** DOCUMENT ME! */
  74:   private static final long serialVersionUID = -5342609566534980231L;
  75: 
  76:   /**
  77:    * Indicates that the button is <em>partially</em> committed to being
  78:    * pressed, but not entirely. This usually happens when a user has pressed
  79:    * but not yet released the mouse button.
  80:    */
  81:   public static final int ARMED = 1;
  82: 
  83:   /**
  84:    * State constant indicating that the button is enabled. Buttons cannot be
  85:    * pressed or selected unless they are enabled.
  86:    */
  87:   public static final int ENABLED = 8;
  88: 
  89:   /**
  90:    * State constant indicating that the user is holding down the button. When
  91:    * this transitions from true to false, an ActionEvent may be fired,
  92:    * depending on the value of the "armed" property.
  93:    */
  94:   public static final int PRESSED = 4;
  95: 
  96:   /**
  97:    * State constant indicating that the mouse is currently positioned over the
  98:    * button.
  99:    */
 100:   public static final int ROLLOVER = 16;
 101: 
 102:   /**
 103:    * State constant indicating that the button is selected. This constant is
 104:    * only meaningful for toggle-type buttons (radio buttons, checkboxes).
 105:    */
 106:   public static final int SELECTED = 2;
 107: 
 108:   /**
 109:    * Represents the "state properties" (armed, enabled, pressed, rollover and
 110:    * selected) by a bitwise combination of integer constants.
 111:    */
 112:   protected int stateMask = ENABLED;
 113: 
 114:   /**
 115:    * List of ItemListeners, ChangeListeners, and ActionListeners registered on
 116:    * this model.
 117:    */
 118:   protected EventListenerList listenerList = new EventListenerList();
 119: 
 120:   /** The single ChangeEvent this model (re)uses to call its ChangeListeners. */
 121:   protected ChangeEvent changeEvent = new ChangeEvent(this);
 122: 
 123:   /**
 124:    * The group this model belongs to. Only one button in a group may be
 125:    * selected at any given time.
 126:    */
 127:   protected ButtonGroup group;
 128: 
 129:   /**
 130:    * The key code (one of {@link java.awt.event.KeyEvent} VK_) used to press
 131:    * this button via a keyboard interface.
 132:    */
 133:   protected int mnemonic = KeyEvent.VK_UNDEFINED;
 134: 
 135:   /**
 136:    * The string used as the "command" property of any ActionEvent this model
 137:    * sends.
 138:    */
 139:   protected String actionCommand;
 140: 
 141:   /**
 142:    * Creates a new DefaultButtonModel object.
 143:    */
 144:   public DefaultButtonModel()
 145:   {
 146:   }
 147: 
 148:   /**
 149:    * Return <code>null</code>. Use {@link AbstractButton} if you wish to
 150:    * interface with a button via an {@link ItemSelectable} interface.
 151:    *
 152:    * @return <code>null</code>
 153:    */
 154:   public Object[] getSelectedObjects()
 155:   {
 156:     return null;
 157:   }
 158: 
 159:   /**
 160:    * Returns a specified class of listeners.
 161:    *
 162:    * @param listenerType the type of listener to return
 163:    *
 164:    * @return array of listeners
 165:    */
 166:   public EventListener[] getListeners(Class listenerType)
 167:   {
 168:     return listenerList.getListeners(listenerType);
 169:   }
 170: 
 171:   /**
 172:    * Add an ActionListener to the model. Usually only called to subscribe an
 173:    * AbstractButton's listener to the model.
 174:    *
 175:    * @param l The listener to add
 176:    */
 177:   public void addActionListener(ActionListener l)
 178:   {
 179:     listenerList.add(ActionListener.class, l);
 180:   }
 181: 
 182:   /**
 183:    * Remove an ActionListener to the model. Usually only called to unsubscribe
 184:    * an AbstractButton's listener to the model.
 185:    *
 186:    * @param l The listener to remove
 187:    */
 188:   public void removeActionListener(ActionListener l)
 189:   {
 190:     listenerList.remove(ActionListener.class, l);
 191:   }
 192: 
 193:   /**
 194:    * Returns all registered <code>ActionListener</code> objects.
 195:    *
 196:    * @return array of <code>ActionListener</code> objects
 197:    */
 198:   public ActionListener[] getActionListeners()
 199:   {
 200:     return (ActionListener[]) listenerList.getListeners(ActionListener.class);
 201:   }
 202: 
 203:   /**
 204:    * Add an ItemListener to the model. Usually only called to subscribe an
 205:    * AbstractButton's listener to the model.
 206:    *
 207:    * @param l The listener to add
 208:    */
 209:   public void addItemListener(ItemListener l)
 210:   {
 211:     listenerList.add(ItemListener.class, l);
 212:   }
 213: 
 214:   /**
 215:    * Remove an ItemListener to the model. Usually only called to unsubscribe
 216:    * an AbstractButton's listener to the model.
 217:    *
 218:    * @param l The listener to remove
 219:    */
 220:   public void removeItemListener(ItemListener l)
 221:   {
 222:     listenerList.remove(ItemListener.class, l);
 223:   }
 224: 
 225:   /**
 226:    * Returns all registered <code>ItemListener</code> objects.
 227:    *
 228:    * @return array of <code>ItemListener</code> objects
 229:    */
 230:   public ItemListener[] getItemListeners()
 231:   {
 232:     return (ItemListener[]) listenerList.getListeners(ItemListener.class);
 233:   }
 234: 
 235:   /**
 236:    * Add a ChangeListener to the model. Usually only called to subscribe an
 237:    * AbstractButton's listener to the model.
 238:    *
 239:    * @param l The listener to add
 240:    */
 241:   public void addChangeListener(ChangeListener l)
 242:   {
 243:     listenerList.add(ChangeListener.class, l);
 244:   }
 245: 
 246:   /**
 247:    * Remove a ChangeListener to the model. Usually only called to unsubscribe
 248:    * an AbstractButton's listener to the model.
 249:    *
 250:    * @param l The listener to remove
 251:    */
 252:   public void removeChangeListener(ChangeListener l)
 253:   {
 254:     listenerList.remove(ChangeListener.class, l);
 255:   }
 256: 
 257:   /**
 258:    * Returns all registered <code>ChangeListener</code> objects.
 259:    *
 260:    * @return array of <code>ChangeListener</code> objects
 261:    */
 262:   public ChangeListener[] getChangeListeners()
 263:   {
 264:     return (ChangeListener[]) listenerList.getListeners(ChangeListener.class);
 265:   }
 266: 
 267:   /**
 268:    * Inform each ItemListener in the {@link listenerList} that an ItemEvent
 269:    * has occurred. This happens in response to any change to the {@link
 270:    * stateMask} field.
 271:    *
 272:    * @param e The ItemEvent to fire
 273:    */
 274:   protected void fireItemStateChanged(ItemEvent e)
 275:   {
 276:     ItemListener[] ll = getItemListeners();
 277: 
 278:     for (int i = 0; i < ll.length; i++)
 279:       ll[i].itemStateChanged(e);
 280:   }
 281: 
 282:   /**
 283:    * Inform each ActionListener in the {@link listenerList} that an
 284:    * ActionEvent has occurred. This happens in response to the any change to
 285:    * the {@link stateMask} field which makes the enabled, armed and pressed
 286:    * properties all simultaneously <code>true</code>.
 287:    *
 288:    * @param e The ActionEvent to fire
 289:    */
 290:   protected void fireActionPerformed(ActionEvent e)
 291:   {
 292:     ActionListener[] ll = getActionListeners();
 293: 
 294:     for (int i = 0; i < ll.length; i++)
 295:       ll[i].actionPerformed(e);
 296:   }
 297: 
 298:   /**
 299:    * Inform each ChangeListener in the {@link listenerList} that a ChangeEvent
 300:    * has occurred. This happens in response to the any change to a property
 301:    * of the model.
 302:    */
 303:   protected void fireStateChanged()
 304:   {
 305:     ChangeListener[] ll = getChangeListeners();
 306: 
 307:     for (int i = 0; i < ll.length; i++)
 308:       ll[i].stateChanged(changeEvent);
 309:   }
 310: 
 311:   /**
 312:    * Get the value of the model's "armed" property.
 313:    *
 314:    * @return The current "armed" property
 315:    */
 316:   public boolean isArmed()
 317:   {
 318:     return (stateMask & ARMED) == ARMED;
 319:   }
 320: 
 321:   /**
 322:    * Set the value of the model's "armed" property.
 323:    *
 324:    * @param a The new "armed" property
 325:    */
 326:   public void setArmed(boolean a)
 327:   {
 328:     // if this call does not represent a CHANGE in state, then return
 329:     if ((a && isArmed()) || (!a && !isArmed()))
 330:       return;
 331:     
 332:     // cannot change ARMED state unless button is enabled
 333:     if (!isEnabled())
 334:       return;
 335: 
 336:     // make the change
 337:     if (a)
 338:       stateMask = stateMask | ARMED;
 339:     else
 340:       stateMask = stateMask & (~ARMED);
 341: 
 342:     // notify interested ChangeListeners
 343:     fireStateChanged();
 344:   }
 345: 
 346:   /**
 347:    * Get the value of the model's "enabled" property.
 348:    *
 349:    * @return The current "enabled" property.
 350:    */
 351:   public boolean isEnabled()
 352:   {
 353:     return (stateMask & ENABLED) == ENABLED;
 354:   }
 355: 
 356:   /**
 357:    * Set the value of the model's "enabled" property.
 358:    *
 359:    * @param e The new "enabled" property
 360:    */
 361:   public void setEnabled(boolean e)
 362:   {
 363:     // if this call does not represent a CHANGE in state, then return
 364:     if ((e && isEnabled()) || (!e && !isEnabled()))
 365:       return;
 366: 
 367:     // make the change
 368:     if (e)
 369:       stateMask = stateMask | ENABLED;
 370:     else
 371:       stateMask = stateMask & (~ENABLED);
 372: 
 373:     // notify interested ChangeListeners
 374:     fireStateChanged();
 375:   }
 376: 
 377:   /**
 378:    * Set the value of the model's "pressed" property.
 379:    *
 380:    * @param p The new "pressed" property
 381:    */
 382:   public void setPressed(boolean p)
 383:   {
 384:     // if this call does not represent a CHANGE in state, then return
 385:     if ((p && isPressed()) || (!p && !isPressed()))
 386:       return;
 387: 
 388:     // cannot changed PRESSED state unless button is enabled
 389:     if (!isEnabled())
 390:       return;
 391: 
 392:     // make the change
 393:     if (p)
 394:       stateMask = stateMask | PRESSED;
 395:     else
 396:       stateMask = stateMask & (~PRESSED);
 397: 
 398:     // notify interested ChangeListeners
 399:     fireStateChanged();
 400: 
 401:     // if button is armed and was released, fire action event
 402:     if (!p && isArmed())
 403:       fireActionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED,
 404:                                           actionCommand));
 405:   }
 406: 
 407:   /**
 408:    * Get the value of the model's "pressed" property.
 409:    *
 410:    * @return The current "pressed" property
 411:    */
 412:   public boolean isPressed()
 413:   {
 414:     return (stateMask & PRESSED) == PRESSED;
 415:   }
 416: 
 417:   /**
 418:    * Set the value of the model's "rollover" property.
 419:    *
 420:    * @param r The new "rollover" property
 421:    */
 422:   public void setRollover(boolean r)
 423:   {
 424:     // if this call does not represent a CHANGE in state, then return
 425:     if ((r && isRollover()) || (!r && !isRollover()))
 426:       return;
 427:     
 428:     // cannot set ROLLOVER property unless button is enabled
 429:     if (!isEnabled())
 430:       return;
 431: 
 432:     // make the change
 433:     if (r)
 434:       stateMask = stateMask | ROLLOVER;
 435:     else
 436:       stateMask = stateMask & (~ROLLOVER);
 437: 
 438:     // notify interested ChangeListeners
 439:     fireStateChanged();
 440:   }
 441: 
 442:   /**
 443:    * Set the value of the model's "selected" property.
 444:    *
 445:    * @param s The new "selected" property
 446:    */
 447:   public void setSelected(boolean s)
 448:   {
 449:     // if this call does not represent a CHANGE in state, then return
 450:     if ((s && isSelected()) || (!s && !isSelected()))
 451:       return;
 452:     
 453:     // make the change
 454:     if (s)
 455:       stateMask = stateMask | SELECTED;
 456:     else
 457:       stateMask = stateMask & (~SELECTED);
 458: 
 459:     // notify interested ChangeListeners
 460:     fireStateChanged();
 461: 
 462:     // fire ItemStateChanged events
 463:     if (s)
 464:       {
 465:         fireItemStateChanged(new ItemEvent(this, ItemEvent.ITEM_STATE_CHANGED,
 466:                                            null, ItemEvent.SELECTED));
 467:         if (group != null)
 468:           group.setSelected(this, true);
 469:       }
 470:     else
 471:       {
 472:         fireItemStateChanged(new ItemEvent(this, ItemEvent.ITEM_STATE_CHANGED,
 473:                                            null, ItemEvent.DESELECTED));
 474:         if (group != null)
 475:           group.setSelected(this, false);
 476:       }
 477:   }
 478: 
 479:   /**
 480:    * Get the value of the model's "selected" property.
 481:    *
 482:    * @return The current "selected" property
 483:    */
 484:   public boolean isSelected()
 485:   {
 486:     return (stateMask & SELECTED) == SELECTED;
 487:   }
 488: 
 489:   /**
 490:    * Get the value of the model's "rollover" property.
 491:    *
 492:    * @return The current "rollover" property
 493:    */
 494:   public boolean isRollover()
 495:   {
 496:     return (stateMask & ROLLOVER) == ROLLOVER;
 497:   }
 498: 
 499:   /**
 500:    * Get the value of the model's "mnemonic" property.
 501:    *
 502:    * @return The current "mnemonic" property
 503:    */
 504:   public int getMnemonic()
 505:   {
 506:     return mnemonic;
 507:   }
 508: 
 509:   /**
 510:    * Set the value of the model's "mnemonic" property.
 511:    *
 512:    * @param key The new "mnemonic" property
 513:    */
 514:   public void setMnemonic(int key)
 515:   {
 516:     if (mnemonic != key)
 517:       {
 518:         mnemonic = key;
 519:         fireStateChanged();
 520:       }
 521:   }
 522: 
 523:   /**
 524:    * Set the value of the model's "actionCommand" property. This property is
 525:    * used as the "command" property of the {@link ActionEvent} fired from the
 526:    * model.
 527:    *
 528:    * @param s The new "actionCommand" property.
 529:    */
 530:   public void setActionCommand(String s)
 531:   {
 532:     if (actionCommand != s)
 533:       {
 534:         actionCommand = s;
 535:         fireStateChanged();
 536:       }
 537:   }
 538: 
 539:   /**
 540:    * Returns the current value of the model's "actionCommand" property.
 541:    *
 542:    * @return The current "actionCommand" property
 543:    */
 544:   public String getActionCommand()
 545:   {
 546:     return actionCommand;
 547:   }
 548: 
 549:   /**
 550:    * Set the value of the model's "group" property. The model is said to be a
 551:    * member of the {@link ButtonGroup} held in its "group" property, and only
 552:    * one model in a given group can have their "selected" property be
 553:    * <code>true</code> at a time.
 554:    *
 555:    * @param g The new "group" property
 556:    */
 557:   public void setGroup(ButtonGroup g)
 558:   {
 559:     if (group != g)
 560:       {
 561:         group = g;
 562:         fireStateChanged();
 563:       }
 564:   }
 565: 
 566:   /**
 567:    * Returns the current value of the model's "group" property.
 568:    *
 569:    * @return The value of the "group" property
 570:    */
 571:   public ButtonGroup getGroup()
 572:   {
 573:     return group;
 574:   }
 575: }