56 57 /** 58 * The SpinnerValueFactory is the model behind the JavaFX 59 * {@link Spinner Spinner control} - without a value factory installed a 60 * Spinner is unusable. It is the role of the value factory to handle almost all 61 * aspects of the Spinner, including: 62 * 63 * <ul> 64 * <li>Representing the current state of the {@link javafx.scene.control.SpinnerValueFactory#valueProperty() value},</li> 65 * <li>{@link SpinnerValueFactory#increment(int) Incrementing} 66 * and {@link SpinnerValueFactory#decrement(int) decrementing} the 67 * value, with one or more steps per call,</li> 68 * <li>{@link javafx.scene.control.SpinnerValueFactory#converterProperty() Converting} text input 69 * from the user (via the Spinner {@link Spinner#editorProperty() editor},</li> 70 * <li>Converting {@link javafx.scene.control.SpinnerValueFactory#converterProperty() objects to user-readable strings} 71 * for display on screen</li> 72 * </ul> 73 * 74 * <p>SpinnerValueFactory classes for some common types are provided with JavaFX, including: 75 * 76 * <br/> 77 * 78 * <ul> 79 * <li>{@link SpinnerValueFactory.IntegerSpinnerValueFactory}</li> 80 * <li>{@link SpinnerValueFactory.DoubleSpinnerValueFactory}</li> 81 * <li>{@link SpinnerValueFactory.ListSpinnerValueFactory}</li> 82 * </ul> 83 * 84 * @param <T> The type of the data this value factory deals with, which must 85 * coincide with the type of the Spinner that the value factory is set on. 86 * @see Spinner 87 * @see SpinnerValueFactory.IntegerSpinnerValueFactory 88 * @see SpinnerValueFactory.DoubleSpinnerValueFactory 89 * @see SpinnerValueFactory.ListSpinnerValueFactory 90 * @since JavaFX 8u40 91 */ 92 public abstract class SpinnerValueFactory<T> { 93 94 /*************************************************************************** 95 * * 96 * Private fields * 97 * * 280 newIndex = items.indexOf(newValue); 281 } 282 currentIndex = newIndex; 283 }); 284 setValue(_getValue(currentIndex)); 285 } 286 287 288 289 /*********************************************************************** 290 * * 291 * Properties * 292 * * 293 **********************************************************************/ 294 // --- Items 295 private ObjectProperty<ObservableList<T>> items; 296 297 /** 298 * Sets the underlying data model for the ListSpinnerValueFactory. Note that it has a generic 299 * type that must match the type of the Spinner itself. 300 */ 301 public final void setItems(ObservableList<T> value) { 302 itemsProperty().set(value); 303 } 304 305 /** 306 * Returns an {@link javafx.collections.ObservableList} that contains the items currently able 307 * to be iterated through by the user. This may be null if 308 * {@link #setItems(javafx.collections.ObservableList)} has previously been 309 * called, however, by default it is an empty ObservableList. 310 * 311 * @return An ObservableList containing the items to be shown to the user, or 312 * null if the items have previously been set to null. 313 */ 314 public final ObservableList<T> getItems() { 315 return items == null ? null : items.get(); 316 } 317 318 /** 319 * The underlying data model for the ListView. Note that it has a generic 320 * type that must match the type of the ListView itself. 321 */ 322 public final ObjectProperty<ObservableList<T>> itemsProperty() { 323 if (items == null) { 324 items = new SimpleObjectProperty<ObservableList<T>>(this, "items") { 325 WeakReference<ObservableList<T>> oldItemsRef; 326 327 @Override protected void invalidated() { 328 ObservableList<T> oldItems = oldItemsRef == null ? null : oldItemsRef.get(); 329 ObservableList<T> newItems = getItems(); 330 331 // update listeners 332 if (oldItems != null) { 333 oldItems.removeListener(weakItemsContentObserver); 334 } 335 if (newItems != null) { 336 newItems.addListener(weakItemsContentObserver); 337 } 338 339 // update the current value based on the index 340 updateCurrentIndex(); 492 int newMin = get(); 493 if (newMin > getMax()) { 494 setMin(getMax()); 495 return; 496 } 497 498 if (currentValue < newMin) { 499 IntegerSpinnerValueFactory.this.setValue(newMin); 500 } 501 } 502 }; 503 504 public final void setMin(int value) { 505 min.set(value); 506 } 507 public final int getMin() { 508 return min.get(); 509 } 510 /** 511 * Sets the minimum allowable value for this value factory 512 */ 513 public final IntegerProperty minProperty() { 514 return min; 515 } 516 517 // --- max 518 private IntegerProperty max = new SimpleIntegerProperty(this, "max") { 519 @Override protected void invalidated() { 520 Integer currentValue = IntegerSpinnerValueFactory.this.getValue(); 521 if (currentValue == null) { 522 return; 523 } 524 525 int newMax = get(); 526 if (newMax < getMin()) { 527 setMax(getMin()); 528 return; 529 } 530 531 if (currentValue > newMax) { 532 IntegerSpinnerValueFactory.this.setValue(newMax); 533 } 534 } 535 }; 536 537 public final void setMax(int value) { 538 max.set(value); 539 } 540 public final int getMax() { 541 return max.get(); 542 } 543 /** 544 * Sets the maximum allowable value for this value factory 545 */ 546 public final IntegerProperty maxProperty() { 547 return max; 548 } 549 550 // --- amountToStepBy 551 private IntegerProperty amountToStepBy = new SimpleIntegerProperty(this, "amountToStepBy"); 552 public final void setAmountToStepBy(int value) { 553 amountToStepBy.set(value); 554 } 555 public final int getAmountToStepBy() { 556 return amountToStepBy.get(); 557 } 558 /** 559 * Sets the amount to increment or decrement by, per step. 560 */ 561 public final IntegerProperty amountToStepByProperty() { 562 return amountToStepBy; 563 } 564 565 566 567 /*********************************************************************** 568 * * 569 * Overridden methods * 570 * * 571 **********************************************************************/ 572 573 /** {@inheritDoc} */ 574 @Override public void decrement(int steps) { 575 final int min = getMin(); 576 final int max = getMax(); 577 final int newIndex = getValue() - steps * getAmountToStepBy(); 578 setValue(newIndex >= min ? newIndex : (isWrapAround() ? Spinner.wrapValue(newIndex, min, max) + 1 : min)); 579 } 752 final double newMin = get(); 753 if (newMin > getMax()) { 754 setMin(getMax()); 755 return; 756 } 757 758 if (currentValue < newMin) { 759 DoubleSpinnerValueFactory.this.setValue(newMin); 760 } 761 } 762 }; 763 764 public final void setMin(double value) { 765 min.set(value); 766 } 767 public final double getMin() { 768 return min.get(); 769 } 770 /** 771 * Sets the minimum allowable value for this value factory 772 */ 773 public final DoubleProperty minProperty() { 774 return min; 775 } 776 777 // --- max 778 private DoubleProperty max = new SimpleDoubleProperty(this, "max") { 779 @Override protected void invalidated() { 780 Double currentValue = DoubleSpinnerValueFactory.this.getValue(); 781 if (currentValue == null) { 782 return; 783 } 784 785 final double newMax = get(); 786 if (newMax < getMin()) { 787 setMax(getMin()); 788 return; 789 } 790 791 if (currentValue > newMax) { 792 DoubleSpinnerValueFactory.this.setValue(newMax); 793 } 794 } 795 }; 796 797 public final void setMax(double value) { 798 max.set(value); 799 } 800 public final double getMax() { 801 return max.get(); 802 } 803 /** 804 * Sets the maximum allowable value for this value factory 805 */ 806 public final DoubleProperty maxProperty() { 807 return max; 808 } 809 810 // --- amountToStepBy 811 private DoubleProperty amountToStepBy = new SimpleDoubleProperty(this, "amountToStepBy"); 812 public final void setAmountToStepBy(double value) { 813 amountToStepBy.set(value); 814 } 815 public final double getAmountToStepBy() { 816 return amountToStepBy.get(); 817 } 818 /** 819 * Sets the amount to increment or decrement by, per step. 820 */ 821 public final DoubleProperty amountToStepByProperty() { 822 return amountToStepBy; 823 } 824 825 826 827 /** {@inheritDoc} */ 828 @Override public void decrement(int steps) { 829 final BigDecimal currentValue = BigDecimal.valueOf(getValue()); 830 final BigDecimal minBigDecimal = BigDecimal.valueOf(getMin()); 831 final BigDecimal maxBigDecimal = BigDecimal.valueOf(getMax()); 832 final BigDecimal amountToStepByBigDecimal = BigDecimal.valueOf(getAmountToStepBy()); 833 BigDecimal newValue = currentValue.subtract(amountToStepByBigDecimal.multiply(BigDecimal.valueOf(steps))); 834 setValue(newValue.compareTo(minBigDecimal) >= 0 ? newValue.doubleValue() : 835 (isWrapAround() ? Spinner.wrapValue(newValue, minBigDecimal, maxBigDecimal).doubleValue() : getMin())); 836 } 837 838 /** {@inheritDoc} */ 839 @Override public void increment(int steps) { | 56 57 /** 58 * The SpinnerValueFactory is the model behind the JavaFX 59 * {@link Spinner Spinner control} - without a value factory installed a 60 * Spinner is unusable. It is the role of the value factory to handle almost all 61 * aspects of the Spinner, including: 62 * 63 * <ul> 64 * <li>Representing the current state of the {@link javafx.scene.control.SpinnerValueFactory#valueProperty() value},</li> 65 * <li>{@link SpinnerValueFactory#increment(int) Incrementing} 66 * and {@link SpinnerValueFactory#decrement(int) decrementing} the 67 * value, with one or more steps per call,</li> 68 * <li>{@link javafx.scene.control.SpinnerValueFactory#converterProperty() Converting} text input 69 * from the user (via the Spinner {@link Spinner#editorProperty() editor},</li> 70 * <li>Converting {@link javafx.scene.control.SpinnerValueFactory#converterProperty() objects to user-readable strings} 71 * for display on screen</li> 72 * </ul> 73 * 74 * <p>SpinnerValueFactory classes for some common types are provided with JavaFX, including: 75 * 76 * <ul> 77 * <li>{@link SpinnerValueFactory.IntegerSpinnerValueFactory}</li> 78 * <li>{@link SpinnerValueFactory.DoubleSpinnerValueFactory}</li> 79 * <li>{@link SpinnerValueFactory.ListSpinnerValueFactory}</li> 80 * </ul> 81 * 82 * @param <T> The type of the data this value factory deals with, which must 83 * coincide with the type of the Spinner that the value factory is set on. 84 * @see Spinner 85 * @see SpinnerValueFactory.IntegerSpinnerValueFactory 86 * @see SpinnerValueFactory.DoubleSpinnerValueFactory 87 * @see SpinnerValueFactory.ListSpinnerValueFactory 88 * @since JavaFX 8u40 89 */ 90 public abstract class SpinnerValueFactory<T> { 91 92 /*************************************************************************** 93 * * 94 * Private fields * 95 * * 278 newIndex = items.indexOf(newValue); 279 } 280 currentIndex = newIndex; 281 }); 282 setValue(_getValue(currentIndex)); 283 } 284 285 286 287 /*********************************************************************** 288 * * 289 * Properties * 290 * * 291 **********************************************************************/ 292 // --- Items 293 private ObjectProperty<ObservableList<T>> items; 294 295 /** 296 * Sets the underlying data model for the ListSpinnerValueFactory. Note that it has a generic 297 * type that must match the type of the Spinner itself. 298 * @param value the list of items 299 */ 300 public final void setItems(ObservableList<T> value) { 301 itemsProperty().set(value); 302 } 303 304 /** 305 * Returns an {@link javafx.collections.ObservableList} that contains the items currently able 306 * to be iterated through by the user. This may be null if 307 * {@link #setItems(javafx.collections.ObservableList)} has previously been 308 * called, however, by default it is an empty ObservableList. 309 * 310 * @return An ObservableList containing the items to be shown to the user, or 311 * null if the items have previously been set to null. 312 */ 313 public final ObservableList<T> getItems() { 314 return items == null ? null : items.get(); 315 } 316 317 /** 318 * The underlying data model for the ListView. Note that it has a generic 319 * type that must match the type of the ListView itself. 320 * @return the list of items 321 */ 322 public final ObjectProperty<ObservableList<T>> itemsProperty() { 323 if (items == null) { 324 items = new SimpleObjectProperty<ObservableList<T>>(this, "items") { 325 WeakReference<ObservableList<T>> oldItemsRef; 326 327 @Override protected void invalidated() { 328 ObservableList<T> oldItems = oldItemsRef == null ? null : oldItemsRef.get(); 329 ObservableList<T> newItems = getItems(); 330 331 // update listeners 332 if (oldItems != null) { 333 oldItems.removeListener(weakItemsContentObserver); 334 } 335 if (newItems != null) { 336 newItems.addListener(weakItemsContentObserver); 337 } 338 339 // update the current value based on the index 340 updateCurrentIndex(); 492 int newMin = get(); 493 if (newMin > getMax()) { 494 setMin(getMax()); 495 return; 496 } 497 498 if (currentValue < newMin) { 499 IntegerSpinnerValueFactory.this.setValue(newMin); 500 } 501 } 502 }; 503 504 public final void setMin(int value) { 505 min.set(value); 506 } 507 public final int getMin() { 508 return min.get(); 509 } 510 /** 511 * Sets the minimum allowable value for this value factory 512 * @return the minimum allowable value for this value factory 513 */ 514 public final IntegerProperty minProperty() { 515 return min; 516 } 517 518 // --- max 519 private IntegerProperty max = new SimpleIntegerProperty(this, "max") { 520 @Override protected void invalidated() { 521 Integer currentValue = IntegerSpinnerValueFactory.this.getValue(); 522 if (currentValue == null) { 523 return; 524 } 525 526 int newMax = get(); 527 if (newMax < getMin()) { 528 setMax(getMin()); 529 return; 530 } 531 532 if (currentValue > newMax) { 533 IntegerSpinnerValueFactory.this.setValue(newMax); 534 } 535 } 536 }; 537 538 public final void setMax(int value) { 539 max.set(value); 540 } 541 public final int getMax() { 542 return max.get(); 543 } 544 /** 545 * Sets the maximum allowable value for this value factory 546 * @return the maximum allowable value for this value factory 547 */ 548 public final IntegerProperty maxProperty() { 549 return max; 550 } 551 552 // --- amountToStepBy 553 private IntegerProperty amountToStepBy = new SimpleIntegerProperty(this, "amountToStepBy"); 554 public final void setAmountToStepBy(int value) { 555 amountToStepBy.set(value); 556 } 557 public final int getAmountToStepBy() { 558 return amountToStepBy.get(); 559 } 560 /** 561 * Sets the amount to increment or decrement by, per step. 562 * @return the amount to increment or decrement by, per step 563 */ 564 public final IntegerProperty amountToStepByProperty() { 565 return amountToStepBy; 566 } 567 568 569 570 /*********************************************************************** 571 * * 572 * Overridden methods * 573 * * 574 **********************************************************************/ 575 576 /** {@inheritDoc} */ 577 @Override public void decrement(int steps) { 578 final int min = getMin(); 579 final int max = getMax(); 580 final int newIndex = getValue() - steps * getAmountToStepBy(); 581 setValue(newIndex >= min ? newIndex : (isWrapAround() ? Spinner.wrapValue(newIndex, min, max) + 1 : min)); 582 } 755 final double newMin = get(); 756 if (newMin > getMax()) { 757 setMin(getMax()); 758 return; 759 } 760 761 if (currentValue < newMin) { 762 DoubleSpinnerValueFactory.this.setValue(newMin); 763 } 764 } 765 }; 766 767 public final void setMin(double value) { 768 min.set(value); 769 } 770 public final double getMin() { 771 return min.get(); 772 } 773 /** 774 * Sets the minimum allowable value for this value factory 775 * @return the minimum allowable value for this value factory 776 */ 777 public final DoubleProperty minProperty() { 778 return min; 779 } 780 781 // --- max 782 private DoubleProperty max = new SimpleDoubleProperty(this, "max") { 783 @Override protected void invalidated() { 784 Double currentValue = DoubleSpinnerValueFactory.this.getValue(); 785 if (currentValue == null) { 786 return; 787 } 788 789 final double newMax = get(); 790 if (newMax < getMin()) { 791 setMax(getMin()); 792 return; 793 } 794 795 if (currentValue > newMax) { 796 DoubleSpinnerValueFactory.this.setValue(newMax); 797 } 798 } 799 }; 800 801 public final void setMax(double value) { 802 max.set(value); 803 } 804 public final double getMax() { 805 return max.get(); 806 } 807 /** 808 * Sets the maximum allowable value for this value factory 809 * @return the maximum allowable value for this value factory 810 */ 811 public final DoubleProperty maxProperty() { 812 return max; 813 } 814 815 // --- amountToStepBy 816 private DoubleProperty amountToStepBy = new SimpleDoubleProperty(this, "amountToStepBy"); 817 public final void setAmountToStepBy(double value) { 818 amountToStepBy.set(value); 819 } 820 public final double getAmountToStepBy() { 821 return amountToStepBy.get(); 822 } 823 /** 824 * Sets the amount to increment or decrement by, per step. 825 * @return the amount to increment or decrement by, per step 826 */ 827 public final DoubleProperty amountToStepByProperty() { 828 return amountToStepBy; 829 } 830 831 832 833 /** {@inheritDoc} */ 834 @Override public void decrement(int steps) { 835 final BigDecimal currentValue = BigDecimal.valueOf(getValue()); 836 final BigDecimal minBigDecimal = BigDecimal.valueOf(getMin()); 837 final BigDecimal maxBigDecimal = BigDecimal.valueOf(getMax()); 838 final BigDecimal amountToStepByBigDecimal = BigDecimal.valueOf(getAmountToStepBy()); 839 BigDecimal newValue = currentValue.subtract(amountToStepByBigDecimal.multiply(BigDecimal.valueOf(steps))); 840 setValue(newValue.compareTo(minBigDecimal) >= 0 ? newValue.doubleValue() : 841 (isWrapAround() ? Spinner.wrapValue(newValue, minBigDecimal, maxBigDecimal).doubleValue() : getMin())); 842 } 843 844 /** {@inheritDoc} */ 845 @Override public void increment(int steps) { |