1 /*
   2  * Copyright (c) 2012, 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.cell;
  27 
  28 import javafx.beans.property.ObjectProperty;
  29 import javafx.beans.property.SimpleObjectProperty;
  30 import javafx.scene.control.Label;
  31 import javafx.scene.control.ListCell;
  32 import javafx.scene.control.ListView;
  33 import javafx.scene.control.TextField;
  34 import javafx.util.Callback;
  35 import javafx.util.StringConverter;
  36 import javafx.util.converter.DefaultStringConverter;
  37 
  38 /**
  39  * A class containing a {@link ListCell} implementation that draws a
  40  * {@link TextField} node inside the cell.
  41  *
  42  * <p>By default, the TextFieldListCell is rendered as a {@link Label} when not
  43  * being edited, and as a TextField when in editing mode. The TextField will, by
  44  * default, stretch to fill the entire list cell.
  45  *
  46  * @param <T> The type of the elements contained within the ListView.
  47  * @since JavaFX 2.2
  48  */
  49 public class TextFieldListCell<T> extends ListCell<T> {
  50 
  51     /***************************************************************************
  52      *                                                                         *
  53      * Static cell factories                                                   *
  54      *                                                                         *
  55      **************************************************************************/
  56 
  57     /**
  58      * Provides a {@link TextField} that allows editing of the cell content when
  59      * the cell is double-clicked, or when {@link ListView#edit(int)} is called.
  60      * This method will only work on {@link ListView} instances which are of
  61      * type String.
  62      *
  63      * @return A {@link Callback} that can be inserted into the
  64      *      {@link ListView#cellFactoryProperty() cell factory property} of a
  65      *      ListView, that enables textual editing of the content.
  66      */
  67     public static Callback<ListView<String>, ListCell<String>> forListView() {
  68         return forListView(new DefaultStringConverter());
  69     }
  70 
  71     /**
  72      * Provides a {@link TextField} that allows editing of the cell content when
  73      * the cell is double-clicked, or when {@link ListView#edit(int)} is called.
  74      * This method will work on any ListView instance, regardless of its generic
  75      * type. However, to enable this, a {@link StringConverter} must be provided
  76      * that will convert the given String (from what the user typed in) into an
  77      * instance of type T. This item will then be passed along to the
  78      * {@link ListView#onEditCommitProperty()} callback.
  79      *
  80      * @param <T> The type of the item contained within the Cell
  81      * @param converter A {@link StringConverter} that can convert the given String
  82      *      (from what the user typed in) into an instance of type T.
  83      * @return A {@link Callback} that can be inserted into the
  84      *      {@link ListView#cellFactoryProperty() cell factory property} of a
  85      *      ListView, that enables textual editing of the content.
  86      */
  87     public static <T> Callback<ListView<T>, ListCell<T>> forListView(final StringConverter<T> converter) {
  88         return list -> new TextFieldListCell<T>(converter);
  89     }
  90 
  91 
  92 
  93     /***************************************************************************
  94      *                                                                         *
  95      * Fields                                                                  *
  96      *                                                                         *
  97      **************************************************************************/
  98     private TextField textField;
  99 
 100 
 101 
 102     /***************************************************************************
 103      *                                                                         *
 104      * Constructors                                                            *
 105      *                                                                         *
 106      **************************************************************************/
 107 
 108     /**
 109      * Creates a default TextFieldListCell with a null converter. Without a
 110      * {@link StringConverter} specified, this cell will not be able to accept
 111      * input from the TextField (as it will not know how to convert this back
 112      * to the domain object). It is therefore strongly encouraged to not use
 113      * this constructor unless you intend to set the converter separately.
 114      */
 115     public TextFieldListCell() {
 116         this(null);
 117     }
 118 
 119     /**
 120      * Creates a TextFieldListCell that provides a {@link TextField} when put
 121      * into editing mode that allows editing of the cell content. This method
 122      * will work on any ListView instance, regardless of its generic type.
 123      * However, to enable this, a {@link StringConverter} must be provided that
 124      * will convert the given String (from what the user typed in) into an
 125      * instance of type T. This item will then be passed along to the
 126      * {@link ListView#onEditCommitProperty()} callback.
 127      *
 128      * @param converter A {@link StringConverter converter} that can convert
 129      *      the given String (from what the user typed in) into an instance of
 130      *      type T.
 131      */
 132     public TextFieldListCell(StringConverter<T> converter) {
 133         this.getStyleClass().add("text-field-list-cell");
 134         setConverter(converter);
 135     }
 136 
 137 
 138 
 139     /***************************************************************************
 140      *                                                                         *
 141      * Properties                                                              *
 142      *                                                                         *
 143      **************************************************************************/
 144 
 145     // --- converter
 146     private ObjectProperty<StringConverter<T>> converter =
 147             new SimpleObjectProperty<StringConverter<T>>(this, "converter");
 148 
 149     /**
 150      * The {@link StringConverter} property.
 151      * @return the {@link StringConverter} property
 152      */
 153     public final ObjectProperty<StringConverter<T>> converterProperty() {
 154         return converter;
 155     }
 156 
 157     /**
 158      * Sets the {@link StringConverter} to be used in this cell.
 159      * @param value the {@link StringConverter} to be used in this cell
 160      */
 161     public final void setConverter(StringConverter<T> value) {
 162         converterProperty().set(value);
 163     }
 164 
 165     /**
 166      * Returns the {@link StringConverter} used in this cell.
 167      * @return the {@link StringConverter} used in this cell
 168      */
 169     public final StringConverter<T> getConverter() {
 170         return converterProperty().get();
 171     }
 172 
 173 
 174     /***************************************************************************
 175      *                                                                         *
 176      * Public API                                                              *
 177      *                                                                         *
 178      **************************************************************************/
 179 
 180     /** {@inheritDoc} */
 181     @Override public void startEdit() {
 182         if (! isEditable() || ! getListView().isEditable()) {
 183             return;
 184         }
 185         super.startEdit();
 186 
 187         if (isEditing()) {
 188             if (textField == null) {
 189                 textField = CellUtils.createTextField(this, getConverter());
 190             }
 191 
 192             CellUtils.startEdit(this, getConverter(), null, null, textField);
 193         }
 194     }
 195 
 196     /** {@inheritDoc} */
 197     @Override public void cancelEdit() {
 198         super.cancelEdit();
 199         CellUtils.cancelEdit(this, getConverter(), null);
 200     }
 201 
 202     /** {@inheritDoc} */
 203     @Override public void updateItem(T item, boolean empty) {
 204         super.updateItem(item, empty);
 205         CellUtils.updateItem(this, getConverter(), null, null, textField);
 206     }
 207 }