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 static javafx.scene.control.cell.CellUtils.createChoiceBox; 29 import javafx.beans.property.ObjectProperty; 30 import javafx.beans.property.SimpleObjectProperty; 31 import javafx.collections.FXCollections; 32 import javafx.collections.ObservableList; 33 import javafx.event.EventHandler; 34 import javafx.scene.control.ChoiceBox; 35 import javafx.scene.control.Label; 36 import javafx.scene.control.TreeTableColumn; 37 import javafx.scene.control.TreeTableCell; 38 import javafx.util.Callback; 39 import javafx.util.StringConverter; 40 41 /** 42 * A class containing a {@link TreeTableCell} implementation that draws a 43 * {@link ChoiceBox} node inside the cell. 44 * 45 * <p>By default, the ChoiceBoxTreeTableCell is rendered as a {@link Label} when not 46 * being edited, and as a ChoiceBox when in editing mode. The ChoiceBox will, by 47 * default, stretch to fill the entire table cell. 48 * 49 * <p>To create a ChoiceBoxTreeTableCell, it is necessary to provide zero or more 50 * items that will be shown to the user when the {@link ChoiceBox} menu is 51 * showing. These items must be of the same type as the TreeTableColumn. 52 * 53 * @param <S> The type of the TableView generic type 54 * @param <T> The type of the elements contained within the TreeTableColumn. 55 * @since JavaFX 8.0 56 */ 57 public class ChoiceBoxTreeTableCell<S,T> extends TreeTableCell<S,T> { 58 59 /*************************************************************************** 60 * * 61 * Static cell factories * 62 * * 63 **************************************************************************/ 64 65 /** 66 * Creates a ChoiceBox cell factory for use in {@link TreeTableColumn} controls. 67 * By default, the ChoiceBoxCell is rendered as a {@link Label} when not 68 * being edited, and as a ChoiceBox when in editing mode. The ChoiceBox will, 69 * by default, stretch to fill the entire list cell. 70 * 71 * @param <S> The type of the TableView generic type 72 * @param <T> The type of the elements contained within the TreeTableColumn. 73 * @param items Zero or more items that will be shown to the user when the 74 * {@link ChoiceBox} menu is showing. These items must be of the same 75 * type as the TreeTableColumn. Note that it is up to the developer to set 76 * {@link EventHandler event handlers} to listen to edit events in the 77 * TreeTableColumn, and react accordingly. Methods of interest include 78 * {@link TreeTableColumn#setOnEditStart(javafx.event.EventHandler) setOnEditStart}, 79 * {@link TreeTableColumn#setOnEditCommit(javafx.event.EventHandler) setOnEditCommit}, 80 * and {@link TreeTableColumn#setOnEditCancel(javafx.event.EventHandler) setOnEditCancel}. 81 * @return A {@link Callback} that will return a TreeTableCell that is able to 82 * work on the type of element contained within the TreeTableColumn. 83 */ 84 @SafeVarargs 85 public static <S,T> Callback<TreeTableColumn<S,T>, TreeTableCell<S,T>> forTreeTableColumn(final T... items) { 86 return forTreeTableColumn(null, items); 87 } 88 89 /** 90 * Creates a ChoiceBox cell factory for use in {@link TreeTableColumn} controls. 91 * By default, the ChoiceBoxCell is rendered as a {@link Label} when not 92 * being edited, and as a ChoiceBox when in editing mode. The ChoiceBox 93 * will, by default, stretch to fill the entire list cell. 94 * 95 * @param <S> The type of the TableView generic type 96 * @param <T> The type of the elements contained within the TreeTableColumn. 97 * @param converter A {@link StringConverter} to convert the given item (of type T) 98 * to a String for displaying to the user. 99 * @param items Zero or more items that will be shown to the user when the 100 * {@link ChoiceBox} menu is showing. These items must be of the same 101 * type as the TreeTableColumn. Note that it is up to the developer to set 102 * {@link EventHandler event handlers} to listen to edit events in the 103 * TreeTableColumn, and react accordingly. Methods of interest include 104 * {@link TreeTableColumn#setOnEditStart(javafx.event.EventHandler) setOnEditStart}, 105 * {@link TreeTableColumn#setOnEditCommit(javafx.event.EventHandler) setOnEditCommit}, 106 * and {@link TreeTableColumn#setOnEditCancel(javafx.event.EventHandler) setOnEditCancel}. 107 * @return A {@link Callback} that will return a TreeTableCell that is able to 108 * work on the type of element contained within the TreeTableColumn. 109 */ 110 @SafeVarargs 111 public static <S,T> Callback<TreeTableColumn<S,T>, TreeTableCell<S,T>> forTreeTableColumn( 112 final StringConverter<T> converter, 113 final T... items) { 114 return forTreeTableColumn(converter, FXCollections.observableArrayList(items)); 115 } 116 117 /** 118 * Creates a ChoiceBox cell factory for use in {@link TreeTableColumn} controls. 119 * By default, the ChoiceBoxCell is rendered as a {@link Label} when not 120 * being edited, and as a ChoiceBox when in editing mode. The ChoiceBox will, 121 * by default, stretch to fill the entire list cell. 122 * 123 * @param <S> The type of the TableView generic type 124 * @param <T> The type of the elements contained within the TreeTableColumn. 125 * @param items Zero or more items that will be shown to the user when the 126 * {@link ChoiceBox} menu is showing. These items must be of the same 127 * type as the TreeTableColumn. Note that it is up to the developer to set 128 * {@link EventHandler event handlers} to listen to edit events in the 129 * TreeTableColumn, and react accordingly. Methods of interest include 130 * {@link TreeTableColumn#setOnEditStart(javafx.event.EventHandler) setOnEditStart}, 131 * {@link TreeTableColumn#setOnEditCommit(javafx.event.EventHandler) setOnEditCommit}, 132 * and {@link TreeTableColumn#setOnEditCancel(javafx.event.EventHandler) setOnEditCancel}. 133 * @return A {@link Callback} that will return a TreeTableCell that is able to 134 * work on the type of element contained within the TreeTableColumn. 135 */ 136 public static <S,T> Callback<TreeTableColumn<S,T>, TreeTableCell<S,T>> forTreeTableColumn( 137 final ObservableList<T> items) { 138 return forTreeTableColumn(null, items); 139 } 140 141 /** 142 * Creates a ChoiceBox cell factory for use in {@link TreeTableColumn} controls. 143 * By default, the ChoiceBoxCell is rendered as a {@link Label} when not 144 * being edited, and as a ChoiceBox when in editing mode. The ChoiceBox will, 145 * by default, stretch to fill the entire list cell. 146 * 147 * @param <S> The type of the TableView generic type 148 * @param <T> The type of the elements contained within the TreeTableColumn. 149 * @param converter A {@link StringConverter} to convert the given item (of type T) 150 * to a String for displaying to the user. 151 * @param items Zero or more items that will be shown to the user when the 152 * {@link ChoiceBox} menu is showing. These items must be of the same 153 * type as the TreeTableColumn. Note that it is up to the developer to set 154 * {@link EventHandler event handlers} to listen to edit events in the 155 * TreeTableColumn, and react accordingly. Methods of interest include 156 * {@link TreeTableColumn#setOnEditStart(javafx.event.EventHandler) setOnEditStart}, 157 * {@link TreeTableColumn#setOnEditCommit(javafx.event.EventHandler) setOnEditCommit}, 158 * and {@link TreeTableColumn#setOnEditCancel(javafx.event.EventHandler) setOnEditCancel}. 159 * @return A {@link Callback} that will return a TreeTableCell that is able to 160 * work on the type of element contained within the TreeTableColumn. 161 */ 162 public static <S,T> Callback<TreeTableColumn<S,T>, TreeTableCell<S,T>> forTreeTableColumn( 163 final StringConverter<T> converter, 164 final ObservableList<T> items) { 165 return list -> new ChoiceBoxTreeTableCell<S,T>(converter, items); 166 } 167 168 169 170 /*************************************************************************** 171 * * 172 * Fields * 173 * * 174 **************************************************************************/ 175 176 private final ObservableList<T> items; 177 178 private ChoiceBox<T> choiceBox; 179 180 181 182 /*************************************************************************** 183 * * 184 * Constructors * 185 * * 186 **************************************************************************/ 187 188 /** 189 * Creates a default ChoiceBoxTreeTableCell with an empty items list. 190 */ 191 public ChoiceBoxTreeTableCell() { 192 this(FXCollections.<T>observableArrayList()); 193 } 194 195 /** 196 * Creates a default {@link ChoiceBoxTreeTableCell} instance with the given items 197 * being used to populate the {@link ChoiceBox} when it is shown. 198 * 199 * @param items The items to show in the ChoiceBox popup menu when selected 200 * by the user. 201 */ 202 @SafeVarargs 203 public ChoiceBoxTreeTableCell(T... items) { 204 this(FXCollections.observableArrayList(items)); 205 } 206 207 /** 208 * Creates a {@link ChoiceBoxTreeTableCell} instance with the given items 209 * being used to populate the {@link ChoiceBox} when it is shown, and the 210 * {@link StringConverter} being used to convert the item in to a 211 * user-readable form. 212 * 213 * @param converter A {@link StringConverter} that can convert an item of type T 214 * into a user-readable string so that it may then be shown in the 215 * ChoiceBox popup menu. 216 * @param items The items to show in the ChoiceBox popup menu when selected 217 * by the user. 218 */ 219 @SafeVarargs 220 public ChoiceBoxTreeTableCell(StringConverter<T> converter, T... items) { 221 this(converter, FXCollections.observableArrayList(items)); 222 } 223 224 /** 225 * Creates a default {@link ChoiceBoxTreeTableCell} instance with the given items 226 * being used to populate the {@link ChoiceBox} when it is shown. 227 * 228 * @param items The items to show in the ChoiceBox popup menu when selected 229 * by the user. 230 */ 231 public ChoiceBoxTreeTableCell(ObservableList<T> items) { 232 this(null, items); 233 } 234 235 /** 236 * Creates a {@link ChoiceBoxTreeTableCell} instance with the given items 237 * being used to populate the {@link ChoiceBox} when it is shown, and the 238 * {@link StringConverter} being used to convert the item in to a 239 * user-readable form. 240 * 241 * @param converter A {@link StringConverter} that can convert an item of type T 242 * into a user-readable string so that it may then be shown in the 243 * ChoiceBox popup menu. 244 * @param items The items to show in the ChoiceBox popup menu when selected 245 * by the user. 246 */ 247 public ChoiceBoxTreeTableCell(StringConverter<T> converter, ObservableList<T> items) { 248 this.getStyleClass().add("choice-box-tree-table-cell"); 249 this.items = items; 250 setConverter(converter != null ? converter : CellUtils.<T>defaultStringConverter()); 251 } 252 253 254 /*************************************************************************** 255 * * 256 * Properties * 257 * * 258 **************************************************************************/ 259 260 // --- converter 261 private ObjectProperty<StringConverter<T>> converter = 262 new SimpleObjectProperty<StringConverter<T>>(this, "converter"); 263 264 /** 265 * The {@link StringConverter} property. 266 * @return the {@link StringConverter} property 267 */ 268 public final ObjectProperty<StringConverter<T>> converterProperty() { 269 return converter; 270 } 271 272 /** 273 * Sets the {@link StringConverter} to be used in this cell. 274 * @param value the {@link StringConverter} to be used in this cell 275 */ 276 public final void setConverter(StringConverter<T> value) { 277 converterProperty().set(value); 278 } 279 280 /** 281 * Returns the {@link StringConverter} used in this cell. 282 * @return the {@link StringConverter} used in this cell 283 */ 284 public final StringConverter<T> getConverter() { 285 return converterProperty().get(); 286 } 287 288 289 290 /*************************************************************************** 291 * * 292 * Public API * 293 * * 294 **************************************************************************/ 295 296 /** 297 * Returns the items to be displayed in the ChoiceBox when it is showing. 298 * @return the items to be displayed in the ChoiceBox when it is showing 299 */ 300 public ObservableList<T> getItems() { 301 return items; 302 } 303 304 /** {@inheritDoc} */ 305 @Override public void startEdit() { 306 if (! isEditable() || ! getTreeTableView().isEditable() || ! getTableColumn().isEditable()) { 307 return; 308 } 309 310 if (choiceBox == null) { 311 choiceBox = createChoiceBox(this, items, converterProperty()); 312 } 313 314 choiceBox.getSelectionModel().select(getItem()); 315 316 super.startEdit(); 317 setText(null); 318 setGraphic(choiceBox); 319 } 320 321 /** {@inheritDoc} */ 322 @Override public void cancelEdit() { 323 super.cancelEdit(); 324 325 setText(getConverter().toString(getItem())); 326 setGraphic(null); 327 } 328 329 /** {@inheritDoc} */ 330 @Override public void updateItem(T item, boolean empty) { 331 super.updateItem(item, empty); 332 CellUtils.updateItem(this, getConverter(), null, null, choiceBox); 333 } 334 }