001/* Checkbox.java -- An AWT checkbox widget
002   Copyright (C) 1999, 2000, 2001, 2002, 2005, 2006
003   Free Software Foundation, Inc.
004
005This file is part of GNU Classpath.
006
007GNU Classpath is free software; you can redistribute it and/or modify
008it under the terms of the GNU General Public License as published by
009the Free Software Foundation; either version 2, or (at your option)
010any later version.
011
012GNU Classpath is distributed in the hope that it will be useful, but
013WITHOUT ANY WARRANTY; without even the implied warranty of
014MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015General Public License for more details.
016
017You should have received a copy of the GNU General Public License
018along with GNU Classpath; see the file COPYING.  If not, write to the
019Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02002110-1301 USA.
021
022Linking this library statically or dynamically with other modules is
023making a combined work based on this library.  Thus, the terms and
024conditions of the GNU General Public License cover the whole
025combination.
026
027As a special exception, the copyright holders of this library give you
028permission to link this library with independent modules to produce an
029executable, regardless of the license terms of these independent
030modules, and to copy and distribute the resulting executable under
031terms of your choice, provided that you also meet, for each linked
032independent module, the terms and conditions of the license of that
033module.  An independent module is a module which is not derived from
034or based on this library.  If you modify this library, you may extend
035this exception to your version of the library, but you are not
036obligated to do so.  If you do not wish to do so, delete this
037exception statement from your version. */
038
039
040package java.awt;
041
042import java.awt.event.ItemEvent;
043import java.awt.event.ItemListener;
044import java.awt.peer.CheckboxPeer;
045import java.io.Serializable;
046
047import javax.accessibility.Accessible;
048import javax.accessibility.AccessibleAction;
049import javax.accessibility.AccessibleContext;
050import javax.accessibility.AccessibleRole;
051import javax.accessibility.AccessibleState;
052import javax.accessibility.AccessibleStateSet;
053import javax.accessibility.AccessibleValue;
054
055/**
056 * This class implements a component which has an on/off state.  Two
057 * or more Checkboxes can be grouped by a CheckboxGroup.
058 *
059 * @author Aaron M. Renn (arenn@urbanophile.com)
060 * @author Tom Tromey (tromey@redhat.com)
061 */
062public class Checkbox extends Component
063  implements ItemSelectable, Accessible, Serializable
064{
065
066// FIXME: Need readObject/writeObject for this.
067
068/*
069 * Static Variables
070 */
071
072// Serialization Constant
073private static final long serialVersionUID = 7270714317450821763L;
074
075/*************************************************************************/
076
077/*
078 * Instance Variables
079 */
080
081/**
082  * @serial The checkbox group for this checkbox.
083  */
084private CheckboxGroup group;
085
086/**
087  * @serial The label on this checkbox.
088  */
089private String label;
090
091/**
092  * @serial The state of this checkbox.
093  * This is package-private to avoid an accessor method.
094  */
095boolean state;
096
097// The list of listeners for this object.
098private transient ItemListener item_listeners;
099
100  /*
101   * The number used to generate the name returned by getName.
102   */
103  private static transient long next_checkbox_number;
104
105/**
106 * This class provides accessibility support for the
107 * checkbox.
108 *
109 * @author Jerry Quinn  (jlquinn@optonline.net)
110 * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
111 */
112protected class AccessibleAWTCheckbox
113  extends AccessibleAWTComponent
114  implements ItemListener, AccessibleAction, AccessibleValue
115{
116  /**
117   * Serialization constant to match JDK 1.5
118   */
119  private static final long serialVersionUID = 7881579233144754107L;
120
121  /**
122   * Default constructor which simply calls the
123   * super class for generic component accessibility
124   * handling.
125   */
126  public AccessibleAWTCheckbox()
127  {
128    super();
129  }
130
131  /**
132   * Captures changes to the state of the checkbox and
133   * fires appropriate accessible property change events.
134   *
135   * @param event the event fired.
136   * @see java.awt.event.ItemListener#itemStateChanged(java.awt.event.ItemEvent)
137   */
138  public void itemStateChanged(ItemEvent event)
139  {
140    firePropertyChange(ACCESSIBLE_STATE_PROPERTY,
141                       state ? null : AccessibleState.CHECKED,
142                       state ? AccessibleState.CHECKED : null);
143  }
144  
145  /**
146   * Returns an implementation of the <code>AccessibleAction</code>
147   * interface for this accessible object.  In this case, the
148   * current instance is simply returned (with a more appropriate
149   * type), as it also implements the accessible action as well as
150   * the context.
151   *
152   * @return the accessible action associated with this context.
153   * @see javax.accessibility.AccessibleAction
154   */
155  public AccessibleAction getAccessibleAction()
156  {
157    return this;
158  }
159  
160  /**
161   * Returns an implementation of the <code>AccessibleValue</code>
162   * interface for this accessible object.  In this case, the
163   * current instance is simply returned (with a more appropriate
164   * type), as it also implements the accessible value as well as
165   * the context.
166   *
167   * @return the accessible value associated with this context.
168   * @see javax.accessibility.AccessibleValue
169   */
170  public AccessibleValue getAccessibleValue()
171  {
172    return this;
173  }
174  
175  /* 
176   * The following methods are implemented in the JDK (up to
177   * 1.5) as stubs.  We do likewise here.
178   */
179
180  /**
181   * Returns the number of actions associated with this accessible
182   * object.  This default implementation returns 0.
183   *
184   * @return the number of accessible actions available.
185   * @see javax.accessibility.AccessibleAction#getAccessibleActionCount()
186   */
187  public int getAccessibleActionCount()
188  {
189    // 1.4.1 and 1.5 do this
190    return 0;
191  }
192
193  /**
194   * Returns a description of the action with the supplied id.
195   * This default implementation always returns null.
196   *
197   * @param i the id of the action whose description should be
198   *          retrieved.
199   * @return a <code>String</code> describing the action.
200   * @see javax.accessibility.AccessibleAction#getAccessibleActionDescription(int)
201   */
202  public String getAccessibleActionDescription(int i)
203  {
204    // 1.5 does this
205    return null;
206  }
207
208  /**
209   * Executes the action with the specified id.  This
210   * default implementation simply returns false.
211   *
212   * @param i the id of the action to perform.
213   * @return true if the action was performed.
214   * @see javax.accessibility.AccessibleAction#doAccessibleAction(int)
215   */
216  public boolean doAccessibleAction(int i)
217  {
218    // 1.5 does this
219    return false;
220  }
221
222  /**
223   * Returns the current value of this accessible object.
224   * If no value has been set, null is returned.  This
225   * default implementation always returns null, regardless.
226   *
227   * @return the numeric value of this object, or null if
228   *         no value has been set.
229   * @see javax.accessibility.AccessibleValue#getCurrentAccessibleValue()
230   */
231  public Number getCurrentAccessibleValue()
232  {
233    // 1.5 does this
234    return null;
235  }
236
237  /**
238   * Sets the current value of this accessible object
239   * to that supplied.  In this default implementation,
240   * the value is never set and the method always returns
241   * false.
242   *
243   * @param number the new accessible value.
244   * @return true if the value was set.
245   * @see javax.accessibility.AccessibleValue#setCurrentAccessibleValue(java.lang.Number)
246   */
247  public boolean setCurrentAccessibleValue(Number number)
248  {
249    // 1.5 does this
250    return false;
251  }
252
253  /**
254   * Returns the minimum acceptable accessible value used
255   * by this object, or null if no minimum value exists.
256   * This default implementation always returns null.
257   *
258   * @return the minimum acceptable accessible value, or null
259   *         if there is no minimum.
260   * @see javax.accessibility.AccessibleValue#getMinimumAccessibleValue()
261   */
262  public Number getMinimumAccessibleValue()
263  {
264    return null;
265  }
266
267  /**
268   * Returns the maximum acceptable accessible value used
269   * by this object, or null if no maximum value exists.
270   * This default implementation always returns null.
271   *
272   * @return the maximum acceptable accessible value, or null
273   *         if there is no maximum.
274   * @see javax.accessibility.AccessibleValue#getMaximumAccessibleValue()
275   */
276  public Number getMaximumAccessibleValue()
277  {
278    return null;
279  }
280  
281  /**
282   * Returns the role of this accessible object.
283   *
284   * @return the instance of <code>AccessibleRole</code>,
285   *         which describes this object.
286   * @see javax.accessibility.AccessibleRole
287   */
288  public AccessibleRole getAccessibleRole() 
289  {
290    return AccessibleRole.CHECK_BOX;
291  }
292  
293  /**
294   * Returns the state set of this accessible object.
295   *
296   * @return a set of <code>AccessibleState</code>s
297   *         which represent the current state of the
298   *         accessible object.
299   * @see javax.accessibility.AccessibleState
300   * @see javax.accessibility.AccessibleStateSet
301   */
302  public AccessibleStateSet getAccessibleStateSet()
303  {
304    AccessibleStateSet set = super.getAccessibleStateSet();
305    if (state)
306      set.add(AccessibleState.CHECKED);
307    return set;
308  }
309
310}
311
312/*************************************************************************/
313
314/*
315 * Constructors
316 */
317
318/**
319  * Initializes a new instance of <code>Checkbox</code> with no label,
320  * an initial state of off, and that is not part of any checkbox group.
321  */
322public 
323Checkbox()
324{
325  this("", false, null);
326}
327
328/*************************************************************************/
329
330/**
331  * Initializes a new instance of <code>Checkbox</code> with the specified
332  * label, an initial state of off, and that is not part of any checkbox
333  * group.
334  *
335  * @param label The label for this checkbox.
336  */
337public
338Checkbox(String label)
339{
340  this(label, false, null);
341}
342
343/*************************************************************************/
344
345/**
346  * Initializes a new instance of <code>Checkbox</code> with the specified
347  * label and initial state, and that is not part of any checkbox
348  * group.
349  *
350  * @param label The label for this checkbox.
351  * @param state The initial state of the checkbox, <code>true</code> for
352  * on, <code>false</code> for off.
353  */
354public
355Checkbox(String label, boolean state)
356{
357  this(label, state, null);
358}
359
360/*************************************************************************/
361
362/**
363  * Initializes a new instance of <code>Checkbox</code> with the specified
364  * label, initial state, and checkbox group.
365  *
366  * @param label The label for this checkbox.
367  * @param group The checkbox group for this box, or <code>null</code>
368  * if there is no checkbox group.
369  * @param state The initial state of the checkbox, <code>true</code> for
370  * on, <code>false</code> for off.
371  */
372public
373Checkbox(String label, CheckboxGroup group, boolean state)
374{
375  this(label, state, group);
376}
377
378/*************************************************************************/
379
380/**
381  * Initializes a new instance of <code>Checkbox</code> with the specified
382  * label, initial state, and checkbox group.
383  *
384  * @param label The label for this checkbox.
385  * @param state The initial state of the checkbox, <code>true</code> for
386  * on, <code>false</code> for off.
387  * @param group The checkbox group for this box, or <code>null</code>
388  * if there is no checkbox group.
389  */
390public
391Checkbox(String label, boolean state, CheckboxGroup group)
392{
393  this.label = label;
394  this.state = state;
395  this.group = group;
396
397  if ( state && group != null )
398    {
399      group.setSelectedCheckbox(this);
400    }
401}
402
403/*************************************************************************/
404
405/*
406 * Instance Variables
407 */
408
409/**
410  * Returns the label for this checkbox.
411  *
412  * @return The label for this checkbox.
413  */
414public String
415getLabel()
416{
417  return(label);
418}
419
420/*************************************************************************/
421
422/**
423  * Sets the label for this checkbox to the specified value.
424  *
425  * @param label The new checkbox label.
426  */
427public synchronized void
428setLabel(String label)
429{
430  this.label = label;
431  if (peer != null)
432    {
433      CheckboxPeer cp = (CheckboxPeer) peer;
434      cp.setLabel(label);
435    }
436}
437
438/*************************************************************************/
439
440/**
441  * Returns the state of this checkbox.
442  *
443  * @return The state of this checkbox, which will be <code>true</code> for
444  * on and <code>false</code> for off.
445  */
446public boolean
447getState()
448{
449  return(state);
450}
451
452/*************************************************************************/
453
454/**
455  * Sets the state of this checkbox to the specified value.
456  *
457  * @param state The new state of the checkbox, which will be <code>true</code>
458  * for on or <code>false</code> for off.
459  */
460public synchronized void
461setState(boolean state)
462{
463  if (this.state != state)
464    {
465      this.state = state;
466      if (peer != null)
467        {
468          CheckboxPeer cp = (CheckboxPeer) peer;
469          cp.setState (state);
470        }
471    }
472}
473
474/*************************************************************************/
475
476/**
477  * Returns an array of length one containing the checkbox label if this
478  * checkbox is selected.  Otherwise <code>null</code> is returned.
479  *
480  * @return The selection state of this checkbox.
481  */
482public Object[]
483getSelectedObjects()
484{
485  if (state == false)
486    return(null);
487
488  Object[] objs = new Object[1];
489  objs[0] = label;
490
491  return(objs);
492}
493
494/*************************************************************************/
495
496/**
497  * Returns the checkbox group this object is a member of, if any.
498  *
499  * @return This object's checkbox group, of <code>null</code> if it is
500  * not a member of any group.
501  */
502public CheckboxGroup
503getCheckboxGroup()
504{
505  return(group);
506}
507
508/*************************************************************************/
509
510/**
511  * Sets this object's checkbox group to the specified group.
512  *
513  * @param group The new checkbox group, or <code>null</code> to make this
514  * object part of no checkbox group.
515  */
516public synchronized void
517setCheckboxGroup(CheckboxGroup group)
518{
519  this.group = group;
520  if (peer != null)
521    {
522      CheckboxPeer cp = (CheckboxPeer) peer;
523      cp.setCheckboxGroup (group);
524    }
525}
526
527/*************************************************************************/
528
529/**
530  * Creates this object's native peer.
531  */
532public void
533addNotify()
534{
535  if (peer == null)
536    peer = getToolkit ().createCheckbox (this);
537  super.addNotify ();
538}
539
540  public ItemListener[] getItemListeners ()
541  {
542    return (ItemListener[])
543      AWTEventMulticaster.getListeners (item_listeners, ItemListener.class);
544  }
545
546/**
547  * Adds a new listeners to the list of registered listeners for this object.
548  *
549  * @param listener The new listener to add.
550  */
551public synchronized void
552addItemListener(ItemListener listener)
553{
554  item_listeners = AWTEventMulticaster.add(item_listeners, listener);
555}
556
557/*************************************************************************/
558
559/**
560  * Removes a listener from the list of registered listeners for this object.
561  *
562  * @param listener The listener to remove.
563  */
564public synchronized void
565removeItemListener(ItemListener listener)
566{
567  item_listeners = AWTEventMulticaster.remove(item_listeners, listener);
568}
569
570/*************************************************************************/
571
572/**
573  * Processes this event by calling <code>processItemEvent()</code> if it
574  * is any instance of <code>ItemEvent</code>.  Otherwise it is passed to
575  * the superclass for processing.
576  *
577  * @param event The event to process.
578  */
579protected void
580processEvent(AWTEvent event)
581{
582  if (event instanceof ItemEvent)
583    processItemEvent((ItemEvent)event);
584  else
585    super.processEvent(event);
586}
587
588/*************************************************************************/
589
590/**
591  * Processes this event by dispatching it to any registered listeners.
592  *
593  * @param event The <code>ItemEvent</code> to process.
594  */
595protected void
596processItemEvent(ItemEvent event)
597{
598  if (item_listeners != null)
599    item_listeners.itemStateChanged(event);
600}
601
602void
603dispatchEventImpl(AWTEvent e)
604{
605  if (e.id <= ItemEvent.ITEM_LAST
606      && e.id >= ItemEvent.ITEM_FIRST)
607    {
608      ItemEvent ie = (ItemEvent) e;
609      int itemState = ie.getStateChange();
610      setState(itemState == ItemEvent.SELECTED ? true : false);
611      if (item_listeners != null 
612          || (eventMask & AWTEvent.ITEM_EVENT_MASK) != 0)
613        processEvent(e);
614    }
615  else
616    super.dispatchEventImpl(e);
617}
618
619/*************************************************************************/
620
621/**
622  * Returns a debugging string for this object.
623  */
624protected String
625paramString()
626{
627  // Note: We cannot add the checkbox group information here because this
628  // would trigger infinite recursion when CheckboxGroup.toString() is
629  // called and the box is in its selected state.
630  return ("label=" + label + ",state=" + state + "," + super.paramString());
631}
632
633/**
634 * Gets the AccessibleContext associated with this <code>Checkbox</code>.
635 * The context is created, if necessary.
636 *
637 * @return the associated context
638 */
639public AccessibleContext getAccessibleContext()
640{
641  /* Create the context if this is the first request */
642  if (accessibleContext == null)
643  {
644    AccessibleAWTCheckbox ac = new AccessibleAWTCheckbox();
645    accessibleContext = ac;
646    addItemListener(ac);
647  }
648  return accessibleContext;
649}
650
651  /**
652   * Generate a unique name for this checkbox.
653   *
654   * @return A unique name for this checkbox.
655   */
656  String generateName()
657  {
658    return "checkbox" + getUniqueLong();
659  }
660
661  private static synchronized long getUniqueLong()
662  {
663    return next_checkbox_number++;
664  }
665}