Spec-Zone .ru
спецификации, руководства, описания, API
001/*
002 * Copyright (c) 2010, 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;
027
028import javafx.beans.InvalidationListener;
029import javafx.beans.Observable;
030import javafx.beans.property.BooleanProperty;
031import javafx.beans.property.ObjectProperty;
032import javafx.beans.property.SimpleBooleanProperty;
033import javafx.beans.property.SimpleObjectProperty;
034import javafx.collections.ObservableList;
035import javafx.scene.Node;
036import javafx.scene.layout.GridPane;
037import javafx.scene.layout.HBox;
038import javafx.scene.shape.Rectangle;
039import javafx.css.CssMetaData;
040import com.sun.javafx.scene.control.accessible.AccessibleListItem;
041import com.sun.javafx.accessible.providers.AccessibleProvider;
042import javafx.css.PseudoClass;
043import javafx.beans.property.ReadOnlyBooleanProperty;
044import javafx.beans.property.ReadOnlyBooleanWrapper;
045import javafx.css.StyleableProperty;
046
047/**
048 * The Cell API is used for virtualized controls such as {@link ListView},
049 * {@link TreeView}, and {@link TableView}.
050 * A Cell is a {@link Labeled} {@link Control}, and is used to render a single 
051 * "row" inside  a ListView, TreeView or TableView. Cells are also used for each 
052 * individual 'cell' inside a TableView (i.e. each row/column intersection). See 
053 * the JavaDoc for each control separately for more detail.
054 * <p>
055 * Every Cell is associated with a single data item (represented by the 
056 * {@link #itemProperty() item} property). The Cell is responsible for
057 * rendering that item and, where appropriate, for editing the item. An item
058 * within a Cell may be represented by text or some other control such as a
059 * {@link CheckBox}, {@link ChoiceBox} or any other {@link Node} such as a 
060 * {@link HBox}, {@link GridPane}, or even a {@link Rectangle}.
061 * <p>
062 * Because TreeView, ListView, TableView and other such controls can potentially
063 * be used for displaying incredibly large amounts of data, it is not feasible
064 * to create an actual Cell for every single item in the control.
065 * We represent extremely large data sets using only very few Cells. Each Cell
066 * is "recycled", or reused. This is what we mean when we say that these controls
067 * are virtualized.
068 * <p>
069 * Since Cell is a Control, it is essentially a "model". Its Skin is responsible
070 * for defining the look and layout, while the Behavior is responsible for
071 * handling all input events and using that information to modify the Control
072 * state. Also, the Cell is styled from CSS just like any other Control.
073 * However, it is not necessary to implement a Skin for most uses of a Cell.
074 * This is because a cell factory can be set - this is detailed more shortly.
075 * <p>
076 * Because by far the most common use case for cells is to show text to a user,
077 * this use case is specially optimized for within Cell. This is done by Cell 
078 * extending from {@link Labeled}. This means that subclasses of Cell need only 
079 * set the {@link #textProperty() text} property, rather than create a separate 
080 * {@link Label} and set that within the Cell. However, for situations where
081 * something more than just plain text is called for, it is possible to place
082 * any {@link Node} in the Cell {@link #graphicProperty() graphic} property.
083 * Despite the term, a graphic can be any Node, and will be fully interactive.
084 * For example, a ListCell might be configured with a {@link Button} as its 
085 * graphic. The Button text could then be bound to the cells
086 * {@link #itemProperty() item} property. In this way, whenever the item in the 
087 * Cell changes, the Button text is automatically updated.
088 * <p>
089 * Cell sets focusTraversable to false.
090 * </p>
091 * <p>
092 * <b>Cell Factories</b>
093 * <p>
094 * The default representation of the Cell <code>item</code> is up to the various
095 * virtualized container's skins to render. For example, the ListView by default
096 * will convert the item to a String and call {@link #setText(java.lang.String)}
097 * with this value. If you want to specialize the Cell used for the
098 * ListView (for example), then you must provide an implementation of the
099 * {@link ListView#cellFactoryProperty() cellFactory} callback function defined 
100 * on the ListView. Similar API exists on most controls that use Cells (for example, 
101 * {@link TreeView#cellFactoryProperty() TreeView}, 
102 * {@link TableView#rowFactoryProperty() TableView},
103 * {@link TableColumn#cellFactoryProperty() TableColumn} and 
104 * {@link ListView#cellFactoryProperty() ListView}.
105 * <p>
106 * The cell factory is called by the platform whenever it determines that a new
107 * cell needs to be created. For example, perhaps your ListView has 10 million
108 * items. Creating all 10 million cells would be prohibitively expensive. So
109 * instead the ListView skin implementation might only create just enough cells
110 * to fit the visual space. If the ListView is resized to be larger, the system
111 * will determine that it needs to create some additional cells. In this case
112 * it will call the cellFactory callback function (if one is provided) to create
113 * the Cell implementation that should be used. If no cell factory is provided,
114 * the built-in default implementation will be used.
115 * <p>
116 * The implementation of the cell factory is then responsible not just for
117 * creating a Cell instance, but also configuring that Cell such that it reacts
118 * to changes in its state. For example, if I were to create
119 * a custom Cell which formatted Numbers such that they would appear as currency
120 * types, I might do so like this:
121 * 
122 * <pre>
123 * public class MoneyFormatCell extends ListCell&lt;Number&gt; {
124 *
125 *     public MoneyFormatCell() {    }
126 *       
127 *     &#064;Override protected void updateItem(Number item, boolean empty) {
128 *         // calling super here is very important - don't skip this!
129 *         super.updateItem(item, empty);
130 *           
131 *         // format the number as if it were a monetary value using the 
132 *         // formatting relevant to the current locale. This would format
133 *         // 43.68 as "$43.68", and -23.67 as "-$23.67"
134 *         setText(item == null ? "" : NumberFormat.getCurrencyInstance().format(item));
135 *
136 *         // change the text fill based on whether it is positive (green)
137 *         // or negative (red). If the cell is selected, the text will 
138 *         // always be white (so that it can be read against the blue 
139 *         // background), and if the value is zero, we'll make it black.
140 *         if (item != null) {
141 *             double value = item.doubleValue();
142 *             setTextFill(isSelected() ? Color.WHITE :
143 *                 value == 0 ? Color.BLACK :
144 *                 value < 0 ? Color.RED : Color.GREEN);
145 *         }
146 *     }
147 * }</pre>
148 * 
149 * This class could then be used inside a ListView as such:
150 * 
151 * <pre>
152 * ObservableList&lt;Number&gt; money = ...;
153 * final ListView&lt;Number&gt; listView = new ListView&lt;Number&gt;(money);
154 * listView.setCellFactory(new Callback&lt;ListView&lt;Number&gt;, ListCell&lt;Number&gt;&gt;() {
155 *     &#064;Override public ListCell&lt;Number&gt; call(ListView&lt;Number&gt; list) {
156 *         return new MoneyFormatCell();
157 *     }
158 * });</pre>
159 *
160 * In this example an anonymous inner class is created, that simply returns
161 * instances of MoneyFormatCell whenever it is called. The MoneyFormatCell class
162 * extends {@link ListCell}, overriding the 
163 * {@link #updateItem(java.lang.Object, boolean) updateItem} method. This method
164 * is called whenever the item in the cell changes, for example when the user 
165 * scrolls the ListView or the content of the underlying data model changes 
166 * (and the cell is reused to represent some different item in the ListView). 
167 * Because of this, there is no need to manage bindings - simply react to the
168 * change in items when this method occurs. In the example above, whenever the 
169 * item changes, we update the cell text property, and also modify the text fill
170 * to ensure that we get the correct visuals. In addition, if the cell is "empty" 
171 * (meaning it is used to fill out space in the ListView but doesn't have any 
172 * data associated with it), then we just use the empty String.
173 * <p>
174 * Note that there are additional 
175 * methods prefixed with 'update' that may be of interest, so be
176 * sure to read the API documentation for Cell, and subclasses of Cell, closely.
177 * <p>
178 * Of course, we can also use the binding API rather than overriding the 
179 * 'update' methods. Shown below is a very trivial example of how this could
180 * be achieved.
181 *
182 *
183 * <pre>
184 * public class BoundLabelCell extends ListCell&lt;String&gt; {
185 *
186 *     public TextFieldCell() {
187 *         textProperty().bind(itemProperty());
188 *     }
189 * }
190 * </pre>
191 * 
192 * <h3>Key Design Goals</h3>
193 * <ul>
194 *   <li>Both time and memory efficient for large data sets</li>
195 *   <li>Easy to build and use libraries for custom cells</li>
196 *   <li>Easy to customize cell visuals</li>
197 *   <li>Easy to customize display formatting (12.34 as $12.34 or 1234% etc)</li>
198 *   <li>Easy to extend for custom visuals</li>
199 *   <li>Easy to have "panels" of data for the visuals</li>
200 *   <li>Easy to animate the cell size or other properties</li>
201 * </ul>
202 * 
203 * <h3>Key Use Cases</h3>
204 * Following are a number of key use cases used to drive the Cell API design,
205 * along with code examples showing how those use cases are satisfied by this
206 * API. This is by no means to be considered the definitive list of capabilities
207 * or features supported, but rather, to provide some guidance as to how to use
208 * the Cell API. The examples below are focused on the ListView, but the same
209 * philosophy applies to TreeCells or other kinds of cells.
210 * <p>
211 * <b>Changing the Cell's Colors</b>
212 * <p>
213 * This should be extraordinarily simple in JavaFX. Each Cell can be styled
214 * directly from CSS. So for example, if you wanted to change the default
215 * background of every cell in a ListView to be WHITE you could do the
216 * following CSS:
217 *
218 * <pre>
219 * .list-cell {
220 *   -fx-padding: 3 3 3 3;
221 *   -fx-background-color: white;
222 * }</pre>
223 * 
224 * If you wanted to set the color of selected ListView cells to be blue, you
225 * could add this to your CSS file:
226 * 
227 * <pre>
228 * .list-cell:selected {
229 *   -fx-background-color: blue;
230 * }</pre>
231 *
232 * Most Cell implementations extend from {@link IndexedCell} rather than Cell.
233 * IndexedCell adds two other pseudoclass states: "odd" and "even". Using this 
234 * you can get alternate row striping by doing something like this in your CSS 
235 * file:
236 * 
237 * <pre>
238 * .list-cell:odd {
239 *   -fx-background-color: grey;
240 * }</pre>
241 * 
242 * Each of these examples require no code changes. Simply update your CSS
243 * file to alter the colors. You can also use the "hover" and other
244 * pseudoclasses in CSS the same as with other controls.
245 * <p>
246 * Another approach to the first example above (formatting a list of numbers) would
247 * be to use style classes. Suppose you had an {@link ObservableList} of Numbers 
248 * to display in a ListView and wanted to color all of the negative values red 
249 * and all positive or 0 values black.
250 * One way to achieve this is with a custom cellFactory which changes the
251 * styleClass of the Cell based on whether the value is negative or positive. This
252 * is as simple as adding code to test if the number in the cell is negative, 
253 * and adding a "negative" styleClass. If the number is not negative, the "negative"
254 * string should be removed. This approach allows for the colors to be defined 
255 * from CSS, allowing for simple customization. The CSS file would then include
256 * something like the following:
257 *
258 * <pre>
259 * .list-cell {
260 *   -fx-text-fill: black;
261 * }
262 * 
263 * .list-cell .negative {
264 *   -fx-text-fill: red;
265 * }</pre>
266 * 
267 * 
268 * @param <T> The type of the item contained within the Cell.
269 *
270 */
271public class Cell<T> extends Labeled {
272    
273    /***************************************************************************
274     *                                                                         *
275     * Constructors                                                            *
276     *                                                                         *
277     **************************************************************************/
278
279    /**
280     * Creates a default Cell with the default style class of 'cell'.
281     */
282    public Cell() {
283        setText(null); // default to null text, to match the null item
284        // focusTraversable is styleable through css. Calling setFocusTraversable
285        // makes it look to css like the user set the value and css will not 
286        // override. Initializing focusTraversable by calling set on the 
287        // CssMetaData ensures that css will be able to override the value.
288        ((StyleableProperty)focusTraversableProperty()).applyStyle(null, Boolean.FALSE);
289        getStyleClass().addAll(DEFAULT_STYLE_CLASS);
290
291        /**
292         * Indicates whether or not this cell has focus. For example, a
293         * ListView defines zero or one cell as being the "focused" cell. This cell
294         * would have focused set to true.
295         */
296        super.focusedProperty().addListener(new InvalidationListener() {
297            @Override public void invalidated(Observable property) {
298                pseudoClassStateChanged(PSEUDO_CLASS_FOCUSED, isFocused()); // TODO is this necessary??
299
300                // The user has shifted focus, so we should cancel the editing on this cell
301                if (!isFocused() && isEditing()) {
302                    cancelEdit();
303                }
304            }
305        });
306        
307        // initialize default pseudo-class state
308        pseudoClassStateChanged(PSEUDO_CLASS_EMPTY, true);
309    }
310    
311    
312    
313    /***************************************************************************
314     *                                                                         *
315     * Properties                                                              *
316     *                                                                         *
317     **************************************************************************/
318
319    // --- item
320    private ObjectProperty<T> item = new SimpleObjectProperty<T>(this, "item");
321
322    /**
323     * The data value associated with this Cell. This value is set by the
324     * virtualized Control when the Cell is created or updated. This represents
325     * the raw data value. 
326    *
327    * <p>This value should only be set in subclasses of Cell by the virtualised 
328    * user interface controls that know how to properly work with the Cell 
329    * class.
330     */
331    public final ObjectProperty<T> itemProperty() { return item; }
332    
333    /** 
334     * Sets the item to the given value - should not be called directly as the
335     * item is managed by the virtualized control.
336     */
337    public final void setItem(T value) { item.set(value); }
338    
339    /**
340     * Returns the data value associated with this Cell.
341     */
342    public final T getItem() { return item.get(); }
343    
344    
345
346    // --- empty
347    private ReadOnlyBooleanWrapper empty = new ReadOnlyBooleanWrapper(true) {
348        @Override protected void invalidated() {
349            final boolean active = get();
350            pseudoClassStateChanged(PSEUDO_CLASS_EMPTY,   active);
351            pseudoClassStateChanged(PSEUDO_CLASS_FILLED, !active);
352        }
353
354        @Override
355        public Object getBean() {
356            return Cell.this;
357        }
358        
359        @Override
360        public String getName() {
361            return "empty";
362        }
363    };
364    
365    /**
366     * A property used to represent whether the cell has any contents.
367     * If true, then the Cell contains no data and is not associated with any
368     * data item in the virtualized Control. 
369     * 
370     * <p>When a cell is empty, it can be styled differently via the 'empty' 
371     * CSS pseudo class state. For example, it may not receive any 
372     * alternate row highlighting, or it may not receive hover background 
373     * fill when hovered.
374     */
375    public final ReadOnlyBooleanProperty emptyProperty() { return empty.getReadOnlyProperty(); }
376    
377    private void setEmpty(boolean value) { empty.set(value); }
378    
379    /**
380     * Returns a boolean representing whether the cell is considered to be empty
381     * or not.
382     */
383    public final boolean isEmpty() { return empty.get(); }
384    
385    
386
387    // --- selected
388    private ReadOnlyBooleanWrapper selected = new ReadOnlyBooleanWrapper() {
389        @Override protected void invalidated() {
390            pseudoClassStateChanged(PSEUDO_CLASS_SELECTED, get());
391        }
392
393        @Override
394        public Object getBean() {
395            return Cell.this;
396        }
397        
398        @Override
399        public String getName() {
400            return "selected";
401        }
402    };
403    
404    /**
405     * Indicates whether or not this cell has been selected. For example, a
406     * ListView defines zero or more cells as being the "selected" cells.
407     */
408    public final ReadOnlyBooleanProperty selectedProperty() { return selected.getReadOnlyProperty(); }
409
410    void setSelected(boolean value) { selected.set(value); }
411    
412    /**
413     * Returns whether this cell is currently selected or not.
414     * @return True if the cell is selected, false otherwise.
415     */
416    public final boolean isSelected() { return selected.get(); }
417    
418    
419    
420    // --- Editing
421    private ReadOnlyBooleanWrapper editing;
422
423    private void setEditing(boolean value) {
424        editingPropertyImpl().set(value);
425    }
426
427    /**
428     * Represents whether the cell is currently in its editing state or not.
429     */
430    public final boolean isEditing() {
431        return editing == null ? false : editing.get();
432    }
433
434    /**
435     * Property representing whether this cell is currently in its editing state.
436     */
437    public final ReadOnlyBooleanProperty editingProperty() {
438        return editingPropertyImpl().getReadOnlyProperty();
439    }
440
441    private ReadOnlyBooleanWrapper editingPropertyImpl() {
442        if (editing == null) {
443            editing = new ReadOnlyBooleanWrapper(this, "editing");
444        }
445        return editing;
446    }
447    
448    
449    
450    // --- Editable
451    private BooleanProperty editable;
452
453    /**
454     * Allows for certain cells to not be able to be edited. This is useful in
455     * cases where, say, a List has 'header rows' - it does not make sense for
456     * the header rows to be editable, so they should have editable set to 
457     * false.
458     * 
459     * @param value A boolean representing whether the cell is editable or not.
460     *      If true, the cell is editable, and if it is false, the cell can not
461     *      be edited.
462     */
463    public final void setEditable(boolean value) {
464        editableProperty().set(value);
465    }
466
467    /**
468     * Returns whether this cell is allowed to be put into an editing state.
469     */
470    public final boolean isEditable() {
471        return editable == null ? true : editable.get();
472    }
473
474    /**
475     * A property representing whether this cell is allowed to be put into an 
476     * editing state. By default editable is set to true in Cells (although for 
477     * a subclass of Cell to be allowed to enter its editing state, it may have
478     * to satisfy additional criteria. For example, ListCell requires that the
479     * ListView {@link ListView#editableProperty() editable} property is also
480     * true.
481     */
482    public final BooleanProperty editableProperty() {
483        if (editable == null) {
484            editable = new SimpleBooleanProperty(this, "editable", true);
485        }
486        return editable;
487    }
488    
489    
490    
491    /***************************************************************************
492     *                                                                         *
493     * Public API                                                              *
494     *                                                                         *
495     **************************************************************************/
496
497    /**
498     * Call this function to transition from a non-editing state into an editing
499     * state, if the cell is editable. If this cell is already in an editing 
500     * state, it will stay in it.
501     */
502    public void startEdit() {
503        if (isEditable() && !isEditing() && !isEmpty()) {
504            setEditing(true);
505        }
506    }
507
508    /**
509     * Call this function to transition from an editing state into a non-editing
510     * state, without saving any user input.
511     */
512    public void cancelEdit() {
513        if (isEditing()) {
514            setEditing(false);
515        }
516    }
517
518    /**
519     * Call this function to transition from an editing state into a non-editing
520     * state, and in the process saving any user input.
521     * 
522     * @param newValue The value as input by the end user, which should be 
523     *      persisted in the relevant way given the data source underpinning the
524     *      user interface.
525     */
526    public void commitEdit(T newValue) {
527        if (isEditing()) {
528            setEditing(false);
529        }
530    }
531
532
533
534    /***************************************************************************
535     *                                                                         *
536     * Expert API                                                              *
537     *                                                                         *
538     **************************************************************************/
539
540    /**
541     * <p>
542     *     Updates the item associated with this Cell. This method should <strong>
543     *     only</strong> be called by Skin implementations of ListView, TableView,
544     *     TreeView, or other controls using Cells. It is not intended to be called
545     *     by application developers.
546     * </p>
547     * <p>
548     *     Because <code>null</code> is a perfectly valid value in the application
549     *     domain, Cell needs some way to distinguish whether or not the cell
550     *     actually holds a value. The <code>empty</code> flag indicates this.
551     *     It is an error to supply a non-null <code>item</code> but a true value for
552     *     <code>empty</code>.
553     * </p>
554     * @param item The new item for the cell
555     * @param empty whether or not this cell represents data from the list. If it
556     *        is empty, then it does not represent any domain data, but is a cell
557     *        being used to render an "empty" row.
558     * @expert
559     */
560    protected void updateItem(T item, boolean empty) {
561        if (isEditing()) cancelEdit();
562        setItem(item);
563        setEmpty(empty);
564        if (empty && isSelected()) {
565            updateSelected(false);
566        }
567    }
568    
569    /**
570     * Updates whether this cell is in a selected state or not.
571     * @expert
572     * @param selected whether or not to select this cell.
573     */
574    public void updateSelected(boolean selected) {
575        if (selected && isEmpty()) return;
576        setSelected(selected);
577    }
578
579    private AccessibleListItem accListItem ;
580    /**
581     * @treatAsPrivate implementation detail
582     * @deprecated This is an internal API that is not intended for use and will be removed in the next version
583     */
584    @Deprecated @Override public AccessibleProvider impl_getAccessible() {
585        if( accListItem == null)
586            accListItem = new AccessibleListItem(this);
587        return (AccessibleProvider)accListItem ;
588    }
589    
590    
591    /***************************************************************************
592     *                                                                         *
593     * Stylesheet Handling                                                     *
594     *                                                                         *
595     **************************************************************************/
596
597    private static final String DEFAULT_STYLE_CLASS = "cell";
598    private static final PseudoClass PSEUDO_CLASS_SELECTED =
599            PseudoClass.getPseudoClass("selected");
600    private static final PseudoClass PSEUDO_CLASS_FOCUSED = 
601            PseudoClass.getPseudoClass("focused");
602    private static final PseudoClass PSEUDO_CLASS_EMPTY =
603            PseudoClass.getPseudoClass("empty");
604    private static final PseudoClass PSEUDO_CLASS_FILLED =
605            PseudoClass.getPseudoClass("filled");
606
607    /**
608      * Most Controls return true for focusTraversable, so Control overrides
609      * this method to return true, but Cell returns false for
610      * focusTraversable's initial value; hence the override of the override. 
611      * This method is called from CSS code to get the correct initial value.
612      * @treatAsPrivate implementation detail
613      */
614    @Deprecated @Override
615    protected /*do not make final*/ Boolean impl_cssGetFocusTraversableInitialValue() {
616        return Boolean.FALSE;
617    }
618    
619}