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