OSDN Git Service

libjava/
[pf3gnuchains/gcc-fork.git] / libjava / classpath / javax / swing / DefaultButtonModel.java
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 }