001    /* Button.java -- AWT button widget
002       Copyright (C) 1999, 2002, 2004, 2005  Free Software Foundation, Inc.
003    
004    This file is part of GNU Classpath.
005    
006    GNU Classpath is free software; you can redistribute it and/or modify
007    it under the terms of the GNU General Public License as published by
008    the Free Software Foundation; either version 2, or (at your option)
009    any later version.
010    
011    GNU Classpath is distributed in the hope that it will be useful, but
012    WITHOUT ANY WARRANTY; without even the implied warranty of
013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014    General Public License for more details.
015    
016    You should have received a copy of the GNU General Public License
017    along with GNU Classpath; see the file COPYING.  If not, write to the
018    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019    02110-1301 USA.
020    
021    Linking this library statically or dynamically with other modules is
022    making a combined work based on this library.  Thus, the terms and
023    conditions of the GNU General Public License cover the whole
024    combination.
025    
026    As a special exception, the copyright holders of this library give you
027    permission to link this library with independent modules to produce an
028    executable, regardless of the license terms of these independent
029    modules, and to copy and distribute the resulting executable under
030    terms of your choice, provided that you also meet, for each linked
031    independent module, the terms and conditions of the license of that
032    module.  An independent module is a module which is not derived from
033    or based on this library.  If you modify this library, you may extend
034    this exception to your version of the library, but you are not
035    obligated to do so.  If you do not wish to do so, delete this
036    exception statement from your version. */
037    
038    
039    package java.awt;
040    
041    import java.awt.event.ActionEvent;
042    import java.awt.event.ActionListener;
043    import java.awt.peer.ButtonPeer;
044    import java.lang.reflect.Array;
045    import java.util.EventListener;
046    
047    import javax.accessibility.Accessible;
048    import javax.accessibility.AccessibleAction;
049    import javax.accessibility.AccessibleContext;
050    import javax.accessibility.AccessibleRole;
051    import javax.accessibility.AccessibleValue;
052    
053    /**
054      * This class provides a button widget for the AWT.
055      *
056      * @author Aaron M. Renn (arenn@urbanophile.com)
057      * @author Tom Tromey (tromey@cygnus.com)
058      */
059    public class Button extends Component
060      implements java.io.Serializable, Accessible
061    {
062    
063    /*
064     * Static Variables
065     */
066    
067    // FIXME: Need readObject/writeObject for serialization
068    
069    // Serialization version constant
070    private static final long serialVersionUID = -8774683716313001058L;
071    
072    /*************************************************************************/
073    
074    /*
075     * Instance Variables
076     */
077    
078    /**
079      * @serial The action command name for this button.
080      * This is package-private to avoid an accessor method.
081      */
082    String actionCommand;
083    
084    /**
085      * @serial The label for this button.
086      * This is package-private to avoid an accessor method.
087      */
088    String label;
089    
090    // List of ActionListeners for this class.
091    private transient ActionListener action_listeners;
092    
093      /*
094       * The number used to generate the name returned by getName.
095       */
096      private static transient long next_button_number;
097    
098      protected class AccessibleAWTButton extends AccessibleAWTComponent
099        implements AccessibleAction, AccessibleValue
100      {
101        private static final long serialVersionUID = -5932203980244017102L;
102    
103        protected AccessibleAWTButton()
104        {
105          // Do nothing here.
106        }
107    
108        /* (non-Javadoc)
109         * @see javax.accessibility.AccessibleAction#getAccessibleActionCount()
110         */
111        public int getAccessibleActionCount()
112        {
113          // Only 1 action possible
114          return 1;
115        }
116    
117        /* (non-Javadoc)
118         * @see javax.accessibility.AccessibleAction#getAccessibleActionDescription(int)
119         */
120        public String getAccessibleActionDescription(int i)
121        {
122          // JDK 1.4.2 returns the string "click" for action 0.  However, the API
123          // docs don't say what the string to be returned is, beyond being a
124          // description of the action.  So we return the same thing for
125          // compatibility with 1.4.2.
126          if (i == 0)
127            return "click";
128          return null;
129        }
130    
131        /* (non-Javadoc)
132         * @see javax.accessibility.AccessibleAction#doAccessibleAction(int)
133         */
134        public boolean doAccessibleAction(int i)
135        {
136          if (i != 0)
137            return false;
138          processActionEvent(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, actionCommand));
139          return true;
140        }
141    
142        public String getAccessibleName()
143        {
144          return label;
145        }
146    
147        public AccessibleAction getAccessibleAction()
148        {
149          return this;
150        }
151    
152        public AccessibleValue getAccessibleValue()
153        {
154          return this;
155        }
156    
157        /* (non-Javadoc)
158         * @see javax.accessibility.AccessibleValue#getCurrentAccessibleValue()
159         */
160        public Number getCurrentAccessibleValue()
161        {
162          // Docs say return 1 if selected, but buttons can't be selected, right?
163          return new Integer(0);
164        }
165    
166        /* (non-Javadoc)
167         * @see javax.accessibility.AccessibleValue#setCurrentAccessibleValue(java.lang.Number)
168         */
169        public boolean setCurrentAccessibleValue(Number number)
170        {
171          // Since there's no selection with buttons, we're ignoring this.
172          // TODO someone who knows shoulw check this.
173          return false;
174        }
175    
176        /* (non-Javadoc)
177         * @see javax.accessibility.AccessibleValue#getMinimumAccessibleValue()
178         */
179        public Number getMinimumAccessibleValue()
180        {
181          return new Integer(0);
182        }
183    
184        /* (non-Javadoc)
185         * @see javax.accessibility.AccessibleValue#getMaximumAccessibleValue()
186         */
187        public Number getMaximumAccessibleValue()
188        {
189          return new Integer(0);
190        }
191    
192        public AccessibleRole getAccessibleRole()
193        {
194          return AccessibleRole.PUSH_BUTTON;
195        }
196      }
197    
198    /*************************************************************************/
199    
200    /*
201     * Constructors
202     */
203    
204    /**
205      * Initializes a new instance of <code>Button</code> with no label.
206      *
207      * @exception HeadlessException If GraphicsEnvironment.isHeadless()
208      * returns true
209      */
210    public
211    Button()
212    {
213      this("");
214    }
215    
216    /*************************************************************************/
217    
218    /**
219      * Initializes a new instance of <code>Button</code> with the specified
220      * label.  The action command name is also initialized to this value.
221      *
222      * @param label The label to display on the button.
223      *
224      * @exception HeadlessException If GraphicsEnvironment.isHeadless()
225      * returns true
226      */
227    public
228    Button(String label)
229    {
230      this.label = label;
231      actionCommand = label;
232    
233      if (GraphicsEnvironment.isHeadless ())
234        throw new HeadlessException ();
235    }
236    
237    /*************************************************************************/
238    
239    /*
240     * Instance Variables
241     */
242    
243    /**
244      * Returns the label for this button.
245      *
246      * @return The label for this button.
247      */
248    public String
249    getLabel()
250    {
251      return(label);
252    }
253    
254    /*************************************************************************/
255    
256    /**
257      * Sets the label for this button to the specified value.
258      *
259      * @param label The new label for this button.
260      */
261    public synchronized void
262    setLabel(String label)
263    {
264      this.label = label;
265      actionCommand = label;
266      if (peer != null)
267        {
268          ButtonPeer bp = (ButtonPeer) peer;
269          bp.setLabel (label);
270        }
271    }
272    
273    /*************************************************************************/
274    
275    /**
276      * Returns the action command name for this button.
277      *
278      * @return The action command name for this button.
279      */
280    public String
281    getActionCommand()
282    {
283      return(actionCommand);
284    }
285    
286    /*************************************************************************/
287    
288    /**
289      * Sets the action command name for this button to the specified value.
290      *
291      * @param actionCommand The new action command name.
292      */
293    public void
294    setActionCommand(String actionCommand)
295    {
296      this.actionCommand = actionCommand == null ? label : actionCommand;
297    }
298    
299    /*************************************************************************/
300    
301    /**
302      * Adds a new entry to the list of listeners that will receive
303      * action events from this button.
304      *
305      * @param listener The listener to add.
306      */
307    public synchronized void
308    addActionListener(ActionListener listener)
309    {
310      action_listeners = AWTEventMulticaster.add(action_listeners, listener);
311    }
312    
313    /*************************************************************************/
314    
315    /**
316      * Removes the specified listener from the list of listeners that will
317      * receive action events from this button.
318      *
319      * @param listener The listener to remove.
320      */
321    public synchronized void
322    removeActionListener(ActionListener listener)
323    {
324      action_listeners = AWTEventMulticaster.remove(action_listeners, listener);
325    }
326    
327      /**
328       * Returns all added <code>ActionListener</code> objects.
329       *
330       * @return an array of listeners
331       *
332       * @since 1.4
333       */
334      public synchronized ActionListener[] getActionListeners()
335      {
336        return (ActionListener[])
337          AWTEventMulticaster.getListeners(action_listeners,
338                                           ActionListener.class);
339      }
340    
341    /**
342     * Returns all registered EventListers of the given listenerType.
343     * listenerType must be a subclass of EventListener, or a
344     * ClassClassException is thrown.
345     *
346     * @param listenerType the listener type to return
347     *
348     * @return an array of listeners
349     *
350     * @exception ClassCastException If listenerType doesn't specify a class or
351     * interface that implements @see java.util.EventListener.
352     *
353     * @since 1.3
354     */
355      public <T extends EventListener> T[] getListeners(Class<T> listenerType)
356      {
357        if (listenerType == ActionListener.class)
358          return (T[]) getActionListeners();
359        return (T[]) Array.newInstance(listenerType, 0);
360      }
361    
362    /*************************************************************************/
363    
364    /**
365      * Notifies this button that it should create its native peer object.
366      */
367    public void
368    addNotify()
369    {
370      if (peer == null)
371        peer = getToolkit ().createButton (this);
372      super.addNotify();
373    }
374    
375    /*************************************************************************/
376    
377    /**
378      * Processes an event for this button.  If the specified event is an
379      * instance of <code>ActionEvent</code>, then the
380      * <code>processActionEvent()</code> method is called to dispatch it
381      * to any registered listeners.  Otherwise, the superclass method
382      * will be invoked.  Note that this method will not be called at all
383      * unless <code>ActionEvent</code>'s are enabled.  This will be done
384      * implicitly if any listeners are added.
385      *
386      * @param event The event to process.
387      */
388    protected void
389    processEvent(AWTEvent event)
390    {
391      if (event instanceof ActionEvent)
392        processActionEvent((ActionEvent)event);
393      else
394        super.processEvent(event);
395    }
396    
397    /*************************************************************************/
398    
399    /**
400      * This method dispatches an action event for this button to any
401      * registered listeners.
402      *
403      * @param event The event to process.
404      */
405    protected void
406    processActionEvent(ActionEvent event)
407    {
408      if (action_listeners != null)
409        action_listeners.actionPerformed(event);
410    }
411    
412    void
413    dispatchEventImpl(AWTEvent e)
414    {
415      if (e.id <= ActionEvent.ACTION_LAST
416          && e.id >= ActionEvent.ACTION_FIRST
417          && (action_listeners != null
418              || (eventMask & AWTEvent.ACTION_EVENT_MASK) != 0))
419        processEvent(e);
420      else
421        super.dispatchEventImpl(e);
422    }
423    
424    /*************************************************************************/
425    
426    /**
427      * Returns a debugging string for this button.
428      *
429      * @return A debugging string for this button.
430      */
431    protected String
432    paramString()
433    {
434      return getName () + "," + getX () + "," + getY () + ","
435        + getWidth () + "x" + getHeight () + ",label=" + getLabel ();
436    }
437    
438    /**
439     * Gets the AccessibleContext associated with this <code>Button</code>.
440     * The context is created, if necessary.
441     *
442     * @return the associated context
443     */
444    public AccessibleContext getAccessibleContext()
445    {
446      /* Create the context if this is the first request */
447      if (accessibleContext == null)
448        accessibleContext = new AccessibleAWTButton();
449      return accessibleContext;
450    }
451    
452      /**
453       * Generate a unique name for this button.
454       *
455       * @return A unique name for this button.
456       */
457      String generateName ()
458      {
459        return "button" + getUniqueLong ();
460      }
461    
462      private static synchronized long getUniqueLong ()
463      {
464        return next_button_number++;
465      }
466    
467    } // class Button