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