1 /*
   2  * Copyright (c) 1995, 2015, 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       1.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.Component#getToolkit()
 172      */
 173     public void addNotify() {
 174         synchronized(getTreeLock()) {
 175             if (peer == null)
 176                 peer = getComponentFactory().createButton(this);
 177             super.addNotify();
 178         }
 179     }
 180 
 181     /**
 182      * Gets the label of this button.
 183      *
 184      * @return    the button's label, or <code>null</code>
 185      *                if the button has no label.
 186      * @see       java.awt.Button#setLabel
 187      */
 188     public String getLabel() {
 189         return label;
 190     }
 191 
 192     /**
 193      * Sets the button's label to be the specified string.
 194      *
 195      * @param     label   the new label, or <code>null</code>
 196      *                if the button has no label.
 197      * @see       java.awt.Button#getLabel
 198      */
 199     public void setLabel(String label) {
 200         boolean testvalid = false;
 201 
 202         synchronized (this) {
 203             if (label != this.label && (this.label == null ||
 204                                         !this.label.equals(label))) {
 205                 this.label = label;
 206                 ButtonPeer peer = (ButtonPeer)this.peer;
 207                 if (peer != null) {
 208                     peer.setLabel(label);
 209                 }
 210                 testvalid = true;
 211             }
 212         }
 213 
 214         // This could change the preferred size of the Component.
 215         if (testvalid) {
 216             invalidateIfValid();
 217         }
 218     }
 219 
 220     /**
 221      * Sets the command name for the action event fired
 222      * by this button. By default this action command is
 223      * set to match the label of the button.
 224      *
 225      * @param     command  a string used to set the button's
 226      *                  action command.
 227      *            If the string is <code>null</code> then the action command
 228      *            is set to match the label of the button.
 229      * @see       java.awt.event.ActionEvent
 230      * @since     1.1
 231      */
 232     public void setActionCommand(String command) {
 233         actionCommand = command;
 234     }
 235 
 236     /**
 237      * Returns the command name of the action event fired by this button.
 238      * If the command name is <code>null</code> (default) then this method
 239      * returns the label of the button.
 240      *
 241      * @return the action command name (or label) for this button
 242      */
 243     public String getActionCommand() {
 244         return (actionCommand == null? label : actionCommand);
 245     }
 246 
 247     /**
 248      * Adds the specified action listener to receive action events from
 249      * this button. Action events occur when a user presses or releases
 250      * the mouse over this button.
 251      * If l is null, no exception is thrown and no action is performed.
 252      * <p>Refer to <a href="doc-files/AWTThreadIssues.html#ListenersThreads"
 253      * >AWT Threading Issues</a> for details on AWT's threading model.
 254      *
 255      * @param         l the action listener
 256      * @see           #removeActionListener
 257      * @see           #getActionListeners
 258      * @see           java.awt.event.ActionListener
 259      * @since         1.1
 260      */
 261     public synchronized void addActionListener(ActionListener l) {
 262         if (l == null) {
 263             return;
 264         }
 265         actionListener = AWTEventMulticaster.add(actionListener, l);
 266         newEventsOnly = true;
 267     }
 268 
 269     /**
 270      * Removes the specified action listener so that it no longer
 271      * receives action events from this button. Action events occur
 272      * when a user presses or releases the mouse over this button.
 273      * If l is null, no exception is thrown and no action is performed.
 274      * <p>Refer to <a href="doc-files/AWTThreadIssues.html#ListenersThreads"
 275      * >AWT Threading Issues</a> for details on AWT's threading model.
 276      *
 277      * @param           l     the action listener
 278      * @see             #addActionListener
 279      * @see             #getActionListeners
 280      * @see             java.awt.event.ActionListener
 281      * @since           1.1
 282      */
 283     public synchronized void removeActionListener(ActionListener l) {
 284         if (l == null) {
 285             return;
 286         }
 287         actionListener = AWTEventMulticaster.remove(actionListener, l);
 288     }
 289 
 290     /**
 291      * Returns an array of all the action listeners
 292      * registered on this button.
 293      *
 294      * @return all of this button's <code>ActionListener</code>s
 295      *         or an empty array if no action
 296      *         listeners are currently registered
 297      *
 298      * @see             #addActionListener
 299      * @see             #removeActionListener
 300      * @see             java.awt.event.ActionListener
 301      * @since 1.4
 302      */
 303     public synchronized ActionListener[] getActionListeners() {
 304         return getListeners(ActionListener.class);
 305     }
 306 
 307     /**
 308      * Returns an array of all the objects currently registered
 309      * as <code><em>Foo</em>Listener</code>s
 310      * upon this <code>Button</code>.
 311      * <code><em>Foo</em>Listener</code>s are registered using the
 312      * <code>add<em>Foo</em>Listener</code> method.
 313      *
 314      * <p>
 315      * You can specify the <code>listenerType</code> argument
 316      * with a class literal, such as
 317      * <code><em>Foo</em>Listener.class</code>.
 318      * For example, you can query a
 319      * <code>Button</code> <code>b</code>
 320      * for its action listeners with the following code:
 321      *
 322      * <pre>ActionListener[] als = (ActionListener[])(b.getListeners(ActionListener.class));</pre>
 323      *
 324      * If no such listeners exist, this method returns an empty array.
 325      *
 326      * @param listenerType the type of listeners requested; this parameter
 327      *          should specify an interface that descends from
 328      *          <code>java.util.EventListener</code>
 329      * @return an array of all objects registered as
 330      *          <code><em>Foo</em>Listener</code>s on this button,
 331      *          or an empty array if no such
 332      *          listeners have been added
 333      * @exception ClassCastException if <code>listenerType</code>
 334      *          doesn't specify a class or interface that implements
 335      *          <code>java.util.EventListener</code>
 336      *
 337      * @see #getActionListeners
 338      * @since 1.3
 339      */
 340     public <T extends EventListener> T[] getListeners(Class<T> listenerType) {
 341         EventListener l = null;
 342         if  (listenerType == ActionListener.class) {
 343             l = actionListener;
 344         } else {
 345             return super.getListeners(listenerType);
 346         }
 347         return AWTEventMulticaster.getListeners(l, listenerType);
 348     }
 349 
 350     // REMIND: remove when filtering is done at lower level
 351     boolean eventEnabled(AWTEvent e) {
 352         if (e.id == ActionEvent.ACTION_PERFORMED) {
 353             if ((eventMask & AWTEvent.ACTION_EVENT_MASK) != 0 ||
 354                 actionListener != null) {
 355                 return true;
 356             }
 357             return false;
 358         }
 359         return super.eventEnabled(e);
 360     }
 361 
 362     /**
 363      * Processes events on this button. If an event is
 364      * an instance of <code>ActionEvent</code>, this method invokes
 365      * the <code>processActionEvent</code> method. Otherwise,
 366      * it invokes <code>processEvent</code> on the superclass.
 367      * <p>Note that if the event parameter is <code>null</code>
 368      * the behavior is unspecified and may result in an
 369      * exception.
 370      *
 371      * @param        e the event
 372      * @see          java.awt.event.ActionEvent
 373      * @see          java.awt.Button#processActionEvent
 374      * @since        1.1
 375      */
 376     protected void processEvent(AWTEvent e) {
 377         if (e instanceof ActionEvent) {
 378             processActionEvent((ActionEvent)e);
 379             return;
 380         }
 381         super.processEvent(e);
 382     }
 383 
 384     /**
 385      * Processes action events occurring on this button
 386      * by dispatching them to any registered
 387      * <code>ActionListener</code> objects.
 388      * <p>
 389      * This method is not called unless action events are
 390      * enabled for this button. Action events are enabled
 391      * when one of the following occurs:
 392      * <ul>
 393      * <li>An <code>ActionListener</code> object is registered
 394      * via <code>addActionListener</code>.
 395      * <li>Action events are enabled via <code>enableEvents</code>.
 396      * </ul>
 397      * <p>Note that if the event parameter is <code>null</code>
 398      * the behavior is unspecified and may result in an
 399      * exception.
 400      *
 401      * @param       e the action event
 402      * @see         java.awt.event.ActionListener
 403      * @see         java.awt.Button#addActionListener
 404      * @see         java.awt.Component#enableEvents
 405      * @since       1.1
 406      */
 407     protected void processActionEvent(ActionEvent e) {
 408         ActionListener listener = actionListener;
 409         if (listener != null) {
 410             listener.actionPerformed(e);
 411         }
 412     }
 413 
 414     /**
 415      * Returns a string representing the state of this <code>Button</code>.
 416      * This method is intended to be used only for debugging purposes, and the
 417      * content and format of the returned string may vary between
 418      * implementations. The returned string may be empty but may not be
 419      * <code>null</code>.
 420      *
 421      * @return     the parameter string of this button
 422      */
 423     protected String paramString() {
 424         return super.paramString() + ",label=" + label;
 425     }
 426 
 427 
 428     /* Serialization support.
 429      */
 430 
 431     /*
 432      * Button Serial Data Version.
 433      * @serial
 434      */
 435     private int buttonSerializedDataVersion = 1;
 436 
 437     /**
 438      * Writes default serializable fields to stream.  Writes
 439      * a list of serializable <code>ActionListeners</code>
 440      * as optional data.  The non-serializable
 441      * <code>ActionListeners</code> are detected and
 442      * no attempt is made to serialize them.
 443      *
 444      * @serialData <code>null</code> terminated sequence of 0 or
 445      *   more pairs: the pair consists of a <code>String</code>
 446      *   and an <code>Object</code>; the <code>String</code>
 447      *   indicates the type of object and is one of the following:
 448      *   <code>actionListenerK</code> indicating an
 449      *     <code>ActionListener</code> object
 450      *
 451      * @param s the <code>ObjectOutputStream</code> to write
 452      * @see AWTEventMulticaster#save(ObjectOutputStream, String, EventListener)
 453      * @see java.awt.Component#actionListenerK
 454      * @see #readObject(ObjectInputStream)
 455      */
 456     private void writeObject(ObjectOutputStream s)
 457       throws IOException
 458     {
 459       s.defaultWriteObject();
 460 
 461       AWTEventMulticaster.save(s, actionListenerK, actionListener);
 462       s.writeObject(null);
 463     }
 464 
 465     /**
 466      * Reads the <code>ObjectInputStream</code> and if
 467      * it isn't <code>null</code> adds a listener to
 468      * receive action events fired by the button.
 469      * Unrecognized keys or values will be ignored.
 470      *
 471      * @param s the <code>ObjectInputStream</code> to read
 472      * @exception HeadlessException if
 473      *   <code>GraphicsEnvironment.isHeadless</code> returns
 474      *   <code>true</code>
 475      * @serial
 476      * @see #removeActionListener(ActionListener)
 477      * @see #addActionListener(ActionListener)
 478      * @see java.awt.GraphicsEnvironment#isHeadless
 479      * @see #writeObject(ObjectOutputStream)
 480      */
 481     private void readObject(ObjectInputStream s)
 482       throws ClassNotFoundException, IOException, HeadlessException
 483     {
 484       GraphicsEnvironment.checkHeadless();
 485       s.defaultReadObject();
 486 
 487       Object keyOrNull;
 488       while(null != (keyOrNull = s.readObject())) {
 489         String key = ((String)keyOrNull).intern();
 490 
 491         if (actionListenerK == key)
 492           addActionListener((ActionListener)(s.readObject()));
 493 
 494         else // skip value for unrecognized key
 495           s.readObject();
 496       }
 497     }
 498 
 499 
 500 /////////////////
 501 // Accessibility support
 502 ////////////////
 503 
 504     /**
 505      * Gets the <code>AccessibleContext</code> associated with
 506      * this <code>Button</code>. For buttons, the
 507      * <code>AccessibleContext</code> takes the form of an
 508      * <code>AccessibleAWTButton</code>.
 509      * A new <code>AccessibleAWTButton</code> instance is
 510      * created if necessary.
 511      *
 512      * @return an <code>AccessibleAWTButton</code> that serves as the
 513      *         <code>AccessibleContext</code> of this <code>Button</code>
 514      * @beaninfo
 515      *       expert: true
 516      *  description: The AccessibleContext associated with this Button.
 517      * @since 1.3
 518      */
 519     public AccessibleContext getAccessibleContext() {
 520         if (accessibleContext == null) {
 521             accessibleContext = new AccessibleAWTButton();
 522         }
 523         return accessibleContext;
 524     }
 525 
 526     /**
 527      * This class implements accessibility support for the
 528      * <code>Button</code> class.  It provides an implementation of the
 529      * Java Accessibility API appropriate to button user-interface elements.
 530      * @since 1.3
 531      */
 532     protected class AccessibleAWTButton extends AccessibleAWTComponent
 533         implements AccessibleAction, AccessibleValue
 534     {
 535         /*
 536          * JDK 1.3 serialVersionUID
 537          */
 538         private static final long serialVersionUID = -5932203980244017102L;
 539 
 540         /**
 541          * Get the accessible name of this object.
 542          *
 543          * @return the localized name of the object -- can be null if this
 544          * object does not have a name
 545          */
 546         public String getAccessibleName() {
 547             if (accessibleName != null) {
 548                 return accessibleName;
 549             } else {
 550                 if (getLabel() == null) {
 551                     return super.getAccessibleName();
 552                 } else {
 553                     return getLabel();
 554                 }
 555             }
 556         }
 557 
 558         /**
 559          * Get the AccessibleAction associated with this object.  In the
 560          * implementation of the Java Accessibility API for this class,
 561          * return this object, which is responsible for implementing the
 562          * AccessibleAction interface on behalf of itself.
 563          *
 564          * @return this object
 565          */
 566         public AccessibleAction getAccessibleAction() {
 567             return this;
 568         }
 569 
 570         /**
 571          * Get the AccessibleValue associated with this object.  In the
 572          * implementation of the Java Accessibility API for this class,
 573          * return this object, which is responsible for implementing the
 574          * AccessibleValue interface on behalf of itself.
 575          *
 576          * @return this object
 577          */
 578         public AccessibleValue getAccessibleValue() {
 579             return this;
 580         }
 581 
 582         /**
 583          * Returns the number of Actions available in this object.  The
 584          * default behavior of a button is to have one action - toggle
 585          * the button.
 586          *
 587          * @return 1, the number of Actions in this object
 588          */
 589         public int getAccessibleActionCount() {
 590             return 1;
 591         }
 592 
 593         /**
 594          * Return a description of the specified action of the object.
 595          *
 596          * @param i zero-based index of the actions
 597          */
 598         public String getAccessibleActionDescription(int i) {
 599             if (i == 0) {
 600                 // [[[PENDING:  WDW -- need to provide a localized string]]]
 601                 return "click";
 602             } else {
 603                 return null;
 604             }
 605         }
 606 
 607         /**
 608          * Perform the specified Action on the object
 609          *
 610          * @param i zero-based index of actions
 611          * @return true if the action was performed; else false.
 612          */
 613         public boolean doAccessibleAction(int i) {
 614             if (i == 0) {
 615                 // Simulate a button click
 616                 Toolkit.getEventQueue().postEvent(
 617                         new ActionEvent(Button.this,
 618                                         ActionEvent.ACTION_PERFORMED,
 619                                         Button.this.getActionCommand()));
 620                 return true;
 621             } else {
 622                 return false;
 623             }
 624         }
 625 
 626         /**
 627          * Get the value of this object as a Number.
 628          *
 629          * @return An Integer of 0 if this isn't selected or an Integer of 1 if
 630          * this is selected.
 631          * @see javax.swing.AbstractButton#isSelected()
 632          */
 633         public Number getCurrentAccessibleValue() {
 634             return Integer.valueOf(0);
 635         }
 636 
 637         /**
 638          * Set the value of this object as a Number.
 639          *
 640          * @return True if the value was set.
 641          */
 642         public boolean setCurrentAccessibleValue(Number n) {
 643             return false;
 644         }
 645 
 646         /**
 647          * Get the minimum value of this object as a Number.
 648          *
 649          * @return An Integer of 0.
 650          */
 651         public Number getMinimumAccessibleValue() {
 652             return Integer.valueOf(0);
 653         }
 654 
 655         /**
 656          * Get the maximum value of this object as a Number.
 657          *
 658          * @return An Integer of 0.
 659          */
 660         public Number getMaximumAccessibleValue() {
 661             return Integer.valueOf(0);
 662         }
 663 
 664         /**
 665          * Get the role of this object.
 666          *
 667          * @return an instance of AccessibleRole describing the role of the
 668          * object
 669          * @see AccessibleRole
 670          */
 671         public AccessibleRole getAccessibleRole() {
 672             return AccessibleRole.PUSH_BUTTON;
 673         }
 674     } // inner class AccessibleAWTButton
 675 
 676 }