< prev index next >

modules/javafx.controls/src/main/java/javafx/scene/control/Cell.java

Print this page
rev 10463 : 8089514: [TableView, TreeView, ListView, TreeTableView] Clicking outside of the edited cell, node, or entry should commit the value


  25 
  26 package javafx.scene.control;
  27 
  28 import javafx.beans.InvalidationListener;
  29 import javafx.beans.Observable;
  30 import javafx.beans.property.BooleanProperty;
  31 import javafx.beans.property.ObjectProperty;
  32 import javafx.beans.property.SimpleBooleanProperty;
  33 import javafx.beans.property.SimpleObjectProperty;
  34 import javafx.collections.ObservableList;
  35 import javafx.scene.Node;
  36 import javafx.scene.layout.GridPane;
  37 import javafx.scene.layout.HBox;
  38 import javafx.scene.shape.Rectangle;
  39 import javafx.css.PseudoClass;
  40 import javafx.beans.property.ReadOnlyBooleanProperty;
  41 import javafx.beans.property.ReadOnlyBooleanWrapper;
  42 import javafx.beans.value.WritableValue;
  43 import javafx.css.StyleableProperty;
  44 


  45 /**
  46  * The Cell API is used for virtualized controls such as {@link ListView},
  47  * {@link TreeView}, and {@link TableView}.
  48  * A Cell is a {@link Labeled} {@link Control}, and is used to render a single
  49  * "row" inside  a ListView, TreeView or TableView. Cells are also used for each
  50  * individual 'cell' inside a TableView (i.e. each row/column intersection). See
  51  * the JavaDoc for each control separately for more detail.
  52  * <p>
  53  * Every Cell is associated with a single data item (represented by the
  54  * {@link #itemProperty() item} property). The Cell is responsible for
  55  * rendering that item and, where appropriate, for editing the item. An item
  56  * within a Cell may be represented by text or some other control such as a
  57  * {@link CheckBox}, {@link ChoiceBox} or any other {@link Node} such as a
  58  * {@link HBox}, {@link GridPane}, or even a {@link Rectangle}.
  59  * <p>
  60  * Because TreeView, ListView, TableView and other such controls can potentially
  61  * be used for displaying incredibly large amounts of data, it is not feasible
  62  * to create an actual Cell for every single item in the control.
  63  * We represent extremely large data sets using only very few Cells. Each Cell
  64  * is "recycled", or reused. This is what we mean when we say that these controls


 342      *                                                                         *
 343      **************************************************************************/
 344 
 345     /**
 346      * Creates a default Cell with the default style class of 'cell'.
 347      */
 348     public Cell() {
 349         setText(null); // default to null text, to match the null item
 350         // focusTraversable is styleable through css. Calling setFocusTraversable
 351         // makes it look to css like the user set the value and css will not
 352         // override. Initializing focusTraversable by calling set on the
 353         // CssMetaData ensures that css will be able to override the value.
 354         ((StyleableProperty<Boolean>)(WritableValue<Boolean>)focusTraversableProperty()).applyStyle(null, Boolean.FALSE);
 355         getStyleClass().addAll(DEFAULT_STYLE_CLASS);
 356 
 357         /**
 358          * Indicates whether or not this cell has focus. For example, a
 359          * ListView defines zero or one cell as being the "focused" cell. This cell
 360          * would have focused set to true.
 361          */
 362         super.focusedProperty().addListener(new InvalidationListener() {
 363             @Override public void invalidated(Observable property) {
 364                 pseudoClassStateChanged(PSEUDO_CLASS_FOCUSED, isFocused()); // TODO is this necessary??
 365 
 366                 // The user has shifted focus, so we should cancel the editing on this cell
 367                 if (!isFocused() && isEditing()) {
 368                     cancelEdit();
 369                 }
 370             }
 371         });
 372 
 373         // initialize default pseudo-class state
 374         pseudoClassStateChanged(PSEUDO_CLASS_EMPTY, true);
 375     }
 376 
 377 
 378 
 379     /***************************************************************************
 380      *                                                                         *
 381      * Properties                                                              *
 382      *                                                                         *
 383      **************************************************************************/
 384 
 385     // --- item
 386     private ObjectProperty<T> item = new SimpleObjectProperty<T>(this, "item");
 387 
 388     /**
 389      * The data value associated with this Cell. This value is set by the


 613      * implementations - it should be sufficient to simply call this method
 614      * when appropriate (e.g. when the user pressed the Enter key, you may do something
 615      * like {@code cell.commitEdit(converter.fromString(textField.getText()));}</p>
 616      *
 617      * @param newValue The value as input by the end user, which should be
 618      *      persisted in the relevant way given the data source underpinning the
 619      *      user interface and the install edit commit handler of the UI control.
 620      */
 621     public void commitEdit(T newValue) {
 622         if (isEditing()) {
 623             setEditing(false);
 624         }
 625     }
 626 
 627     /** {@inheritDoc} */
 628     @Override protected void layoutChildren() {
 629         if (itemDirty) {
 630             updateItem(getItem(), isEmpty());
 631             itemDirty = false;
 632         }

 633         super.layoutChildren();
 634     }
 635 
 636 
 637 
 638     /***************************************************************************
 639      *                                                                         *
 640      * Expert API                                                              *
 641      *                                                                         *
 642      **************************************************************************/
 643 
 644     /**
 645      * The updateItem method should not be called by developers, but it is the
 646      * best method for developers to override to allow for them to customise the
 647      * visuals of the cell. To clarify, developers should never call this method
 648      * in their code (they should leave it up to the UI control, such as the
 649      * {@link javafx.scene.control.ListView} control) to call this method. However,
 650      * the purpose of having the updateItem method is so that developers, when
 651      * specifying custom cell factories (again, like the ListView
 652      * {@link javafx.scene.control.ListView#cellFactoryProperty() cell factory}),


 719      *
 720      * <p>The default implementation of this method tests against equality, but
 721      * developers are able to override this method to perform checks in other ways
 722      * that are specific to their domain.</p>
 723      *
 724      * @param oldItem The currently-set item contained within the cell (i.e. it is
 725      *                the same as what is available via {@link #getItem()}).
 726      * @param newItem The item that will be set in the cell, if this method
 727      *                returns true. If this method returns false, it may not be
 728      *                set.
 729      * @return Returns true if the new item is considered to be different than
 730      *         the old item. By default this method tests against equality, but
 731      *         subclasses may alter the implementation to test appropriate to
 732      *         their needs.
 733      * @since JavaFX 8u40
 734      */
 735     protected boolean isItemChanged(T oldItem, T newItem) {
 736         return oldItem != null ? !oldItem.equals(newItem) : newItem != null;
 737     }
 738 




















 739 
 740 
 741     /***************************************************************************
 742      *                                                                         *
 743      * Private Implementation                                                  *
 744      *                                                                         *
 745      **************************************************************************/
 746 
 747     // itemDirty and markCellDirty introduced as a solution for JDK-8145588.
 748     // In the fullness of time, a more fully developed solution can be developed
 749     // that offers a public API around this lazy-dirty impl.
 750     private boolean itemDirty = false;
 751     private final void markCellDirty() {
 752         itemDirty = true;
 753         requestLayout();
 754     }
 755 





 756 
 757     /***************************************************************************
 758      *                                                                         *
 759      * Stylesheet Handling                                                     *
 760      *                                                                         *
 761      **************************************************************************/
 762 
 763     private static final String DEFAULT_STYLE_CLASS = "cell";
 764     private static final PseudoClass PSEUDO_CLASS_SELECTED =
 765             PseudoClass.getPseudoClass("selected");
 766     private static final PseudoClass PSEUDO_CLASS_FOCUSED =
 767             PseudoClass.getPseudoClass("focused");
 768     private static final PseudoClass PSEUDO_CLASS_EMPTY =
 769             PseudoClass.getPseudoClass("empty");
 770     private static final PseudoClass PSEUDO_CLASS_FILLED =
 771             PseudoClass.getPseudoClass("filled");
 772 
 773     /**
 774      * Returns the initial focus traversable state of this control, for use
 775      * by the JavaFX CSS engine to correctly set its initial value. This method
 776      * is overridden as by default UI controls have focus traversable set to true,
 777      * but that is not appropriate for this control.
 778      *
 779      * @since 9
 780      */
 781     @Override protected Boolean getInitialFocusTraversable() {
 782         return Boolean.FALSE;
 783     }
 784 }


  25 
  26 package javafx.scene.control;
  27 
  28 import javafx.beans.InvalidationListener;
  29 import javafx.beans.Observable;
  30 import javafx.beans.property.BooleanProperty;
  31 import javafx.beans.property.ObjectProperty;
  32 import javafx.beans.property.SimpleBooleanProperty;
  33 import javafx.beans.property.SimpleObjectProperty;
  34 import javafx.collections.ObservableList;
  35 import javafx.scene.Node;
  36 import javafx.scene.layout.GridPane;
  37 import javafx.scene.layout.HBox;
  38 import javafx.scene.shape.Rectangle;
  39 import javafx.css.PseudoClass;
  40 import javafx.beans.property.ReadOnlyBooleanProperty;
  41 import javafx.beans.property.ReadOnlyBooleanWrapper;
  42 import javafx.beans.value.WritableValue;
  43 import javafx.css.StyleableProperty;
  44 
  45 import java.util.Optional;
  46 
  47 /**
  48  * The Cell API is used for virtualized controls such as {@link ListView},
  49  * {@link TreeView}, and {@link TableView}.
  50  * A Cell is a {@link Labeled} {@link Control}, and is used to render a single
  51  * "row" inside  a ListView, TreeView or TableView. Cells are also used for each
  52  * individual 'cell' inside a TableView (i.e. each row/column intersection). See
  53  * the JavaDoc for each control separately for more detail.
  54  * <p>
  55  * Every Cell is associated with a single data item (represented by the
  56  * {@link #itemProperty() item} property). The Cell is responsible for
  57  * rendering that item and, where appropriate, for editing the item. An item
  58  * within a Cell may be represented by text or some other control such as a
  59  * {@link CheckBox}, {@link ChoiceBox} or any other {@link Node} such as a
  60  * {@link HBox}, {@link GridPane}, or even a {@link Rectangle}.
  61  * <p>
  62  * Because TreeView, ListView, TableView and other such controls can potentially
  63  * be used for displaying incredibly large amounts of data, it is not feasible
  64  * to create an actual Cell for every single item in the control.
  65  * We represent extremely large data sets using only very few Cells. Each Cell
  66  * is "recycled", or reused. This is what we mean when we say that these controls


 344      *                                                                         *
 345      **************************************************************************/
 346 
 347     /**
 348      * Creates a default Cell with the default style class of 'cell'.
 349      */
 350     public Cell() {
 351         setText(null); // default to null text, to match the null item
 352         // focusTraversable is styleable through css. Calling setFocusTraversable
 353         // makes it look to css like the user set the value and css will not
 354         // override. Initializing focusTraversable by calling set on the
 355         // CssMetaData ensures that css will be able to override the value.
 356         ((StyleableProperty<Boolean>)(WritableValue<Boolean>)focusTraversableProperty()).applyStyle(null, Boolean.FALSE);
 357         getStyleClass().addAll(DEFAULT_STYLE_CLASS);
 358 
 359         /**
 360          * Indicates whether or not this cell has focus. For example, a
 361          * ListView defines zero or one cell as being the "focused" cell. This cell
 362          * would have focused set to true.
 363          */
 364         super.focusedProperty().addListener(o -> {



 365             // The user has shifted focus, so we should cancel the editing on this cell
 366             if (!isFocused() && isEditing()) {
 367                 attemptEditCommit();

 368             }
 369         });
 370 
 371         // initialize default pseudo-class state
 372         pseudoClassStateChanged(PSEUDO_CLASS_EMPTY, true);
 373     }
 374 
 375 
 376 
 377     /***************************************************************************
 378      *                                                                         *
 379      * Properties                                                              *
 380      *                                                                         *
 381      **************************************************************************/
 382 
 383     // --- item
 384     private ObjectProperty<T> item = new SimpleObjectProperty<T>(this, "item");
 385 
 386     /**
 387      * The data value associated with this Cell. This value is set by the


 611      * implementations - it should be sufficient to simply call this method
 612      * when appropriate (e.g. when the user pressed the Enter key, you may do something
 613      * like {@code cell.commitEdit(converter.fromString(textField.getText()));}</p>
 614      *
 615      * @param newValue The value as input by the end user, which should be
 616      *      persisted in the relevant way given the data source underpinning the
 617      *      user interface and the install edit commit handler of the UI control.
 618      */
 619     public void commitEdit(T newValue) {
 620         if (isEditing()) {
 621             setEditing(false);
 622         }
 623     }
 624 
 625     /** {@inheritDoc} */
 626     @Override protected void layoutChildren() {
 627         if (itemDirty) {
 628             updateItem(getItem(), isEmpty());
 629             itemDirty = false;
 630         }
 631 
 632         super.layoutChildren();
 633     }
 634 
 635 
 636 
 637     /***************************************************************************
 638      *                                                                         *
 639      * Expert API                                                              *
 640      *                                                                         *
 641      **************************************************************************/
 642 
 643     /**
 644      * The updateItem method should not be called by developers, but it is the
 645      * best method for developers to override to allow for them to customise the
 646      * visuals of the cell. To clarify, developers should never call this method
 647      * in their code (they should leave it up to the UI control, such as the
 648      * {@link javafx.scene.control.ListView} control) to call this method. However,
 649      * the purpose of having the updateItem method is so that developers, when
 650      * specifying custom cell factories (again, like the ListView
 651      * {@link javafx.scene.control.ListView#cellFactoryProperty() cell factory}),


 718      *
 719      * <p>The default implementation of this method tests against equality, but
 720      * developers are able to override this method to perform checks in other ways
 721      * that are specific to their domain.</p>
 722      *
 723      * @param oldItem The currently-set item contained within the cell (i.e. it is
 724      *                the same as what is available via {@link #getItem()}).
 725      * @param newItem The item that will be set in the cell, if this method
 726      *                returns true. If this method returns false, it may not be
 727      *                set.
 728      * @return Returns true if the new item is considered to be different than
 729      *         the old item. By default this method tests against equality, but
 730      *         subclasses may alter the implementation to test appropriate to
 731      *         their needs.
 732      * @since JavaFX 8u40
 733      */
 734     protected boolean isItemChanged(T oldItem, T newItem) {
 735         return oldItem != null ? !oldItem.equals(newItem) : newItem != null;
 736     }
 737 
 738     /**
 739      * Developers of custom cell implementations should override this method when
 740      * the cell provides editing functionality, with this method returning the
 741      * user input after the user has interacted with the editing components.
 742      * The form of the returned data (wrapped in an {@link Optional}) should
 743      * be the same as the form of the underlying data model, hence the
 744      * use of the {@code T} generic type. If no value is available, or if the
 745      * value to be returned is invalid, {@code Optional.empty()} should be returned
 746      * to indicate that the commit should not proceed..
 747      *
 748      * @return The value provided by the user into this cell when it was in its
 749      *      editing state, in the form of the underlying data model. If the value
 750      *      is invalid or unable to be determined, {@code Optional.empty()} should
 751      *      be returned.
 752      * @since 10
 753      */
 754     protected Optional<T> getEditorValue() {
 755         return Optional.empty();
 756     }
 757 
 758 
 759 
 760     /***************************************************************************
 761      *                                                                         *
 762      * Private Implementation                                                  *
 763      *                                                                         *
 764      **************************************************************************/
 765 
 766     // itemDirty and markCellDirty introduced as a solution for JDK-8145588.
 767     // In the fullness of time, a more fully developed solution can be developed
 768     // that offers a public API around this lazy-dirty impl.
 769     private boolean itemDirty = false;
 770     private final void markCellDirty() {
 771         itemDirty = true;
 772         requestLayout();
 773     }
 774 
 775     void attemptEditCommit() {
 776         // The user has shifted focus, so we should cancel the editing on this cell
 777         getEditorValue().ifPresentOrElse(this::commitEdit, this::cancelEdit);
 778     }
 779 
 780 
 781     /***************************************************************************
 782      *                                                                         *
 783      * Stylesheet Handling                                                     *
 784      *                                                                         *
 785      **************************************************************************/
 786 
 787     private static final String DEFAULT_STYLE_CLASS = "cell";
 788     private static final PseudoClass PSEUDO_CLASS_SELECTED =
 789             PseudoClass.getPseudoClass("selected");


 790     private static final PseudoClass PSEUDO_CLASS_EMPTY =
 791             PseudoClass.getPseudoClass("empty");
 792     private static final PseudoClass PSEUDO_CLASS_FILLED =
 793             PseudoClass.getPseudoClass("filled");
 794 
 795     /**
 796      * Returns the initial focus traversable state of this control, for use
 797      * by the JavaFX CSS engine to correctly set its initial value. This method
 798      * is overridden as by default UI controls have focus traversable set to true,
 799      * but that is not appropriate for this control.
 800      *
 801      * @since 9
 802      */
 803     @Override protected Boolean getInitialFocusTraversable() {
 804         return Boolean.FALSE;
 805     }
 806 }
< prev index next >