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