OSDN Git Service

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