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