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