Spec-Zone .ru
спецификации, руководства, описания, API
001/*
002 * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.  Oracle designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Oracle in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
022 * or visit www.oracle.com if you need additional information or have any
023 * questions.
024 */
025
026package javafx.scene.control.cell;
027
028import static javafx.scene.control.cell.CellUtils.createChoiceBox;
029import javafx.beans.property.ObjectProperty;
030import javafx.beans.property.SimpleObjectProperty;
031import javafx.collections.FXCollections;
032import javafx.collections.ObservableList;
033import javafx.event.EventHandler;
034import javafx.scene.control.ChoiceBox;
035import javafx.scene.control.Label;
036import javafx.scene.control.TableCell;
037import javafx.scene.control.TableColumn;
038import javafx.util.Callback;
039import javafx.util.StringConverter;
040
041/**
042 * A class containing a {@link TableCell} implementation that draws a 
043 * {@link ChoiceBox} node inside the cell.
044 * 
045 * <p>By default, the ChoiceBoxTableCell is rendered as a {@link Label} when not 
046 * being edited, and as a ChoiceBox when in editing mode. The ChoiceBox will, by 
047 * default, stretch to fill the entire table cell.
048 * 
049 * <p>To create a ChoiceBoxTableCell, it is necessary to provide zero or more 
050 * items that will be shown to the user when the {@link ChoiceBox} menu is 
051 * showing. These items must be of the same type as the TableColumn.
052 * 
053 * @param <T> The type of the elements contained within the TableColumn.
054 * @since 2.2
055 */
056public class ChoiceBoxTableCell<S,T> extends TableCell<S,T> {
057    
058    /***************************************************************************
059     *                                                                         *
060     * Static cell factories                                                   *
061     *                                                                         *
062     **************************************************************************/
063    
064    /**
065     * Creates a ChoiceBox cell factory for use in {@link TableColumn} controls. 
066     * By default, the ChoiceBoxCell is rendered as a {@link Label} when not 
067     * being edited, and as a ChoiceBox when in editing mode. The ChoiceBox will, 
068     * by default, stretch to fill the entire list cell.
069     * 
070     * @param <T> The type of the elements contained within the TableColumn.
071     * @param items Zero or more items that will be shown to the user when the
072     *      {@link ChoiceBox} menu is showing. These items must be of the same 
073     *      type as the TableColumn. Note that it is up to the developer to set 
074     *      {@link EventHandler event handlers} to listen to edit events in the 
075     *      TableColumn, and react accordingly. Methods of interest include 
076     *      {@link TableColumn#setOnEditStart(javafx.event.EventHandler) setOnEditStart},
077     *      {@link TableColumn#setOnEditCommit(javafx.event.EventHandler) setOnEditCommit}, 
078     *      and {@link TableColumn#setOnEditCancel(javafx.event.EventHandler) setOnEditCancel}.
079     * @return A {@link Callback} that will return a TableCell that is able to 
080     *      work on the type of element contained within the TableColumn.
081     */
082    public static <S,T> Callback<TableColumn<S,T>, TableCell<S,T>> forTableColumn(final T... items) {
083        return forTableColumn(null, items);
084    }
085    
086    /**
087     * Creates a ChoiceBox cell factory for use in {@link TableColumn} controls. 
088     * By default, the ChoiceBoxCell is rendered as a {@link Label} when not 
089     * being edited, and as a ChoiceBox when in editing mode. The ChoiceBox 
090     * will, by default, stretch to fill the entire list cell.
091     * 
092     * @param <T> The type of the elements contained within the TableColumn.
093     * @param converter A {@link StringConverter} to convert the given item (of type T) 
094     *      to a String for displaying to the user.
095     * @param items Zero or more items that will be shown to the user when the
096     *      {@link ChoiceBox} menu is showing. These items must be of the same
097     *      type as the TableColumn. Note that it is up to the developer to set 
098     *      {@link EventHandler event handlers} to listen to edit events in the 
099     *      TableColumn, and react accordingly. Methods of interest include 
100     *      {@link TableColumn#setOnEditStart(javafx.event.EventHandler) setOnEditStart},
101     *      {@link TableColumn#setOnEditCommit(javafx.event.EventHandler) setOnEditCommit}, 
102     *      and {@link TableColumn#setOnEditCancel(javafx.event.EventHandler) setOnEditCancel}.
103     * @return A {@link Callback} that will return a TableCell that is able to 
104     *      work on the type of element contained within the TableColumn.
105     */
106    public static <S,T> Callback<TableColumn<S,T>, TableCell<S,T>> forTableColumn(
107            final StringConverter<T> converter, 
108            final T... items) {
109        return forTableColumn(converter, FXCollections.observableArrayList(items));
110    }
111    
112    /**
113     * Creates a ChoiceBox cell factory for use in {@link TableColumn} controls. 
114     * By default, the ChoiceBoxCell is rendered as a {@link Label} when not 
115     * being edited, and as a ChoiceBox when in editing mode. The ChoiceBox will, 
116     * by default, stretch to fill the entire list cell.
117     * 
118     * @param <T> The type of the elements contained within the TableColumn.
119     * @param items Zero or more items that will be shown to the user when the
120     *      {@link ChoiceBox} menu is showing. These items must be of the same 
121     *      type as the TableColumn. Note that it is up to the developer to set 
122     *      {@link EventHandler event handlers} to listen to edit events in the 
123     *      TableColumn, and react accordingly. Methods of interest include 
124     *      {@link TableColumn#setOnEditStart(javafx.event.EventHandler) setOnEditStart},
125     *      {@link TableColumn#setOnEditCommit(javafx.event.EventHandler) setOnEditCommit}, 
126     *      and {@link TableColumn#setOnEditCancel(javafx.event.EventHandler) setOnEditCancel}.
127     * @return A {@link Callback} that will return a TableCell that is able to 
128     *      work on the type of element contained within the TableColumn.
129     */
130    public static <S,T> Callback<TableColumn<S,T>, TableCell<S,T>> forTableColumn(
131            final ObservableList<T> items) {
132        return forTableColumn(null, items);
133    }
134    
135    /**
136     * Creates a ChoiceBox cell factory for use in {@link TableColumn} controls. 
137     * By default, the ChoiceBoxCell is rendered as a {@link Label} when not 
138     * being edited, and as a ChoiceBox when in editing mode. The ChoiceBox will, 
139     * by default, stretch to fill the entire list cell.
140     * 
141     * @param <T> The type of the elements contained within the TableColumn.
142     * @param converter A {@link StringConverter} to convert the given item (of type T) 
143     * to a String for displaying to the user.
144     * @param items Zero or more items that will be shown to the user when the
145     *      {@link ChoiceBox} menu is showing. These items must be of the same 
146     *      type as the TableColumn. Note that it is up to the developer to set 
147     *      {@link EventHandler event handlers} to listen to edit events in the 
148     *      TableColumn, and react accordingly. Methods of interest include 
149     *      {@link TableColumn#setOnEditStart(javafx.event.EventHandler) setOnEditStart},
150     *      {@link TableColumn#setOnEditCommit(javafx.event.EventHandler) setOnEditCommit}, 
151     *      and {@link TableColumn#setOnEditCancel(javafx.event.EventHandler) setOnEditCancel}.
152     * @return A {@link Callback} that will return a TableCell that is able to 
153     *      work on the type of element contained within the TableColumn.
154     */
155    public static <S,T> Callback<TableColumn<S,T>, TableCell<S,T>> forTableColumn(
156            final StringConverter<T> converter, 
157            final ObservableList<T> items) {
158        return new Callback<TableColumn<S,T>, TableCell<S,T>>() {
159            @Override public TableCell<S,T> call(TableColumn<S,T> list) {
160                return new ChoiceBoxTableCell<S,T>(converter, items);
161            }
162        };
163    }
164    
165    
166    
167    /***************************************************************************
168     *                                                                         *
169     * Fields                                                                  *
170     *                                                                         *
171     **************************************************************************/     
172        
173    private final ObservableList<T> items;
174
175    private ChoiceBox<T> choiceBox;
176    
177    
178    
179    /***************************************************************************
180     *                                                                         *
181     * Constructors                                                            *
182     *                                                                         *
183     **************************************************************************/     
184    
185    /**
186     * Creates a default ChoiceBoxTableCell with an empty items list.
187     */
188    public ChoiceBoxTableCell() {
189        this(FXCollections.<T>observableArrayList());
190    }
191    
192    /**
193     * Creates a default {@link ChoiceBoxTableCell} instance with the given items
194     * being used to populate the {@link ChoiceBox} when it is shown.
195     * 
196     * @param items The items to show in the ChoiceBox popup menu when selected 
197     *      by the user.
198     */
199    public ChoiceBoxTableCell(T... items) {
200        this(FXCollections.observableArrayList(items));
201    }
202    
203    /**
204     * Creates a {@link ChoiceBoxTableCell} instance with the given items
205     * being used to populate the {@link ChoiceBox} when it is shown, and the 
206     * {@link StringConverter} being used to convert the item in to a 
207     * user-readable form.
208     * 
209     * @param converter A {@link StringConverter} that can convert an item of type T 
210     *      into a user-readable string so that it may then be shown in the 
211     *      ChoiceBox popup menu.
212     * @param items The items to show in the ChoiceBox popup menu when selected 
213     *      by the user.
214     */
215    public ChoiceBoxTableCell(StringConverter<T> converter, T... items) {
216        this(converter, FXCollections.observableArrayList(items));
217    }
218    
219    /**
220     * Creates a default {@link ChoiceBoxTableCell} instance with the given items
221     * being used to populate the {@link ChoiceBox} when it is shown.
222     * 
223     * @param items The items to show in the ChoiceBox popup menu when selected 
224     *      by the user.
225     */
226    public ChoiceBoxTableCell(ObservableList<T> items) {
227        this(null, items);
228    }
229
230    /**
231     * Creates a {@link ChoiceBoxTableCell} instance with the given items
232     * being used to populate the {@link ChoiceBox} when it is shown, and the 
233     * {@link StringConverter} being used to convert the item in to a 
234     * user-readable form.
235     * 
236     * @param converter A {@link StringConverter} that can convert an item of type T 
237     *      into a user-readable string so that it may then be shown in the 
238     *      ChoiceBox popup menu.
239     * @param items The items to show in the ChoiceBox popup menu when selected 
240     *      by the user.
241     */
242    public ChoiceBoxTableCell(StringConverter<T> converter, ObservableList<T> items) {
243        this.getStyleClass().add("choice-box-table-cell");
244        this.items = items;
245        setConverter(converter != null ? converter : CellUtils.<T>defaultStringConverter());
246    }
247    
248    
249    /***************************************************************************
250     *                                                                         *
251     * Properties                                                              *
252     *                                                                         *
253     **************************************************************************/
254    
255    // --- converter
256    private ObjectProperty<StringConverter<T>> converter = 
257            new SimpleObjectProperty<StringConverter<T>>(this, "converter");
258
259    /**
260     * The {@link StringConverter} property.
261     */
262    public final ObjectProperty<StringConverter<T>> converterProperty() { 
263        return converter; 
264    }
265    
266    /** 
267     * Sets the {@link StringConverter} to be used in this cell.
268     */
269    public final void setConverter(StringConverter<T> value) { 
270        converterProperty().set(value); 
271    }
272    
273    /**
274     * Returns the {@link StringConverter} used in this cell.
275     */
276    public final StringConverter<T> getConverter() { 
277        return converterProperty().get(); 
278    }
279    
280    
281    
282    /***************************************************************************
283     *                                                                         *
284     * Public API                                                              *
285     *                                                                         *
286     **************************************************************************/
287    
288    /**
289     * Returns the items to be displayed in the ChoiceBox when it is showing.
290     */
291    public ObservableList<T> getItems() {
292        return items;
293    }    
294    
295    /** {@inheritDoc} */
296    @Override public void startEdit() {
297        if (! isEditable() || ! getTableView().isEditable() || ! getTableColumn().isEditable()) {
298            return;
299        }
300        
301        if (choiceBox == null) {
302            choiceBox = createChoiceBox(this, items);
303        }
304        
305        choiceBox.getSelectionModel().select(getItem());
306        
307        super.startEdit();
308        setText(null);
309        setGraphic(choiceBox);
310    }
311
312    /** {@inheritDoc} */
313    @Override public void cancelEdit() {
314        super.cancelEdit();
315        
316        setText(getConverter().toString(getItem()));
317        setGraphic(null);
318    }
319    
320    /** {@inheritDoc} */
321    @Override public void updateItem(T item, boolean empty) {
322        super.updateItem(item, empty);
323        CellUtils.updateItem(this, getConverter(), null, null, choiceBox);
324    }
325}