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