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 
  30 import com.sun.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      */
  94     public ProgressIndicator(double progress) {
  95         // focusTraversable is styleable through css. Calling setFocusTraversable
  96         // makes it look to css like the user set the value and css will not 
  97         // override. Initializing focusTraversable by calling applyStyle with null
  98         // StyleOrigin ensures that css will be able to override the value.
  99         ((StyleableProperty<Boolean>)(WritableValue<Boolean>)focusTraversableProperty()).applyStyle(null, Boolean.FALSE);
 100         setProgress(progress);
 101         getStyleClass().setAll(DEFAULT_STYLE_CLASS);
 102         setAccessibleRole(AccessibleRole.PROGRESS_INDICATOR);
 103         
 104         // need to initialize pseudo-class state
 105         final int c = Double.compare(INDETERMINATE_PROGRESS, progress);
 106         pseudoClassStateChanged(PSEUDO_CLASS_INDETERMINATE, c == 0);
 107         pseudoClassStateChanged(PSEUDO_CLASS_DETERMINATE,   c != 0);
 108     }
 109     /***************************************************************************
 110      *                                                                         *
 111      * Properties                                                              *
 112      *                                                                         *
 113      **************************************************************************/
 114     /**
 115      * A flag indicating whether it is possible to determine the progress
 116      * of the ProgressIndicator. Typically indeterminate progress bars are
 117      * rendered with some form of animation indicating potentially "infinite"
 118      * progress.
 119      */
 120     private ReadOnlyBooleanWrapper indeterminate;
 121     private void setIndeterminate(boolean value) {
 122         indeterminatePropertyImpl().set(value);
 123     }
 124 
 125     public final boolean isIndeterminate() {
 126         return indeterminate == null ? true : indeterminate.get();
 127     }
 128 
 129     public final ReadOnlyBooleanProperty indeterminateProperty() {
 130         return indeterminatePropertyImpl().getReadOnlyProperty();
 131     }
 132 
 133     private ReadOnlyBooleanWrapper indeterminatePropertyImpl() {
 134         if (indeterminate == null) {
 135             indeterminate = new ReadOnlyBooleanWrapper(true) {
 136                 @Override protected void invalidated() {
 137                     final boolean active = get();
 138                     pseudoClassStateChanged(PSEUDO_CLASS_INDETERMINATE, active);
 139                     pseudoClassStateChanged(PSEUDO_CLASS_DETERMINATE,  !active);
 140                 }
 141 
 142                 @Override
 143                 public Object getBean() {
 144                     return ProgressIndicator.this;
 145                 }
 146 
 147                 @Override
 148                 public String getName() {
 149                     return "indeterminate";
 150                 }
 151             };
 152         }
 153         return indeterminate;
 154     }
 155     /**
 156      * The actual progress of the ProgressIndicator. A negative value for
 157      * progress indicates that the progress is indeterminate. A positive value
 158      * between 0 and 1 indicates the percentage of progress where 0 is 0% and 1
 159      * is 100%. Any value greater than 1 is interpreted as 100%.
 160      */
 161     private DoubleProperty progress;
 162     public final void setProgress(double value) {
 163         progressProperty().set(value);
 164     }
 165 
 166     public final double getProgress() {
 167         return progress == null ? INDETERMINATE_PROGRESS : progress.get();
 168     }
 169 
 170     public final DoubleProperty progressProperty() {
 171         if (progress == null) {
 172             progress = new DoublePropertyBase(-1.0) {
 173                 @Override protected void invalidated() {
 174                     setIndeterminate(getProgress() < 0.0);
 175                 }
 176 
 177                 @Override
 178                 public Object getBean() {
 179                     return ProgressIndicator.this;
 180                 }
 181 
 182                 @Override
 183                 public String getName() {
 184                     return "progress";
 185                 }
 186             };
 187         }
 188         return progress;
 189     }
 190 
 191     /***************************************************************************
 192      *                                                                         *
 193      * Methods                                                                 *
 194      *                                                                         *
 195      **************************************************************************/
 196 
 197     /** {@inheritDoc} */
 198     @Override protected Skin<?> createDefaultSkin() {
 199         return new ProgressIndicatorSkin(this);
 200     }
 201 
 202     /***************************************************************************
 203      *                                                                         *
 204      * Stylesheet Handling                                                     *
 205      *                                                                         *
 206      **************************************************************************/
 207 
 208     /**
 209      * Initialize the style class to 'progress-indicator'.
 210      *
 211      * This is the selector class from which CSS can be used to style
 212      * this control.
 213      */
 214     private static final String DEFAULT_STYLE_CLASS = "progress-indicator";
 215 
 216     /**
 217      * Pseudoclass indicating this is a determinate (i.e., progress can be
 218      * determined) progress indicator.
 219      */
 220     private static final PseudoClass PSEUDO_CLASS_DETERMINATE =
 221             PseudoClass.getPseudoClass("determinate");
 222 
 223     /**
 224      * Pseudoclass indicating this is an indeterminate (i.e., progress cannot
 225      * be determined) progress indicator.
 226      */
 227     private static final PseudoClass PSEUDO_CLASS_INDETERMINATE =
 228             PseudoClass.getPseudoClass("indeterminate");
 229     
 230     /**
 231       * Most Controls return true for focusTraversable, so Control overrides
 232       * this method to return true, but ProgressIndicator returns false for
 233       * focusTraversable's initial value; hence the override of the override. 
 234       * This method is called from CSS code to get the correct initial value.
 235       * @treatAsPrivate implementation detail
 236       */
 237     @Deprecated @Override
 238     protected /*do not make final*/ Boolean impl_cssGetFocusTraversableInitialValue() {
 239         return Boolean.FALSE;
 240     }
 241 
 242 
 243     /***************************************************************************
 244      *                                                                         *
 245      * Accessibility handling                                                  *
 246      *                                                                         *
 247      **************************************************************************/
 248 
 249     @Override
 250     public Object queryAccessibleAttribute(AccessibleAttribute attribute, Object... parameters) {
 251         switch (attribute) {
 252             case VALUE: return getProgress();
 253             case MAX_VALUE: return 1.0;
 254             case MIN_VALUE: return 0.0;
 255             case INDETERMINATE: return isIndeterminate();
 256             default: return super.queryAccessibleAttribute(attribute, parameters);
 257         }
 258     }
 259 
 260 }