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.createComboBox;
029import javafx.beans.property.BooleanProperty;
030import javafx.beans.property.ObjectProperty;
031import javafx.beans.property.SimpleBooleanProperty;
032import javafx.beans.property.SimpleObjectProperty;
033import javafx.collections.FXCollections;
034import javafx.collections.ObservableList;
035import javafx.event.EventHandler;
036import javafx.scene.control.ComboBox;
037import javafx.scene.control.Label;
038import javafx.scene.control.TreeTableCell;
039import javafx.scene.control.TreeTableColumn;
040import javafx.util.Callback;
041import javafx.util.StringConverter;
042
043/**
044 * A class containing a {@link TreeTableCell} implementation that draws a 
045 * {@link ComboBox} node inside the cell.
046 * 
047 * <p>By default, the ComboBoxTreeTableCell is rendered as a {@link Label} when not 
048 * being edited, and as a ComboBox when in editing mode. The ComboBox will, by 
049 * default, stretch to fill the entire table cell.
050 * 
051 * <p>To create a ComboBoxTreeTableCell, it is necessary to provide zero or more 
052 * items that will be shown to the user when the {@link ComboBox} menu is 
053 * showing. These items must be of the same type as the TreeTableColumn.
054 * 
055 * @param <T> The type of the elements contained within the TreeTableColumn.
056 * @since 8.0
057 */
058public class ComboBoxTreeTableCell<S,T> extends TreeTableCell<S,T> {
059    
060    /***************************************************************************
061     *                                                                         *
062     * Static cell factories                                                   *
063     *                                                                         *
064     **************************************************************************/
065    
066    /**
067     * Creates a ComboBox cell factory for use in {@link TreeTableColumn} controls. 
068     * By default, the ComboBoxCell is rendered as a {@link Label} when not 
069     * being edited, and as a ComboBox when in editing mode. The ComboBox will, 
070     * by default, stretch to fill the entire list cell.
071     * 
072     * @param <T> The type of the elements contained within the TreeTableColumn.
073     * @param items Zero or more items that will be shown to the user when the
074     *      {@link ComboBox} menu is showing. These items must be of the same 
075     *      type as the TreeTableColumn. Note that it is up to the developer to set 
076     *      {@link EventHandler event handlers} to listen to edit events in the 
077     *      TreeTableColumn, and react accordingly. Methods of interest include 
078     *      {@link TreeTableColumn#setOnEditStart(javafx.event.EventHandler) setOnEditStart},
079     *      {@link TreeTableColumn#setOnEditCommit(javafx.event.EventHandler) setOnEditCommit}, 
080     *      and {@link TreeTableColumn#setOnEditCancel(javafx.event.EventHandler) setOnEditCancel}.
081     * @return A {@link Callback} that will return a TreeTableCell that is able to 
082     *      work on the type of element contained within the TreeTableColumn.
083     */
084    public static <S,T> Callback<TreeTableColumn<S,T>, TreeTableCell<S,T>> forTreeTableColumn(
085            final T... items) {
086        return forTreeTableColumn(null, items);
087    }
088    
089    /**
090     * Creates a ComboBox cell factory for use in {@link TreeTableColumn} controls. 
091     * By default, the ComboBoxCell is rendered as a {@link Label} when not 
092     * being edited, and as a ComboBox when in editing mode. The ComboBox will, 
093     * by default, stretch to fill the entire list cell.
094     * 
095     * @param <T> The type of the elements contained within the TreeTableColumn.
096     * @param converter A {@link StringConverter} to convert the given item (of 
097     *      type T) to a String for displaying to the user.
098     * @param items Zero or more items that will be shown to the user when the
099     *      {@link ComboBox} menu is showing. These items must be of the same 
100     *      type as the TreeTableColumn. Note that it is up to the developer to set 
101     *      {@link EventHandler event handlers} to listen to edit events in the 
102     *      TreeTableColumn, and react accordingly. Methods of interest include 
103     *      {@link TreeTableColumn#setOnEditStart(javafx.event.EventHandler) setOnEditStart},
104     *      {@link TreeTableColumn#setOnEditCommit(javafx.event.EventHandler) setOnEditCommit}, 
105     *      and {@link TreeTableColumn#setOnEditCancel(javafx.event.EventHandler) setOnEditCancel}.
106     * @return A {@link Callback} that will return a TreeTableCell that is able to 
107     *      work on the type of element contained within the TreeTableColumn.
108     */
109    public static <S,T> Callback<TreeTableColumn<S,T>, TreeTableCell<S,T>> forTreeTableColumn(
110            final StringConverter<T> converter, 
111            final T... items) {
112        return forTreeTableColumn(converter, FXCollections.observableArrayList(items));
113    }
114    
115    /**
116     * Creates a ComboBox cell factory for use in {@link TreeTableColumn} controls. 
117     * By default, the ComboBoxCell is rendered as a {@link Label} when not 
118     * being edited, and as a ComboBox when in editing mode. The ComboBox will, 
119     * by default, stretch to fill the entire list cell.
120     * 
121     * @param <T> The type of the elements contained within the TreeTableColumn.
122     * @param items Zero or more items that will be shown to the user when the
123     *      {@link ComboBox} menu is showing. These items must be of the same 
124     *      type as the TreeTableColumn. Note that it is up to the developer to set 
125     *      {@link EventHandler event handlers} to listen to edit events in the 
126     *      TreeTableColumn, and react accordingly. Methods of interest include 
127     *      {@link TreeTableColumn#setOnEditStart(javafx.event.EventHandler) setOnEditStart},
128     *      {@link TreeTableColumn#setOnEditCommit(javafx.event.EventHandler) setOnEditCommit}, 
129     *      and {@link TreeTableColumn#setOnEditCancel(javafx.event.EventHandler) setOnEditCancel}.
130     * @return A {@link Callback} that will return a TreeTableCell that is able to 
131     *      work on the type of element contained within the TreeTableColumn.
132     */
133    public static <S,T> Callback<TreeTableColumn<S,T>, TreeTableCell<S,T>> forTreeTableColumn(
134            final ObservableList<T> items) {
135        return forTreeTableColumn(null, items);
136    }
137    
138    /**
139     * Creates a ComboBox cell factory for use in {@link TreeTableColumn} controls. 
140     * By default, the ComboBoxCell is rendered as a {@link Label} when not 
141     * being edited, and as a ComboBox when in editing mode. The ComboBox will, 
142     * by default, stretch to fill the entire list cell.
143     * 
144     * @param <T> The type of the elements contained within the TreeTableColumn.
145     * @param converter A {@link StringConverter} to convert the given item (of 
146     *      type T) to a String for displaying to the user.
147     * @param items Zero or more items that will be shown to the user when the
148     *      {@link ComboBox} menu is showing. These items must be of the same 
149     *      type as the TreeTableColumn. Note that it is up to the developer to set 
150     *      {@link EventHandler event handlers} to listen to edit events in the 
151     *      TreeTableColumn, and react accordingly. Methods of interest include 
152     *      {@link TreeTableColumn#setOnEditStart(javafx.event.EventHandler) setOnEditStart},
153     *      {@link TreeTableColumn#setOnEditCommit(javafx.event.EventHandler) setOnEditCommit}, 
154     *      and {@link TreeTableColumn#setOnEditCancel(javafx.event.EventHandler) setOnEditCancel}.
155     * @return A {@link Callback} that will return a TreeTableCell that is able to 
156     *      work on the type of element contained within the TreeTableColumn.
157     */
158    public static <S,T> Callback<TreeTableColumn<S,T>, TreeTableCell<S,T>> forTreeTableColumn(
159            final StringConverter<T> converter, 
160            final ObservableList<T> items) {
161        return new Callback<TreeTableColumn<S,T>, TreeTableCell<S,T>>() {
162            @Override public TreeTableCell<S,T> call(TreeTableColumn<S,T> list) {
163                return new ComboBoxTreeTableCell<S,T>(converter, items);
164            }
165        };
166    }
167    
168    
169    
170    /***************************************************************************
171     *                                                                         *
172     * Fields                                                                  *
173     *                                                                         *
174     **************************************************************************/      
175        
176    private final ObservableList<T> items;
177
178    private ComboBox<T> comboBox;
179
180    
181    
182    /***************************************************************************
183     *                                                                         *
184     * Constructors                                                            *
185     *                                                                         *
186     **************************************************************************/     
187    
188    /**
189     * Creates a default ComboBoxTreeTableCell with an empty items list.
190     */
191    public ComboBoxTreeTableCell() {
192        this(FXCollections.<T>observableArrayList());
193    }
194    
195    /**
196     * Creates a default {@link ComboBoxTreeTableCell} instance with the given items
197     * being used to populate the {@link ComboBox} when it is shown.
198     * 
199     * @param items The items to show in the ComboBox popup menu when selected 
200     *      by the user.
201     */
202    public ComboBoxTreeTableCell(T... items) {
203        this(FXCollections.observableArrayList(items));
204    }
205    
206    /**
207     * Creates a {@link ComboBoxTreeTableCell} instance with the given items
208     * being used to populate the {@link ComboBox} when it is shown, and the 
209     * {@link StringConverter} being used to convert the item in to a 
210     * user-readable form.
211     * 
212     * @param converter A {@link StringConverter} that can convert an item of type T 
213     *      into a user-readable string so that it may then be shown in the 
214     *      ComboBox popup menu.
215     * @param items The items to show in the ComboBox popup menu when selected 
216     *      by the user.
217     */
218    public ComboBoxTreeTableCell(StringConverter<T> converter, T... items) {
219        this(converter, FXCollections.observableArrayList(items));
220    }
221    
222    /**
223     * Creates a default {@link ComboBoxTreeTableCell} instance with the given items
224     * being used to populate the {@link ComboBox} when it is shown.
225     * 
226     * @param items The items to show in the ComboBox popup menu when selected 
227     *      by the user.
228     */
229    public ComboBoxTreeTableCell(ObservableList<T> items) {
230        this(null, items);
231    }
232
233    /**
234     * Creates a {@link ComboBoxTreeTableCell} instance with the given items
235     * being used to populate the {@link ComboBox} when it is shown, and the 
236     * {@link StringConverter} being used to convert the item in to a 
237     * user-readable form.
238     * 
239     * @param converter A {@link StringConverter} that can convert an item of type T 
240     *      into a user-readable string so that it may then be shown in the 
241     *      ComboBox popup menu.
242     * @param items The items to show in the ComboBox popup menu when selected 
243     *      by the user.
244     */
245    public ComboBoxTreeTableCell(StringConverter<T> converter, ObservableList<T> items) {
246        this.getStyleClass().add("combo-box-tree-table-cell");
247        this.items = items;
248        setConverter(converter != null ? converter : CellUtils.<T>defaultStringConverter());
249    }
250    
251    
252    
253    /***************************************************************************
254     *                                                                         *
255     * Properties                                                              *
256     *                                                                         *
257     **************************************************************************/
258    
259    // --- converter
260    private ObjectProperty<StringConverter<T>> converter = 
261            new SimpleObjectProperty<StringConverter<T>>(this, "converter");
262
263    /**
264     * The {@link StringConverter} property.
265     */
266    public final ObjectProperty<StringConverter<T>> converterProperty() { 
267        return converter; 
268    }
269    
270    /** 
271     * Sets the {@link StringConverter} to be used in this cell.
272     */
273    public final void setConverter(StringConverter<T> value) { 
274        converterProperty().set(value); 
275    }
276    
277    /**
278     * Returns the {@link StringConverter} used in this cell.
279     */
280    public final StringConverter<T> getConverter() { 
281        return converterProperty().get(); 
282    }
283    
284    
285    // --- comboBox editable
286    private BooleanProperty comboBoxEditable = 
287            new SimpleBooleanProperty(this, "comboBoxEditable");
288
289    /**
290     * A property representing whether the ComboBox, when shown to the user,
291     * is editable or not.
292     */
293    public final BooleanProperty comboBoxEditableProperty() { 
294        return comboBoxEditable; 
295    }
296    
297    /** 
298     * Configures the ComboBox to be editable (to allow user input outside of the
299     * options provide in the dropdown list).
300     */
301    public final void setComboBoxEditable(boolean value) { 
302        comboBoxEditableProperty().set(value); 
303    }
304    
305    /**
306     * Returns true if the ComboBox is editable.
307     */
308    public final boolean isComboBoxEditable() { 
309        return comboBoxEditableProperty().get(); 
310    }
311    
312    
313    
314    /***************************************************************************
315     *                                                                         *
316     * Public API                                                              *
317     *                                                                         *
318     **************************************************************************/
319    
320    /**
321     * Returns the items to be displayed in the ChoiceBox when it is showing.
322     */
323    public ObservableList<T> getItems() {
324        return items;
325    }    
326    
327    /** {@inheritDoc} */
328    @Override public void startEdit() {
329        if (! isEditable() || ! getTreeTableView().isEditable() || ! getTableColumn().isEditable()) {
330            return;
331        }
332        
333        if (comboBox == null) {
334            comboBox = createComboBox(this, items, getConverter());
335            comboBox.editableProperty().bind(comboBoxEditableProperty());
336        }
337        
338        comboBox.getSelectionModel().select(getItem());
339        
340        super.startEdit();
341        setText(null);
342        setGraphic(comboBox);
343    }
344
345    /** {@inheritDoc} */
346    @Override public void cancelEdit() {
347        super.cancelEdit();
348        
349        setText(getConverter().toString(getItem()));
350        setGraphic(null);
351    }
352    
353    /** {@inheritDoc} */
354    @Override public void updateItem(T item, boolean empty) {
355        super.updateItem(item, empty);
356        CellUtils.updateItem(this, getConverter(), null, null, comboBox);
357    }
358}