1 /*
   2  * Copyright (c) 2010, 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 javafx.scene.control;
  27 
  28 import javafx.css.PseudoClass;
  29 import javafx.beans.property.ObjectProperty;
  30 import javafx.beans.property.ObjectPropertyBase;
  31 import javafx.event.ActionEvent;
  32 import javafx.event.EventHandler;
  33 import javafx.scene.AccessibleAction;
  34 import javafx.scene.Node;
  35 import javafx.beans.property.ReadOnlyBooleanProperty;
  36 import javafx.beans.property.ReadOnlyBooleanWrapper;
  37 
  38 /**
  39  * Base class for button-like UI Controls, including Hyperlinks, Buttons,
  40  * ToggleButtons, CheckBoxes, and RadioButtons. The primary contribution of
  41  * ButtonBase is providing a consistent API for handling the concept of button
  42  * "arming". In UIs, a button will typically only "fire" if some user gesture
  43  * occurs while the button is "armed". For example, a Button may be armed if
  44  * the mouse is pressed and the Button is enabled and the mouse is over the
  45  * button. In such a situation, if the mouse is then released, then the Button
  46  * is "fired", meaning its action takes place.
  47  * @since JavaFX 2.0
  48  */
  49 
  50 public abstract class ButtonBase extends Labeled {
  51 
  52     /***************************************************************************
  53      *                                                                         *
  54      * Constructors                                                            *
  55      *                                                                         *
  56      **************************************************************************/
  57 
  58     /**
  59      * Create a default ButtonBase with empty text.
  60      */
  61     public ButtonBase() { }
  62 
  63     /**
  64      * Create a ButtonBase with the given text.
  65      * @param text null text is treated as the empty string
  66      */
  67     public ButtonBase(String text) {
  68         super(text);
  69     }
  70 
  71     /**
  72      * Create a ButtonBase with the given text and graphic.
  73      * @param text null text is treated as the empty string
  74      * @param graphic a null graphic is acceptable
  75      */
  76     public ButtonBase(String text, Node graphic) {
  77         super(text, graphic);
  78     }
  79 
  80 
  81     /***************************************************************************
  82      *                                                                         *
  83      * Properties                                                              *
  84      *                                                                         *
  85      **************************************************************************/
  86 
  87     /**
  88      * Indicates that the button has been "armed" such that a mouse release
  89      * will cause the button's action to be invoked. This is subtly different
  90      * from pressed. Pressed indicates that the mouse has been
  91      * pressed on a Node and has not yet been released. {@code arm} however
  92      * also takes into account whether the mouse is actually over the
  93      * button and pressed.
  94      */
  95     public final ReadOnlyBooleanProperty armedProperty() { return armed.getReadOnlyProperty(); }
  96     private void setArmed(boolean value) { armed.set(value); }
  97     public final boolean isArmed() { return armedProperty().get(); }
  98     private ReadOnlyBooleanWrapper armed = new ReadOnlyBooleanWrapper() {
  99         @Override protected void invalidated() {
 100             pseudoClassStateChanged(ARMED_PSEUDOCLASS_STATE, get());
 101         }
 102 
 103         @Override
 104         public Object getBean() {
 105             return ButtonBase.this;
 106         }
 107 
 108         @Override
 109         public String getName() {
 110             return "armed";
 111         }
 112     };
 113 
 114     /**
 115      * The button's action, which is invoked whenever the button is fired. This
 116      * may be due to the user clicking on the button with the mouse, or by
 117      * a touch event, or by a key press, or if the developer programmatically
 118      * invokes the {@link #fire()} method.
 119      */
 120     public final ObjectProperty<EventHandler<ActionEvent>> onActionProperty() { return onAction; }
 121     public final void setOnAction(EventHandler<ActionEvent> value) { onActionProperty().set(value); }
 122     public final EventHandler<ActionEvent> getOnAction() { return onActionProperty().get(); }
 123     private ObjectProperty<EventHandler<ActionEvent>> onAction = new ObjectPropertyBase<EventHandler<ActionEvent>>() {
 124         @Override protected void invalidated() {
 125             setEventHandler(ActionEvent.ACTION, get());
 126         }
 127 
 128         @Override
 129         public Object getBean() {
 130             return ButtonBase.this;
 131         }
 132 
 133         @Override
 134         public String getName() {
 135             return "onAction";
 136         }
 137     };
 138 
 139 
 140     /***************************************************************************
 141      *                                                                         *
 142      * Methods                                                                 *
 143      *                                                                         *
 144      **************************************************************************/
 145 
 146     /**
 147      * Arms the button. An armed button will fire an action (whether that be
 148      * the action of a {@link Button} or toggling selection on a
 149      * {@link CheckBox} or some other behavior) on the next expected UI
 150      * gesture.
 151      *
 152      * @expert This function is intended to be used by experts, primarily
 153      *         by those implementing new Skins or Behaviors. It is not common
 154      *         for developers or designers to access this function directly.
 155      */
 156     public void arm() {
 157         setArmed(true);
 158     }
 159 
 160     /**
 161      * Disarms the button. See {@link #arm()}.
 162      *
 163      * @expert This function is intended to be used by experts, primarily
 164      *         by those implementing new Skins or Behaviors. It is not common
 165      *         for developers or designers to access this function directly.
 166      */
 167     public void disarm() {
 168         setArmed(false);
 169     }
 170 
 171     /**
 172      * Invoked when a user gesture indicates that an event for this
 173      * {@code ButtonBase} should occur.
 174      * <p>
 175      * If invoked, this method will be executed regardless of the status of
 176      * {@link #arm}.
 177      * </p>
 178      */
 179     public abstract void fire();
 180 
 181 
 182     /***************************************************************************
 183      *                                                                         *
 184      * Stylesheet Handling                                                     *
 185      *                                                                         *
 186      **************************************************************************/
 187 
 188     private static final PseudoClass ARMED_PSEUDOCLASS_STATE = PseudoClass.getPseudoClass("armed");
 189 
 190 
 191     /***************************************************************************
 192      *                                                                         *
 193      * Accessibility handling                                                  *
 194      *                                                                         *
 195      **************************************************************************/
 196 
 197     @Override
 198     public void executeAccessibleAction(AccessibleAction action, Object... parameters) {
 199         switch (action) {
 200             case FIRE:
 201                 fire();
 202                 break;
 203             default: super.executeAccessibleAction(action);
 204         }
 205     }
 206 }