gt:                 updateText(); // Set the text with the latest value
context: /*
   * 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.FormatterAccessor;
  import javafx.beans.NamedArg;
  import javafx.beans.property.ObjectProperty;
  import javafx.beans.property.ObjectPropertyBase;
  import javafx.util.StringConverter;
  
  import java.util.function.Consumer;
  import java.util.function.UnaryOperator;
  
  /**
   * A Formatter describes a format of a {@code TextInputControl} text by using two distinct mechanisms:
   * <ul>
   *     <li>A filter ({@link #getFilter()}) that can intercept and modify user input. This helps to keep the text
   *     in the desired format. A default text supplier can be used to provide the intial text.</li>
   *     <li>A value converter ({@link #getValueConverter()}) and value ({@link #valueProperty()})
   *     can be used to provide special format that represents a value of type {@code V}.
   *     If the control is editable and the text is changed by the user, the value is then updated to correspond to the text.
   * </ul>
   * <p>
   * It's possible to have a formatter with just filter or value converter. If value converter is not provided however, setting a value will
   * result in an {@code IllegalStateException} and the value is always null.
   * <p>
   * Since {@code Formatter} contains a value which represents the state of the {@code TextInputControl} to which it is currently assigned, a single
   * {@code Formatter} instance can be used only in one {@code TextInputControl} at a time.
   *
   * @param <V> The type of the value
   * @since JavaFX 8u40
   */
  public class TextFormatter<V> {
      private final StringConverter<V> valueConverter;
      private final UnaryOperator<Change> filter;
  
      private Consumer<TextFormatter<?>> textUpdater;
  
      /**
       * This string converter converts the text to the same String value. This might be useful for cases where you
       * want to manipulate with the text through the value or you need to provide a default text value.
       */
      public static final StringConverter<String> IDENTITY_STRING_CONVERTER = new StringConverter<String>() {
          @Override
          public String toString(String object) {
              return object == null ? "" : object;
          }
          @Override
          public String fromString(String string) {
              return string;
          }
      };
  
  
      /**
       * Creates a new Formatter with the provided filter.
       * @param filter The filter to use in this formatter or null
       */
      public TextFormatter(@NamedArg("filter") UnaryOperator<Change> filter) {
          this(null, null, filter);
      }
  
      /**
       * Creates a new Formatter with the provided filter, value converter and default value.
       * @param valueConverter The value converter to use in this formatter or null.
       * @param defaultValue the default value.
       * @param filter The filter to use in this formatter or null
       */
      public TextFormatter(@NamedArg("valueConverter") StringConverter<V> valueConverter,
                           @NamedArg("defaultValue") V defaultValue, @NamedArg("filter") UnaryOperator<Change> filter) {
          this.filter = filter;
          this.valueConverter = valueConverter;
          setValue(defaultValue);
      }
  
      /**
       * Creates a new Formatter with the provided value converter and default value.
       * @param valueConverter The value converter to use in this formatter. This must not be null.
       * @param defaultValue the default value
       */
      public TextFormatter(@NamedArg("valueConverter") StringConverter<V> valueConverter, @NamedArg("defaultValue") V defaultValue) {
          this(valueConverter, defaultValue, null);
      }
  
      /**
       * Creates a new Formatter with the provided value converter. The default value will be null.
       * @param valueConverter The value converter to use in this formatter. This must not be null.
       */
      public TextFormatter(@NamedArg("valueConverter") StringConverter<V> valueConverter) {
          this(valueConverter, null, null);
      }
  
  
      /**
       * The converter between the values and text.
       * It maintains a "binding" between the {@link javafx.scene.control.TextInputControl#textProperty()} }
       * and {@link #valueProperty()} }. The value is updated when the control loses it's focus or it is commited (TextField only).
       * Setting the value will update the text of the control, usin the provided converter.
       *
       * If it's impossible to convert text to value, an exception should be thrown.
       * @return StringConverter for values or null if none provided
       * @see javafx.scene.control.TextField#commitValue()
       * @see javafx.scene.control.TextField#cancelEdit()
       */
      public final StringConverter<V> getValueConverter() {
          return valueConverter;
      }
  
      /**
       * Filter allows user to intercept and modify any change done to the text content.
       * <p>
       * The filter itself is an {@code UnaryOperator} that accepts {@link javafx.scene.control.TextFormatter.Change} object.
       * It should return a {@link javafx.scene.control.TextFormatter.Change} object that contains the actual (filtered)
       * change. Returning null rejects the change.
       * @return the filter for this formatter or null if there is none
       */
      public final UnaryOperator<Change> getFilter() {
          return filter;
      }
  
      /**
       * The current value for this formatter. When the formatter is set on a {@code TextInputControl} and has a
       * @{code valueConverter}, the value is set by the control, when the text is commited.
       */
      private final ObjectProperty<V> value = new ObjectPropertyBase<V>() {
  
          @Override
          public Object getBean() {
              return TextFormatter.this;
          }
  
          @Override
          public String getName() {
              return "value";
          }
  
          @Override
          protected void invalidated() {
              if (valueConverter == null && get() != null) {
                  if (isBound()) {
                      unbind();
                  }
                  throw new IllegalStateException("Value changes are not supported when valueConverter is not set");
              }
              updateText();
          }
      };
  
      public final ObjectProperty<V> valueProperty() {
          return value;
      }
      public final void setValue(V value) {
          if (valueConverter == null && value != null) {
              throw new IllegalStateException("Value changes are not supported when valueConverter is not set");
          }
          this.value.set(value);
      }
      public final V getValue() {
          return value.get();
      }
  
      private void updateText() {
          if (textUpdater != null) {
              textUpdater.accept(this);
          }
      }
  
      void bindToControl(Consumer<TextFormatter<?>> updater) {
          if (textUpdater != null) {
              throw new IllegalStateException("Formatter is already used in other control");
          }
          this.textUpdater = updater;
      }
  
      void unbindFromControl() {
          this.textUpdater = null;
      }
  
      void updateValue(String text) {
          if (!value.isBound()) {
              try {
                  V v = valueConverter.fromString(text);
                  setValue(v);
              } catch (Exception e) {
  