Frames | No Frames |
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: }