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