/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javafx.scene.control;
import com.sun.javafx.scene.control.FakeFocusTextField;
import javafx.scene.control.skin.ComboBoxListViewSkin;
import javafx.scene.control.skin.SpinnerSkin;
import javafx.beans.NamedArg;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.MapChangeListener;
import javafx.collections.ObservableList;
import javafx.scene.AccessibleAction;
import javafx.scene.AccessibleAttribute;
import javafx.scene.AccessibleRole;
import javafx.util.StringConverter;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.temporal.TemporalUnit;
/**
* A single line text field that lets the user select a number or an object
* value from an ordered sequence. Spinners typically provide a pair of tiny
* arrow buttons for stepping through the elements of the sequence. The keyboard
* up/down arrow keys also cycle through the elements. The user may also be
* allowed to type a (legal) value directly into the spinner. Although combo
* boxes provide similar functionality, spinners are sometimes preferred because
* they don't require a drop down list that can obscure important data, and also
* because they allow for features such as
* {@link SpinnerValueFactory#wrapAroundProperty() wrapping}
* and simpler specification of 'infinite' data models (the
* {@link SpinnerValueFactory SpinnerValueFactory}, rather than using a
* {@link javafx.collections.ObservableList ObservableList} data model like many
* other JavaFX UI controls.
*
*
A Spinner's sequence value is defined by its
* {@link SpinnerValueFactory SpinnerValueFactory}. The value factory
* can be specified as a constructor argument and changed with the
* {@link #valueFactoryProperty() value factory property}. SpinnerValueFactory
* classes for some common types are provided with JavaFX, including:
*
*
*
*
A Spinner has a TextField child component that is responsible for displaying
* and potentially changing the current {@link #valueProperty() value} of the
* Spinner, which is called the {@link #editorProperty() editor}. By default the
* Spinner is non-editable, but input can be accepted if the
* {@link #editableProperty() editable property} is set to true. The Spinner
* editor stays in sync with the value factory by listening for changes to the
* {@link SpinnerValueFactory#valueProperty() value property} of the value factory.
* If the user has changed the value displayed in the editor it is possible for
* the Spinner {@link #valueProperty() value} to differ from that of the editor.
* To make sure the model has the same value as the editor, the user must commit
* the edit using the Enter key.
*
* @see SpinnerValueFactory
* @param The type of all values that can be iterated through in the Spinner.
* Common types include Integer and String.
* @since JavaFX 8u40
*/
public class Spinner extends Control {
// default style class, puts arrows on right, stacked vertically
private static final String DEFAULT_STYLE_CLASS = "spinner";
/** The arrows are placed on the right of the Spinner, pointing horizontally (i.e. left and right). */
public static final String STYLE_CLASS_ARROWS_ON_RIGHT_HORIZONTAL = "arrows-on-right-horizontal";
/** The arrows are placed on the left of the Spinner, pointing vertically (i.e. up and down). */
public static final String STYLE_CLASS_ARROWS_ON_LEFT_VERTICAL = "arrows-on-left-vertical";
/** The arrows are placed on the left of the Spinner, pointing horizontally (i.e. left and right). */
public static final String STYLE_CLASS_ARROWS_ON_LEFT_HORIZONTAL = "arrows-on-left-horizontal";
/** The arrows are placed above and beneath the spinner, stretching to take the entire width. */
public static final String STYLE_CLASS_SPLIT_ARROWS_VERTICAL = "split-arrows-vertical";
/** The decrement arrow is placed on the left of the Spinner, and the increment on the right. */
public static final String STYLE_CLASS_SPLIT_ARROWS_HORIZONTAL = "split-arrows-horizontal";
/***************************************************************************
* *
* Constructors *
* *
**************************************************************************/
/**
* Constructs a default Spinner instance, with the default 'spinner' style
* class and a non-editable editor.
*/
public Spinner() {
getStyleClass().add(DEFAULT_STYLE_CLASS);
setAccessibleRole(AccessibleRole.SPINNER);
getEditor().setOnAction(action -> {
String text = getEditor().getText();
SpinnerValueFactory valueFactory = getValueFactory();
if (valueFactory != null) {
StringConverter converter = valueFactory.getConverter();
if (converter != null) {
T value = converter.fromString(text);
valueFactory.setValue(value);
}
}
});
getEditor().editableProperty().bind(editableProperty());
value.addListener((o, oldValue, newValue) -> setText(newValue));
// Fix for RT-29885
getProperties().addListener((MapChangeListener