1 /*
   2  * Copyright (c) 2010, 2016, 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 
  30 import javafx.scene.control.skin.ProgressIndicatorSkin;
  31 
  32 import javafx.beans.property.DoubleProperty;
  33 import javafx.beans.property.DoublePropertyBase;
  34 import javafx.beans.property.ReadOnlyBooleanProperty;
  35 import javafx.beans.property.ReadOnlyBooleanWrapper;
  36 import javafx.beans.value.WritableValue;
  37 import javafx.css.StyleableProperty;
  38 import javafx.scene.AccessibleAttribute;
  39 import javafx.scene.AccessibleRole;
  40 
  41 
  42 /**
  43  * A circular control which is used for indicating progress, either
  44  * infinite (aka indeterminate) or finite. Often used with the Task API for
  45  * representing progress of background Tasks.
  46  * <p>
  47  * ProgressIndicator sets focusTraversable to false.
  48  * </p>
  49  *
  50  * <p>
  51  * This first example creates a ProgressIndicator with an indeterminate value :
  52  * <pre><code>
  53  * import javafx.scene.control.ProgressIndicator;
  54  * ProgressIndicator p1 = new ProgressIndicator();
  55  * </code></pre>
  56  *
  57  * <p>
  58  * This next example creates a ProgressIndicator which is 25% complete :
  59  * <pre><code>
  60  * import javafx.scene.control.ProgressIndicator;
  61  * ProgressIndicator p2 = new ProgressIndicator();
  62  * p2.setProgress(0.25F);
  63  * </code></pre>
  64  *
  65  * Implementation of ProgressIndicator According to JavaFX UI Control API Specification
  66  * @since JavaFX 2.0
  67  */
  68 
  69 public class ProgressIndicator extends Control {
  70 
  71     /**
  72      * Value for progress indicating that the progress is indeterminate.
  73      *
  74      * @see #setProgress
  75      */
  76     public static final double INDETERMINATE_PROGRESS = -1;
  77 
  78     /***************************************************************************
  79      *                                                                         *
  80      * Constructors                                                            *
  81      *                                                                         *
  82      **************************************************************************/
  83 
  84     /**
  85      * Creates a new indeterminate ProgressIndicator.
  86      */
  87     public ProgressIndicator() {
  88         this(INDETERMINATE_PROGRESS);
  89     }
  90 
  91     /**
  92      * Creates a new ProgressIndicator with the given progress value.
  93      * @param progress the progress
  94      */
  95     public ProgressIndicator(double progress) {
  96         // focusTraversable is styleable through css. Calling setFocusTraversable
  97         // makes it look to css like the user set the value and css will not
  98         // override. Initializing focusTraversable by calling applyStyle with null
  99         // StyleOrigin ensures that css will be able to override the value.
 100         ((StyleableProperty<Boolean>)(WritableValue<Boolean>)focusTraversableProperty()).applyStyle(null, Boolean.FALSE);
 101         setProgress(progress);
 102         getStyleClass().setAll(DEFAULT_STYLE_CLASS);
 103         setAccessibleRole(AccessibleRole.PROGRESS_INDICATOR);
 104 
 105         // need to initialize pseudo-class state
 106         final int c = Double.compare(INDETERMINATE_PROGRESS, progress);
 107         pseudoClassStateChanged(PSEUDO_CLASS_INDETERMINATE, c == 0);
 108         pseudoClassStateChanged(PSEUDO_CLASS_DETERMINATE,   c != 0);
 109     }
 110     /***************************************************************************
 111      *                                                                         *
 112      * Properties                                                              *
 113      *                                                                         *
 114      **************************************************************************/
 115     /**
 116      * A flag indicating whether it is possible to determine the progress
 117      * of the ProgressIndicator. Typically indeterminate progress bars are
 118      * rendered with some form of animation indicating potentially "infinite"
 119      * progress.
 120      */
 121     private ReadOnlyBooleanWrapper indeterminate;
 122     private void setIndeterminate(boolean value) {
 123         indeterminatePropertyImpl().set(value);
 124     }
 125 
 126     public final boolean isIndeterminate() {
 127         return indeterminate == null ? true : indeterminate.get();
 128     }
 129 
 130     public final ReadOnlyBooleanProperty indeterminateProperty() {
 131         return indeterminatePropertyImpl().getReadOnlyProperty();
 132     }
 133 
 134     private ReadOnlyBooleanWrapper indeterminatePropertyImpl() {
 135         if (indeterminate == null) {
 136             indeterminate = new ReadOnlyBooleanWrapper(true) {
 137                 @Override protected void invalidated() {
 138                     final boolean active = get();
 139                     pseudoClassStateChanged(PSEUDO_CLASS_INDETERMINATE, active);
 140                     pseudoClassStateChanged(PSEUDO_CLASS_DETERMINATE,  !active);
 141                 }
 142 
 143                 @Override
 144                 public Object getBean() {
 145                     return ProgressIndicator.this;
 146                 }
 147 
 148                 @Override
 149                 public String getName() {
 150                     return "indeterminate";
 151                 }
 152             };
 153         }
 154         return indeterminate;
 155     }
 156     /**
 157      * The actual progress of the ProgressIndicator. A negative value for
 158      * progress indicates that the progress is indeterminate. A positive value
 159      * between 0 and 1 indicates the percentage of progress where 0 is 0% and 1
 160      * is 100%. Any value greater than 1 is interpreted as 100%.
 161      */
 162     private DoubleProperty progress;
 163     public final void setProgress(double value) {
 164         progressProperty().set(value);
 165     }
 166 
 167     public final double getProgress() {
 168         return progress == null ? INDETERMINATE_PROGRESS : progress.get();
 169     }
 170 
 171     public final DoubleProperty progressProperty() {
 172         if (progress == null) {
 173             progress = new DoublePropertyBase(-1.0) {
 174                 @Override protected void invalidated() {
 175                     setIndeterminate(getProgress() < 0.0);
 176                 }
 177 
 178                 @Override
 179                 public Object getBean() {
 180                     return ProgressIndicator.this;
 181                 }
 182 
 183                 @Override
 184                 public String getName() {
 185                     return "progress";
 186                 }
 187             };
 188         }
 189         return progress;
 190     }
 191 
 192     /***************************************************************************
 193      *                                                                         *
 194      * Methods                                                                 *
 195      *                                                                         *
 196      **************************************************************************/
 197 
 198     /** {@inheritDoc} */
 199     @Override protected Skin<?> createDefaultSkin() {
 200         return new ProgressIndicatorSkin(this);
 201     }
 202 
 203     /***************************************************************************
 204      *                                                                         *
 205      * Stylesheet Handling                                                     *
 206      *                                                                         *
 207      **************************************************************************/
 208 
 209     /**
 210      * Initialize the style class to 'progress-indicator'.
 211      *
 212      * This is the selector class from which CSS can be used to style
 213      * this control.
 214      */
 215     private static final String DEFAULT_STYLE_CLASS = "progress-indicator";
 216 
 217     /**
 218      * Pseudoclass indicating this is a determinate (i.e., progress can be
 219      * determined) progress indicator.
 220      */
 221     private static final PseudoClass PSEUDO_CLASS_DETERMINATE =
 222             PseudoClass.getPseudoClass("determinate");
 223 
 224     /**
 225      * Pseudoclass indicating this is an indeterminate (i.e., progress cannot
 226      * be determined) progress indicator.
 227      */
 228     private static final PseudoClass PSEUDO_CLASS_INDETERMINATE =
 229             PseudoClass.getPseudoClass("indeterminate");
 230 
 231     /**
 232      * Returns the initial focus traversable state of this control, for use
 233      * by the JavaFX CSS engine to correctly set its initial value. This method
 234      * is overridden as by default UI controls have focus traversable set to true,
 235      * but that is not appropriate for this control.
 236      *
 237      * @since 9
 238      */
 239     @Override protected Boolean getInitialFocusTraversable() {
 240         return Boolean.FALSE;
 241     }
 242 
 243 
 244     /***************************************************************************
 245      *                                                                         *
 246      * Accessibility handling                                                  *
 247      *                                                                         *
 248      **************************************************************************/
 249 
 250     @Override
 251     public Object queryAccessibleAttribute(AccessibleAttribute attribute, Object... parameters) {
 252         switch (attribute) {
 253             case VALUE: return getProgress();
 254             case MAX_VALUE: return 1.0;
 255             case MIN_VALUE: return 0.0;
 256             case INDETERMINATE: return isIndeterminate();
 257             default: return super.queryAccessibleAttribute(attribute, parameters);
 258         }
 259     }
 260 
 261 }