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.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.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     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      * @beaninfo
 516      *       expert: true
 517      *  description: The AccessibleContext associated with this Button.
 518      * @since 1.3
 519      */
 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 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 }