Source for javax.swing.DefaultButtonModel

   1: /* DefaultButtonModel.java --
   2:    Copyright (C) 2002, 2004, 2006, 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 pressed" 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:     // Nothing to do here.
 149:   }
 150: 
 151:   /**
 152:    * Return <code>null</code>. Use {@link AbstractButton} if you wish to
 153:    * interface with a button via an {@link ItemSelectable} interface.
 154:    *
 155:    * @return <code>null</code>
 156:    */
 157:   public Object[] getSelectedObjects()
 158:   {
 159:     return null;
 160:   }
 161: 
 162:   /**
 163:    * Returns a specified class of listeners.
 164:    *
 165:    * @param listenerType the type of listener to return
 166:    *
 167:    * @return array of listeners
 168:    */
 169:   public <T extends EventListener> T[] getListeners(Class<T> listenerType)
 170:   {
 171:     return listenerList.getListeners(listenerType);
 172:   }
 173: 
 174:   /**
 175:    * Add an ActionListener to the model. Usually only called to subscribe an
 176:    * AbstractButton's listener to the model.
 177:    *
 178:    * @param l The listener to add
 179:    */
 180:   public void addActionListener(ActionListener l)
 181:   {
 182:     listenerList.add(ActionListener.class, l);
 183:   }
 184: 
 185:   /**
 186:    * Remove an ActionListener to the model. Usually only called to unsubscribe
 187:    * an AbstractButton's listener to the model.
 188:    *
 189:    * @param l The listener to remove
 190:    */
 191:   public void removeActionListener(ActionListener l)
 192:   {
 193:     listenerList.remove(ActionListener.class, l);
 194:   }
 195: 
 196:   /**
 197:    * Returns all registered <code>ActionListener</code> objects.
 198:    *
 199:    * @return array of <code>ActionListener</code> objects
 200:    */
 201:   public ActionListener[] getActionListeners()
 202:   {
 203:     return (ActionListener[]) listenerList.getListeners(ActionListener.class);
 204:   }
 205: 
 206:   /**
 207:    * Add an ItemListener to the model. Usually only called to subscribe an
 208:    * AbstractButton's listener to the model.
 209:    *
 210:    * @param l The listener to add
 211:    */
 212:   public void addItemListener(ItemListener l)
 213:   {
 214:     listenerList.add(ItemListener.class, l);
 215:   }
 216: 
 217:   /**
 218:    * Remove an ItemListener to the model. Usually only called to unsubscribe
 219:    * an AbstractButton's listener to the model.
 220:    *
 221:    * @param l The listener to remove
 222:    */
 223:   public void removeItemListener(ItemListener l)
 224:   {
 225:     listenerList.remove(ItemListener.class, l);
 226:   }
 227: 
 228:   /**
 229:    * Returns all registered <code>ItemListener</code> objects.
 230:    *
 231:    * @return array of <code>ItemListener</code> objects
 232:    */
 233:   public ItemListener[] getItemListeners()
 234:   {
 235:     return (ItemListener[]) listenerList.getListeners(ItemListener.class);
 236:   }
 237: 
 238:   /**
 239:    * Add a ChangeListener to the model. Usually only called to subscribe an
 240:    * AbstractButton's listener to the model.
 241:    *
 242:    * @param l The listener to add
 243:    */
 244:   public void addChangeListener(ChangeListener l)
 245:   {
 246:     listenerList.add(ChangeListener.class, l);
 247:   }
 248: 
 249:   /**
 250:    * Remove a ChangeListener to the model. Usually only called to unsubscribe
 251:    * an AbstractButton's listener to the model.
 252:    *
 253:    * @param l The listener to remove
 254:    */
 255:   public void removeChangeListener(ChangeListener l)
 256:   {
 257:     listenerList.remove(ChangeListener.class, l);
 258:   }
 259: 
 260:   /**
 261:    * Returns all registered <code>ChangeListener</code> objects.
 262:    *
 263:    * @return array of <code>ChangeListener</code> objects
 264:    */
 265:   public ChangeListener[] getChangeListeners()
 266:   {
 267:     return (ChangeListener[]) listenerList.getListeners(ChangeListener.class);
 268:   }
 269: 
 270:   /**
 271:    * Inform each ItemListener in the {@link #listenerList} that an ItemEvent
 272:    * has occurred. This happens in response to any change to the {@link
 273:    * #stateMask} field.
 274:    *
 275:    * @param e The ItemEvent to fire
 276:    */
 277:   protected void fireItemStateChanged(ItemEvent e)
 278:   {
 279:     ItemListener[] ll = getItemListeners();
 280: 
 281:     for (int i = 0; i < ll.length; i++)
 282:       ll[i].itemStateChanged(e);
 283:   }
 284: 
 285:   /**
 286:    * Inform each ActionListener in the {@link #listenerList} that an
 287:    * ActionEvent has occurred. This happens in response to the any change to
 288:    * the {@link #stateMask} field which makes the enabled, armed and pressed
 289:    * properties all simultaneously <code>true</code>.
 290:    *
 291:    * @param e The ActionEvent to fire
 292:    */
 293:   protected void fireActionPerformed(ActionEvent e)
 294:   {
 295:     ActionListener[] ll = getActionListeners();
 296: 
 297:     for (int i = 0; i < ll.length; i++)
 298:       ll[i].actionPerformed(e);
 299:   }
 300: 
 301:   /**
 302:    * Inform each ChangeListener in the {@link #listenerList} that a ChangeEvent
 303:    * has occurred. This happens in response to the any change to a property
 304:    * of the model.
 305:    */
 306:   protected void fireStateChanged()
 307:   {
 308:     ChangeListener[] ll = getChangeListeners();
 309: 
 310:     for (int i = 0; i < ll.length; i++)
 311:       ll[i].stateChanged(changeEvent);
 312:   }
 313: 
 314:   /**
 315:    * Get the value of the model's "armed" property.
 316:    *
 317:    * @return The current "armed" property
 318:    */
 319:   public boolean isArmed()
 320:   {
 321:     return (stateMask & ARMED) == ARMED;
 322:   }
 323: 
 324:   /**
 325:    * Set the value of the model's "armed" property.
 326:    *
 327:    * @param a The new "armed" property
 328:    */
 329:   public void setArmed(boolean a)
 330:   {
 331:     // if this call does not represent a CHANGE in state, then return
 332:     if ((a && isArmed()) || (!a && !isArmed()))
 333:       return;
 334:     
 335:     // cannot change ARMED state unless button is enabled
 336:     if (!isEnabled())
 337:       return;
 338: 
 339:     // make the change
 340:     if (a)
 341:       stateMask = stateMask | ARMED;
 342:     else
 343:       stateMask = stateMask & (~ARMED);
 344: 
 345:     // notify interested ChangeListeners
 346:     fireStateChanged();
 347:   }
 348: 
 349:   /**
 350:    * Get the value of the model's "enabled" property.
 351:    *
 352:    * @return The current "enabled" property.
 353:    */
 354:   public boolean isEnabled()
 355:   {
 356:     return (stateMask & ENABLED) == ENABLED;
 357:   }
 358: 
 359:   /**
 360:    * Set the value of the model's "enabled" property.
 361:    *
 362:    * @param e The new "enabled" property
 363:    */
 364:   public void setEnabled(boolean e)
 365:   {
 366:     // if this call does not represent a CHANGE in state, then return
 367:     if ((e && isEnabled()) || (!e && !isEnabled()))
 368:       return;
 369: 
 370:     // make the change
 371:     if (e)
 372:       stateMask = stateMask | ENABLED;
 373:     else
 374:       stateMask = stateMask & (~ENABLED) & (~ARMED) & (~PRESSED);
 375: 
 376:     // notify interested ChangeListeners
 377:     fireStateChanged();
 378:   }
 379: 
 380:   /**
 381:    * Set the value of the model's "pressed" property.
 382:    *
 383:    * @param p The new "pressed" property
 384:    */
 385:   public void setPressed(boolean p)
 386:   {
 387:     // if this call does not represent a CHANGE in state, then return
 388:     if ((p && isPressed()) || (!p && !isPressed()))
 389:       return;
 390: 
 391:     // cannot changed PRESSED state unless button is enabled
 392:     if (!isEnabled())
 393:       return;
 394: 
 395:     // make the change
 396:     if (p)
 397:       stateMask = stateMask | PRESSED;
 398:     else
 399:       stateMask = stateMask & (~PRESSED);
 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:     // notify interested ChangeListeners
 407:     fireStateChanged();
 408:   }
 409: 
 410:   /**
 411:    * Get the value of the model's "pressed" property.
 412:    *
 413:    * @return The current "pressed" property
 414:    */
 415:   public boolean isPressed()
 416:   {
 417:     return (stateMask & PRESSED) == PRESSED;
 418:   }
 419: 
 420:   /**
 421:    * Set the value of the model's "rollover" property.
 422:    *
 423:    * @param r The new "rollover" property
 424:    */
 425:   public void setRollover(boolean r)
 426:   {
 427:     // if this call does not represent a CHANGE in state, then return
 428:     if (r == isRollover())
 429:       return;
 430:     
 431:     // cannot set ROLLOVER property unless button is enabled
 432:     if (!isEnabled())
 433:       return;
 434: 
 435:     // make the change
 436:     if (r)
 437:       stateMask = stateMask | ROLLOVER;
 438:     else
 439:       stateMask = stateMask & (~ROLLOVER);
 440: 
 441:     // notify interested ChangeListeners
 442:     fireStateChanged();
 443:   }
 444: 
 445:   /**
 446:    * Set the value of the model's "selected" property.
 447:    *
 448:    * @param s The new "selected" property
 449:    */
 450:   public void setSelected(boolean s)
 451:   {
 452:     // if this call does not represent a CHANGE in state, then return
 453:     if ((s && isSelected()) || (!s && !isSelected()))
 454:       return;
 455:     
 456:     // make the change
 457:     if (s)
 458:       stateMask = stateMask | SELECTED;
 459:     else
 460:       stateMask = stateMask & (~SELECTED);
 461: 
 462:     // notify interested ChangeListeners
 463:     fireStateChanged();
 464: 
 465:     // fire ItemStateChanged events
 466:     if (s)
 467:       {
 468:         fireItemStateChanged(new ItemEvent(this, ItemEvent.ITEM_STATE_CHANGED,
 469:                                            this, ItemEvent.SELECTED));
 470:         if (group != null)
 471:           group.setSelected(this, true);
 472:       }
 473:     else
 474:       {
 475:         fireItemStateChanged(new ItemEvent(this, ItemEvent.ITEM_STATE_CHANGED,
 476:                                            this, ItemEvent.DESELECTED));
 477:         if (group != null)
 478:           group.setSelected(this, false);
 479:       }
 480:   }
 481: 
 482:   /**
 483:    * Get the value of the model's "selected" property.
 484:    *
 485:    * @return The current "selected" property
 486:    */
 487:   public boolean isSelected()
 488:   {
 489:     return (stateMask & SELECTED) == SELECTED;
 490:   }
 491: 
 492:   /**
 493:    * Get the value of the model's "rollover" property.
 494:    *
 495:    * @return The current "rollover" property
 496:    */
 497:   public boolean isRollover()
 498:   {
 499:     return (stateMask & ROLLOVER) == ROLLOVER;
 500:   }
 501: 
 502:   /**
 503:    * Get the value of the model's "mnemonic" property.
 504:    *
 505:    * @return The current "mnemonic" property
 506:    */
 507:   public int getMnemonic()
 508:   {
 509:     return mnemonic;
 510:   }
 511: 
 512:   /**
 513:    * Set the value of the model's "mnemonic" property.
 514:    *
 515:    * @param key The new "mnemonic" property
 516:    */
 517:   public void setMnemonic(int key)
 518:   {
 519:     if (mnemonic != key)
 520:       {
 521:         mnemonic = key;
 522:         fireStateChanged();
 523:       }
 524:   }
 525: 
 526:   /**
 527:    * Set the value of the model's "actionCommand" property. This property is
 528:    * used as the "command" property of the {@link ActionEvent} fired from the
 529:    * model.
 530:    *
 531:    * @param s The new "actionCommand" property.
 532:    */
 533:   public void setActionCommand(String s)
 534:   {
 535:     if (actionCommand != s)
 536:       {
 537:         actionCommand = s;
 538:         fireStateChanged();
 539:       }
 540:   }
 541: 
 542:   /**
 543:    * Returns the current value of the model's "actionCommand" property.
 544:    *
 545:    * @return The current "actionCommand" property
 546:    */
 547:   public String getActionCommand()
 548:   {
 549:     return actionCommand;
 550:   }
 551: 
 552:   /**
 553:    * Set the value of the model's "group" property. The model is said to be a
 554:    * member of the {@link ButtonGroup} held in its "group" property, and only
 555:    * one model in a given group can have their "selected" property be
 556:    * <code>true</code> at a time.
 557:    *
 558:    * @param g The new "group" property (<code>null</code> permitted).
 559:    * 
 560:    * @see #getGroup()
 561:    */
 562:   public void setGroup(ButtonGroup g)
 563:   {
 564:     group = g;
 565:   }
 566: 
 567:   /**
 568:    * Returns the current value of the model's "group" property.
 569:    *
 570:    * @return The value of the "group" property
 571:    * 
 572:    * @see #setGroup(ButtonGroup)
 573:    */
 574:   public ButtonGroup getGroup()
 575:   {
 576:     return group;
 577:   }
 578: }