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.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.Component#getToolkit()
 173      */
 174     public void addNotify() {
 175         synchronized(getTreeLock()) {
 176             if (peer == null)
 177                 peer = getComponentFactory().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     1.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      * @return the action command name (or label) for this button
 243      */
 244     public String getActionCommand() {
 245         return (actionCommand == null? label : actionCommand);
 246     }
 247 
 248     /**
 249      * Adds the specified action listener to receive action events from
 250      * this button. Action events occur when a user presses or releases
 251      * the mouse over this button.
 252      * If l is null, no exception is thrown and no action is performed.
 253      * <p>Refer to <a href="doc-files/AWTThreadIssues.html#ListenersThreads"
 254      * >AWT Threading Issues</a> for details on AWT's threading model.
 255      *
 256      * @param         l the action listener
 257      * @see           #removeActionListener
 258      * @see           #getActionListeners
 259      * @see           java.awt.event.ActionListener
 260      * @since         1.1
 261      */
 262     public synchronized void addActionListener(ActionListener l) {
 263         if (l == null) {
 264             return;
 265         }
 266         actionListener = AWTEventMulticaster.add(actionListener, l);
 267         newEventsOnly = true;
 268     }
 269 
 270     /**
 271      * Removes the specified action listener so that it no longer
 272      * receives action events from this button. Action events occur
 273      * when a user presses or releases the mouse over this button.
 274      * If l is null, no exception is thrown and no action is performed.
 275      * <p>Refer to <a href="doc-files/AWTThreadIssues.html#ListenersThreads"
 276      * >AWT Threading Issues</a> for details on AWT's threading model.
 277      *
 278      * @param           l     the action listener
 279      * @see             #addActionListener
 280      * @see             #getActionListeners
 281      * @see             java.awt.event.ActionListener
 282      * @since           1.1
 283      */
 284     public synchronized void removeActionListener(ActionListener l) {
 285         if (l == null) {
 286             return;
 287         }
 288         actionListener = AWTEventMulticaster.remove(actionListener, l);
 289     }
 290 
 291     /**
 292      * Returns an array of all the action listeners
 293      * registered on this button.
 294      *
 295      * @return all of this button's <code>ActionListener</code>s
 296      *         or an empty array if no action
 297      *         listeners are currently registered
 298      *
 299      * @see             #addActionListener
 300      * @see             #removeActionListener
 301      * @see             java.awt.event.ActionListener
 302      * @since 1.4
 303      */
 304     public synchronized ActionListener[] getActionListeners() {
 305         return getListeners(ActionListener.class);
 306     }
 307 
 308     /**
 309      * Returns an array of all the objects currently registered
 310      * as <code><em>Foo</em>Listener</code>s
 311      * upon this <code>Button</code>.
 312      * <code><em>Foo</em>Listener</code>s are registered using the
 313      * <code>add<em>Foo</em>Listener</code> method.
 314      *
 315      * <p>
 316      * You can specify the <code>listenerType</code> argument
 317      * with a class literal, such as
 318      * <code><em>Foo</em>Listener.class</code>.
 319      * For example, you can query a
 320      * <code>Button</code> <code>b</code>
 321      * for its action listeners with the following code:
 322      *
 323      * <pre>ActionListener[] als = (ActionListener[])(b.getListeners(ActionListener.class));</pre>
 324      *
 325      * If no such listeners exist, this method returns an empty array.
 326      *
 327      * @param listenerType the type of listeners requested; this parameter
 328      *          should specify an interface that descends from
 329      *          <code>java.util.EventListener</code>
 330      * @return an array of all objects registered as
 331      *          <code><em>Foo</em>Listener</code>s on this button,
 332      *          or an empty array if no such
 333      *          listeners have been added
 334      * @exception ClassCastException if <code>listenerType</code>
 335      *          doesn't specify a class or interface that implements
 336      *          <code>java.util.EventListener</code>
 337      *
 338      * @see #getActionListeners
 339      * @since 1.3
 340      */
 341     public <T extends EventListener> T[] getListeners(Class<T> listenerType) {
 342         EventListener l = null;
 343         if  (listenerType == ActionListener.class) {
 344             l = actionListener;
 345         } else {
 346             return super.getListeners(listenerType);
 347         }
 348         return AWTEventMulticaster.getListeners(l, listenerType);
 349     }
 350 
 351     // REMIND: remove when filtering is done at lower level
 352     boolean eventEnabled(AWTEvent e) {
 353         if (e.id == ActionEvent.ACTION_PERFORMED) {
 354             if ((eventMask & AWTEvent.ACTION_EVENT_MASK) != 0 ||
 355                 actionListener != null) {
 356                 return true;
 357             }
 358             return false;
 359         }
 360         return super.eventEnabled(e);
 361     }
 362 
 363     /**
 364      * Processes events on this button. If an event is
 365      * an instance of <code>ActionEvent</code>, this method invokes
 366      * the <code>processActionEvent</code> method. Otherwise,
 367      * it invokes <code>processEvent</code> on the superclass.
 368      * <p>Note that if the event parameter is <code>null</code>
 369      * the behavior is unspecified and may result in an
 370      * exception.
 371      *
 372      * @param        e the event
 373      * @see          java.awt.event.ActionEvent
 374      * @see          java.awt.Button#processActionEvent
 375      * @since        1.1
 376      */
 377     protected void processEvent(AWTEvent e) {
 378         if (e instanceof ActionEvent) {
 379             processActionEvent((ActionEvent)e);
 380             return;
 381         }
 382         super.processEvent(e);
 383     }
 384 
 385     /**
 386      * Processes action events occurring on this button
 387      * by dispatching them to any registered
 388      * <code>ActionListener</code> objects.
 389      * <p>
 390      * This method is not called unless action events are
 391      * enabled for this button. Action events are enabled
 392      * when one of the following occurs:
 393      * <ul>
 394      * <li>An <code>ActionListener</code> object is registered
 395      * via <code>addActionListener</code>.
 396      * <li>Action events are enabled via <code>enableEvents</code>.
 397      * </ul>
 398      * <p>Note that if the event parameter is <code>null</code>
 399      * the behavior is unspecified and may result in an
 400      * exception.
 401      *
 402      * @param       e the action event
 403      * @see         java.awt.event.ActionListener
 404      * @see         java.awt.Button#addActionListener
 405      * @see         java.awt.Component#enableEvents
 406      * @since       1.1
 407      */
 408     protected void processActionEvent(ActionEvent e) {
 409         ActionListener listener = actionListener;
 410         if (listener != null) {
 411             listener.actionPerformed(e);
 412         }
 413     }
 414 
 415     /**
 416      * Returns a string representing the state of this <code>Button</code>.
 417      * This method is intended to be used only for debugging purposes, and the
 418      * content and format of the returned string may vary between
 419      * implementations. The returned string may be empty but may not be
 420      * <code>null</code>.
 421      *
 422      * @return     the parameter string of this button
 423      */
 424     protected String paramString() {
 425         return super.paramString() + ",label=" + label;
 426     }
 427 
 428 
 429     /* Serialization support.
 430      */
 431 
 432     /*
 433      * Button Serial Data Version.
 434      * @serial
 435      */
 436     private int buttonSerializedDataVersion = 1;
 437 
 438     /**
 439      * Writes default serializable fields to stream.  Writes
 440      * a list of serializable <code>ActionListeners</code>
 441      * as optional data.  The non-serializable
 442      * <code>ActionListeners</code> are detected and
 443      * no attempt is made to serialize them.
 444      *
 445      * @serialData <code>null</code> terminated sequence of 0 or
 446      *   more pairs: the pair consists of a <code>String</code>
 447      *   and an <code>Object</code>; the <code>String</code>
 448      *   indicates the type of object and is one of the following:
 449      *   <code>actionListenerK</code> indicating an
 450      *     <code>ActionListener</code> object
 451      *
 452      * @param s the <code>ObjectOutputStream</code> to write
 453      * @see AWTEventMulticaster#save(ObjectOutputStream, String, EventListener)
 454      * @see java.awt.Component#actionListenerK
 455      * @see #readObject(ObjectInputStream)
 456      */
 457     private void writeObject(ObjectOutputStream s)
 458       throws IOException
 459     {
 460       s.defaultWriteObject();
 461 
 462       AWTEventMulticaster.save(s, actionListenerK, actionListener);
 463       s.writeObject(null);
 464     }
 465 
 466     /**
 467      * Reads the <code>ObjectInputStream</code> and if
 468      * it isn't <code>null</code> adds a listener to
 469      * receive action events fired by the button.
 470      * Unrecognized keys or values will be ignored.
 471      *
 472      * @param s the <code>ObjectInputStream</code> to read
 473      * @exception HeadlessException if
 474      *   <code>GraphicsEnvironment.isHeadless</code> returns
 475      *   <code>true</code>
 476      * @serial
 477      * @see #removeActionListener(ActionListener)
 478      * @see #addActionListener(ActionListener)
 479      * @see java.awt.GraphicsEnvironment#isHeadless
 480      * @see #writeObject(ObjectOutputStream)
 481      */
 482     private void readObject(ObjectInputStream s)
 483       throws ClassNotFoundException, IOException, HeadlessException
 484     {
 485       GraphicsEnvironment.checkHeadless();
 486       s.defaultReadObject();
 487 
 488       Object keyOrNull;
 489       while(null != (keyOrNull = s.readObject())) {
 490         String key = ((String)keyOrNull).intern();
 491 
 492         if (actionListenerK == key)
 493           addActionListener((ActionListener)(s.readObject()));
 494 
 495         else // skip value for unrecognized key
 496           s.readObject();
 497       }
 498     }
 499 
 500 
 501 /////////////////
 502 // Accessibility support
 503 ////////////////
 504 
 505     /**
 506      * Gets the <code>AccessibleContext</code> associated with
 507      * this <code>Button</code>. For buttons, the
 508      * <code>AccessibleContext</code> takes the form of an
 509      * <code>AccessibleAWTButton</code>.
 510      * A new <code>AccessibleAWTButton</code> instance is
 511      * created if necessary.
 512      *
 513      * @return an <code>AccessibleAWTButton</code> that serves as the
 514      *         <code>AccessibleContext</code> of this <code>Button</code>
 515      * @since 1.3
 516      */
 517     @BeanProperty(expert = true, description
 518             = "The AccessibleContext associated with this Button.")
 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 }