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