View Javadoc
1   /*
2    * Copyright (c) 1995, 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  
26  package java.awt;
27  
28  import java.awt.peer.ButtonPeer;
29  import java.util.EventListener;
30  import java.awt.event.*;
31  import java.io.ObjectOutputStream;
32  import java.io.ObjectInputStream;
33  import java.io.IOException;
34  import javax.accessibility.*;
35  
36  /**
37   * This class creates a labeled button. The application can cause
38   * some action to happen when the button is pushed. This image
39   * depicts three views of a "<code>Quit</code>" button as it appears
40   * under the Solaris operating system:
41   * <p>
42   * <img src="doc-files/Button-1.gif" alt="The following context describes the graphic"
43   * style="float:center; margin: 7px 10px;">
44   * <p>
45   * The first view shows the button as it appears normally.
46   * The second view shows the button
47   * when it has input focus. Its outline is darkened to let the
48   * user know that it is an active object. The third view shows the
49   * button when the user clicks the mouse over the button, and thus
50   * requests that an action be performed.
51   * <p>
52   * The gesture of clicking on a button with the mouse
53   * is associated with one instance of <code>ActionEvent</code>,
54   * which is sent out when the mouse is both pressed and released
55   * over the button. If an application is interested in knowing
56   * when the button has been pressed but not released, as a separate
57   * gesture, it can specialize <code>processMouseEvent</code>,
58   * or it can register itself as a listener for mouse events by
59   * calling <code>addMouseListener</code>. Both of these methods are
60   * defined by <code>Component</code>, the abstract superclass of
61   * all components.
62   * <p>
63   * When a button is pressed and released, AWT sends an instance
64   * of <code>ActionEvent</code> to the button, by calling
65   * <code>processEvent</code> on the button. The button's
66   * <code>processEvent</code> method receives all events
67   * for the button; it passes an action event along by
68   * calling its own <code>processActionEvent</code> method.
69   * The latter method passes the action event on to any action
70   * listeners that have registered an interest in action
71   * events generated by this button.
72   * <p>
73   * If an application wants to perform some action based on
74   * a button being pressed and released, it should implement
75   * <code>ActionListener</code> and register the new listener
76   * to receive events from this button, by calling the button's
77   * <code>addActionListener</code> method. The application can
78   * make use of the button's action command as a messaging protocol.
79   *
80   * @author      Sami Shaio
81   * @see         java.awt.event.ActionEvent
82   * @see         java.awt.event.ActionListener
83   * @see         java.awt.Component#processMouseEvent
84   * @see         java.awt.Component#addMouseListener
85   * @since       JDK1.0
86   */
87  public class Button extends Component implements Accessible {
88  
89      /**
90       * The button's label.  This value may be null.
91       * @serial
92       * @see #getLabel()
93       * @see #setLabel(String)
94       */
95      String label;
96  
97      /**
98       * The action to be performed once a button has been
99       * pressed.  This value may be null.
100      * @serial
101      * @see #getActionCommand()
102      * @see #setActionCommand(String)
103      */
104     String actionCommand;
105 
106     transient ActionListener actionListener;
107 
108     private static final String base = "button";
109     private static int nameCounter = 0;
110 
111     /*
112      * JDK 1.1 serialVersionUID
113      */
114     private static final long serialVersionUID = -8774683716313001058L;
115 
116 
117     static {
118         /* ensure that the necessary native libraries are loaded */
119         Toolkit.loadLibraries();
120         if (!GraphicsEnvironment.isHeadless()) {
121             initIDs();
122         }
123     }
124 
125     /**
126      * Initialize JNI field and method IDs for fields that may be
127      * accessed from C.
128      */
129     private static native void initIDs();
130 
131     /**
132      * Constructs a button with an empty string for its label.
133      *
134      * @exception HeadlessException if GraphicsEnvironment.isHeadless()
135      * returns true
136      * @see java.awt.GraphicsEnvironment#isHeadless
137      */
138     public Button() throws HeadlessException {
139         this("");
140     }
141 
142     /**
143      * Constructs a button with the specified label.
144      *
145      * @param label  a string label for the button, or
146      *               <code>null</code> for no label
147      * @exception HeadlessException if GraphicsEnvironment.isHeadless()
148      * returns true
149      * @see java.awt.GraphicsEnvironment#isHeadless
150      */
151     public Button(String label) throws HeadlessException {
152         GraphicsEnvironment.checkHeadless();
153         this.label = label;
154     }
155 
156     /**
157      * Construct a name for this component.  Called by getName() when the
158      * name is null.
159      */
160     String constructComponentName() {
161         synchronized (Button.class) {
162             return base + nameCounter++;
163         }
164     }
165 
166     /**
167      * Creates the peer of the button.  The button's peer allows the
168      * application to change the look of the button without changing
169      * its functionality.
170      *
171      * @see     java.awt.Toolkit#createButton(java.awt.Button)
172      * @see     java.awt.Component#getToolkit()
173      */
174     public void addNotify() {
175         synchronized(getTreeLock()) {
176             if (peer == null)
177                 peer = getToolkit().createButton(this);
178             super.addNotify();
179         }
180     }
181 
182     /**
183      * Gets the label of this button.
184      *
185      * @return    the button's label, or <code>null</code>
186      *                if the button has no label.
187      * @see       java.awt.Button#setLabel
188      */
189     public String getLabel() {
190         return label;
191     }
192 
193     /**
194      * Sets the button's label to be the specified string.
195      *
196      * @param     label   the new label, or <code>null</code>
197      *                if the button has no label.
198      * @see       java.awt.Button#getLabel
199      */
200     public void setLabel(String label) {
201         boolean testvalid = false;
202 
203         synchronized (this) {
204             if (label != this.label && (this.label == null ||
205                                         !this.label.equals(label))) {
206                 this.label = label;
207                 ButtonPeer peer = (ButtonPeer)this.peer;
208                 if (peer != null) {
209                     peer.setLabel(label);
210                 }
211                 testvalid = true;
212             }
213         }
214 
215         // This could change the preferred size of the Component.
216         if (testvalid) {
217             invalidateIfValid();
218         }
219     }
220 
221     /**
222      * Sets the command name for the action event fired
223      * by this button. By default this action command is
224      * set to match the label of the button.
225      *
226      * @param     command  a string used to set the button's
227      *                  action command.
228      *            If the string is <code>null</code> then the action command
229      *            is set to match the label of the button.
230      * @see       java.awt.event.ActionEvent
231      * @since     JDK1.1
232      */
233     public void setActionCommand(String command) {
234         actionCommand = command;
235     }
236 
237     /**
238      * Returns the command name of the action event fired by this button.
239      * If the command name is <code>null</code> (default) then this method
240      * returns the label of the button.
241      */
242     public String getActionCommand() {
243         return (actionCommand == null? label : actionCommand);
244     }
245 
246     /**
247      * Adds the specified action listener to receive action events from
248      * this button. Action events occur when a user presses or releases
249      * the mouse over this button.
250      * If l is null, no exception is thrown and no action is performed.
251      * <p>Refer to <a href="doc-files/AWTThreadIssues.html#ListenersThreads"
252      * >AWT Threading Issues</a> for details on AWT's threading model.
253      *
254      * @param         l the action listener
255      * @see           #removeActionListener
256      * @see           #getActionListeners
257      * @see           java.awt.event.ActionListener
258      * @since         JDK1.1
259      */
260     public synchronized void addActionListener(ActionListener l) {
261         if (l == null) {
262             return;
263         }
264         actionListener = AWTEventMulticaster.add(actionListener, l);
265         newEventsOnly = true;
266     }
267 
268     /**
269      * Removes the specified action listener so that it no longer
270      * receives action events from this button. Action events occur
271      * when a user presses or releases the mouse over this button.
272      * If l is null, no exception is thrown and no action is performed.
273      * <p>Refer to <a href="doc-files/AWTThreadIssues.html#ListenersThreads"
274      * >AWT Threading Issues</a> for details on AWT's threading model.
275      *
276      * @param           l     the action listener
277      * @see             #addActionListener
278      * @see             #getActionListeners
279      * @see             java.awt.event.ActionListener
280      * @since           JDK1.1
281      */
282     public synchronized void removeActionListener(ActionListener l) {
283         if (l == null) {
284             return;
285         }
286         actionListener = AWTEventMulticaster.remove(actionListener, l);
287     }
288 
289     /**
290      * Returns an array of all the action listeners
291      * registered on this button.
292      *
293      * @return all of this button's <code>ActionListener</code>s
294      *         or an empty array if no action
295      *         listeners are currently registered
296      *
297      * @see             #addActionListener
298      * @see             #removeActionListener
299      * @see             java.awt.event.ActionListener
300      * @since 1.4
301      */
302     public synchronized ActionListener[] getActionListeners() {
303         return getListeners(ActionListener.class);
304     }
305 
306     /**
307      * Returns an array of all the objects currently registered
308      * as <code><em>Foo</em>Listener</code>s
309      * upon this <code>Button</code>.
310      * <code><em>Foo</em>Listener</code>s are registered using the
311      * <code>add<em>Foo</em>Listener</code> method.
312      *
313      * <p>
314      * You can specify the <code>listenerType</code> argument
315      * with a class literal, such as
316      * <code><em>Foo</em>Listener.class</code>.
317      * For example, you can query a
318      * <code>Button</code> <code>b</code>
319      * for its action listeners with the following code:
320      *
321      * <pre>ActionListener[] als = (ActionListener[])(b.getListeners(ActionListener.class));</pre>
322      *
323      * If no such listeners exist, this method returns an empty array.
324      *
325      * @param listenerType the type of listeners requested; this parameter
326      *          should specify an interface that descends from
327      *          <code>java.util.EventListener</code>
328      * @return an array of all objects registered as
329      *          <code><em>Foo</em>Listener</code>s on this button,
330      *          or an empty array if no such
331      *          listeners have been added
332      * @exception ClassCastException if <code>listenerType</code>
333      *          doesn't specify a class or interface that implements
334      *          <code>java.util.EventListener</code>
335      *
336      * @see #getActionListeners
337      * @since 1.3
338      */
339     public <T extends EventListener> T[] getListeners(Class<T> listenerType) {
340         EventListener l = null;
341         if  (listenerType == ActionListener.class) {
342             l = actionListener;
343         } else {
344             return super.getListeners(listenerType);
345         }
346         return AWTEventMulticaster.getListeners(l, listenerType);
347     }
348 
349     // REMIND: remove when filtering is done at lower level
350     boolean eventEnabled(AWTEvent e) {
351         if (e.id == ActionEvent.ACTION_PERFORMED) {
352             if ((eventMask & AWTEvent.ACTION_EVENT_MASK) != 0 ||
353                 actionListener != null) {
354                 return true;
355             }
356             return false;
357         }
358         return super.eventEnabled(e);
359     }
360 
361     /**
362      * Processes events on this button. If an event is
363      * an instance of <code>ActionEvent</code>, this method invokes
364      * the <code>processActionEvent</code> method. Otherwise,
365      * it invokes <code>processEvent</code> on the superclass.
366      * <p>Note that if the event parameter is <code>null</code>
367      * the behavior is unspecified and may result in an
368      * exception.
369      *
370      * @param        e the event
371      * @see          java.awt.event.ActionEvent
372      * @see          java.awt.Button#processActionEvent
373      * @since        JDK1.1
374      */
375     protected void processEvent(AWTEvent e) {
376         if (e instanceof ActionEvent) {
377             processActionEvent((ActionEvent)e);
378             return;
379         }
380         super.processEvent(e);
381     }
382 
383     /**
384      * Processes action events occurring on this button
385      * by dispatching them to any registered
386      * <code>ActionListener</code> objects.
387      * <p>
388      * This method is not called unless action events are
389      * enabled for this button. Action events are enabled
390      * when one of the following occurs:
391      * <ul>
392      * <li>An <code>ActionListener</code> object is registered
393      * via <code>addActionListener</code>.
394      * <li>Action events are enabled via <code>enableEvents</code>.
395      * </ul>
396      * <p>Note that if the event parameter is <code>null</code>
397      * the behavior is unspecified and may result in an
398      * exception.
399      *
400      * @param       e the action event
401      * @see         java.awt.event.ActionListener
402      * @see         java.awt.Button#addActionListener
403      * @see         java.awt.Component#enableEvents
404      * @since       JDK1.1
405      */
406     protected void processActionEvent(ActionEvent e) {
407         ActionListener listener = actionListener;
408         if (listener != null) {
409             listener.actionPerformed(e);
410         }
411     }
412 
413     /**
414      * Returns a string representing the state of this <code>Button</code>.
415      * This method is intended to be used only for debugging purposes, and the
416      * content and format of the returned string may vary between
417      * implementations. The returned string may be empty but may not be
418      * <code>null</code>.
419      *
420      * @return     the parameter string of this button
421      */
422     protected String paramString() {
423         return super.paramString() + ",label=" + label;
424     }
425 
426 
427     /* Serialization support.
428      */
429 
430     /*
431      * Button Serial Data Version.
432      * @serial
433      */
434     private int buttonSerializedDataVersion = 1;
435 
436     /**
437      * Writes default serializable fields to stream.  Writes
438      * a list of serializable <code>ActionListeners</code>
439      * as optional data.  The non-serializable
440      * <code>ActionListeners</code> are detected and
441      * no attempt is made to serialize them.
442      *
443      * @serialData <code>null</code> terminated sequence of 0 or
444      *   more pairs: the pair consists of a <code>String</code>
445      *   and an <code>Object</code>; the <code>String</code>
446      *   indicates the type of object and is one of the following:
447      *   <code>actionListenerK</code> indicating an
448      *     <code>ActionListener</code> object
449      *
450      * @param s the <code>ObjectOutputStream</code> to write
451      * @see AWTEventMulticaster#save(ObjectOutputStream, String, EventListener)
452      * @see java.awt.Component#actionListenerK
453      * @see #readObject(ObjectInputStream)
454      */
455     private void writeObject(ObjectOutputStream s)
456       throws IOException
457     {
458       s.defaultWriteObject();
459 
460       AWTEventMulticaster.save(s, actionListenerK, actionListener);
461       s.writeObject(null);
462     }
463 
464     /**
465      * Reads the <code>ObjectInputStream</code> and if
466      * it isn't <code>null</code> adds a listener to
467      * receive action events fired by the button.
468      * Unrecognized keys or values will be ignored.
469      *
470      * @param s the <code>ObjectInputStream</code> to read
471      * @exception HeadlessException if
472      *   <code>GraphicsEnvironment.isHeadless</code> returns
473      *   <code>true</code>
474      * @serial
475      * @see #removeActionListener(ActionListener)
476      * @see #addActionListener(ActionListener)
477      * @see java.awt.GraphicsEnvironment#isHeadless
478      * @see #writeObject(ObjectOutputStream)
479      */
480     private void readObject(ObjectInputStream s)
481       throws ClassNotFoundException, IOException, HeadlessException
482     {
483       GraphicsEnvironment.checkHeadless();
484       s.defaultReadObject();
485 
486       Object keyOrNull;
487       while(null != (keyOrNull = s.readObject())) {
488         String key = ((String)keyOrNull).intern();
489 
490         if (actionListenerK == key)
491           addActionListener((ActionListener)(s.readObject()));
492 
493         else // skip value for unrecognized key
494           s.readObject();
495       }
496     }
497 
498 
499 /////////////////
500 // Accessibility support
501 ////////////////
502 
503     /**
504      * Gets the <code>AccessibleContext</code> associated with
505      * this <code>Button</code>. For buttons, the
506      * <code>AccessibleContext</code> takes the form of an
507      * <code>AccessibleAWTButton</code>.
508      * A new <code>AccessibleAWTButton</code> instance is
509      * created if necessary.
510      *
511      * @return an <code>AccessibleAWTButton</code> that serves as the
512      *         <code>AccessibleContext</code> of this <code>Button</code>
513      * @beaninfo
514      *       expert: true
515      *  description: The AccessibleContext associated with this Button.
516      * @since 1.3
517      */
518     public AccessibleContext getAccessibleContext() {
519         if (accessibleContext == null) {
520             accessibleContext = new AccessibleAWTButton();
521         }
522         return accessibleContext;
523     }
524 
525     /**
526      * This class implements accessibility support for the
527      * <code>Button</code> class.  It provides an implementation of the
528      * Java Accessibility API appropriate to button user-interface elements.
529      * @since 1.3
530      */
531     protected class AccessibleAWTButton extends AccessibleAWTComponent
532         implements AccessibleAction, AccessibleValue
533     {
534         /*
535          * JDK 1.3 serialVersionUID
536          */
537         private static final long serialVersionUID = -5932203980244017102L;
538 
539         /**
540          * Get the accessible name of this object.
541          *
542          * @return the localized name of the object -- can be null if this
543          * object does not have a name
544          */
545         public String getAccessibleName() {
546             if (accessibleName != null) {
547                 return accessibleName;
548             } else {
549                 if (getLabel() == null) {
550                     return super.getAccessibleName();
551                 } else {
552                     return getLabel();
553                 }
554             }
555         }
556 
557         /**
558          * Get the AccessibleAction associated with this object.  In the
559          * implementation of the Java Accessibility API for this class,
560          * return this object, which is responsible for implementing the
561          * AccessibleAction interface on behalf of itself.
562          *
563          * @return this object
564          */
565         public AccessibleAction getAccessibleAction() {
566             return this;
567         }
568 
569         /**
570          * Get the AccessibleValue associated with this object.  In the
571          * implementation of the Java Accessibility API for this class,
572          * return this object, which is responsible for implementing the
573          * AccessibleValue interface on behalf of itself.
574          *
575          * @return this object
576          */
577         public AccessibleValue getAccessibleValue() {
578             return this;
579         }
580 
581         /**
582          * Returns the number of Actions available in this object.  The
583          * default behavior of a button is to have one action - toggle
584          * the button.
585          *
586          * @return 1, the number of Actions in this object
587          */
588         public int getAccessibleActionCount() {
589             return 1;
590         }
591 
592         /**
593          * Return a description of the specified action of the object.
594          *
595          * @param i zero-based index of the actions
596          */
597         public String getAccessibleActionDescription(int i) {
598             if (i == 0) {
599                 // [[[PENDING:  WDW -- need to provide a localized string]]]
600                 return "click";
601             } else {
602                 return null;
603             }
604         }
605 
606         /**
607          * Perform the specified Action on the object
608          *
609          * @param i zero-based index of actions
610          * @return true if the the action was performed; else false.
611          */
612         public boolean doAccessibleAction(int i) {
613             if (i == 0) {
614                 // Simulate a button click
615                 Toolkit.getEventQueue().postEvent(
616                         new ActionEvent(Button.this,
617                                         ActionEvent.ACTION_PERFORMED,
618                                         Button.this.getActionCommand()));
619                 return true;
620             } else {
621                 return false;
622             }
623         }
624 
625         /**
626          * Get the value of this object as a Number.
627          *
628          * @return An Integer of 0 if this isn't selected or an Integer of 1 if
629          * this is selected.
630          * @see javax.swing.AbstractButton#isSelected()
631          */
632         public Number getCurrentAccessibleValue() {
633             return Integer.valueOf(0);
634         }
635 
636         /**
637          * Set the value of this object as a Number.
638          *
639          * @return True if the value was set.
640          */
641         public boolean setCurrentAccessibleValue(Number n) {
642             return false;
643         }
644 
645         /**
646          * Get the minimum value of this object as a Number.
647          *
648          * @return An Integer of 0.
649          */
650         public Number getMinimumAccessibleValue() {
651             return Integer.valueOf(0);
652         }
653 
654         /**
655          * Get the maximum value of this object as a Number.
656          *
657          * @return An Integer of 0.
658          */
659         public Number getMaximumAccessibleValue() {
660             return Integer.valueOf(0);
661         }
662 
663         /**
664          * Get the role of this object.
665          *
666          * @return an instance of AccessibleRole describing the role of the
667          * object
668          * @see AccessibleRole
669          */
670         public AccessibleRole getAccessibleRole() {
671             return AccessibleRole.PUSH_BUTTON;
672         }
673     } // inner class AccessibleAWTButton
674 
675 }