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 com.sun.javafx.scene.control.skin.NestedTableColumnHeader;
029import com.sun.javafx.scene.control.skin.TableColumnHeader;
030import com.sun.javafx.scene.control.skin.TableHeaderRow;
031import com.sun.javafx.scene.control.skin.TableViewSkin;
032import com.sun.javafx.scene.control.skin.TableViewSkinBase;
033
034import javafx.beans.property.ObjectProperty;
035import javafx.beans.property.SimpleObjectProperty;
036import javafx.collections.FXCollections;
037import javafx.collections.ListChangeListener;
038import javafx.collections.ObservableList;
039import javafx.css.CssMetaData;
040import javafx.css.Styleable;
041import javafx.event.Event;
042import javafx.event.EventHandler;
043import javafx.event.EventTarget;
044import javafx.event.EventType;
045import javafx.scene.Node;
046import javafx.util.Callback;
047
048import javafx.collections.WeakListChangeListener;
049import java.util.Collections;
050
051import java.util.List;
052import java.util.Map;
053import javafx.beans.InvalidationListener;
054import javafx.beans.Observable;
055import javafx.beans.property.ReadOnlyObjectProperty;
056import javafx.beans.property.ReadOnlyObjectWrapper;
057import javafx.beans.value.ObservableValue;
058import javafx.beans.value.WritableValue;
059
060/**
061 * A {@link TableView} is made up of a number of TableColumn instances. Each
062 * TableColumn in a table is responsible for displaying (and editing) the contents
063 * of that column. As well as being responsible for displaying and editing data 
064 * for a single column, a TableColumn also contains the necessary properties to:
065 * <ul>
066 *    <li>Be resized (using {@link #minWidthProperty() minWidth}/{@link #prefWidthProperty() prefWidth}/{@link #maxWidthProperty() maxWidth}
067 *      and {@link #widthProperty() width} properties)
068 *    <li>Have its {@link #visibleProperty() visibility} toggled
069 *    <li>Display {@link #textProperty() header text}
070 *    <li>Display any {@link #getColumns() nested columns} it may contain
071 *    <li>Have a {@link #contextMenuProperty() context menu} when the user 
072 *      right-clicks the column header area
073 *    <li>Have the contents of the table be sorted (using 
074 *      {@link #comparatorProperty() comparator}, {@link #sortable sortable} and
075 *      {@link #sortTypeProperty() sortType})
076 * </ul>
077 * </p>
078 * 
079 * When creating a TableColumn instance, perhaps the two most important properties
080 * to set are the column {@link #textProperty() text} (what to show in the column
081 * header area), and the column {@link #cellValueFactory cell value factory}
082 * (which is used to populate individual cells in the column). This can be 
083 * achieved using some variation on the following code:
084 * 
085 * <pre>
086 * {@code 
087 * ObservableList<Person> data = ...
088 * TableView<Person> tableView = new TableView<Person>(data);
089 * 
090 * TableColumn<Person,String> firstNameCol = new TableColumn<Person,String>("First Name");
091 * firstNameCol.setCellValueFactory(new Callback<CellDataFeatures<Person, String>, ObservableValue<String>>() {
092 *     public ObservableValue<String> call(CellDataFeatures<Person, String> p) {
093 *         // p.getValue() returns the Person instance for a particular TableView row
094 *         return p.getValue().firstNameProperty();
095 *     }
096 *  });
097 * }
098 * tableView.getColumns().add(firstNameCol);}</pre>
099 * 
100 * This approach assumes that the object returned from <code>p.getValue()</code>
101 * has a JavaFX {@link ObservableValue} that can simply be returned. The benefit of this
102 * is that the TableView will internally create bindings to ensure that,
103 * should the returned {@link ObservableValue} change, the cell contents will be
104 * automatically refreshed. 
105 * 
106 * <p>In situations where a TableColumn must interact with classes created before
107 * JavaFX, or that generally do not wish to use JavaFX apis for properties, it is
108 * possible to wrap the returned value in a {@link ReadOnlyObjectWrapper} instance. For
109 * example:
110 * 
111 * <pre>
112 * {@code 
113 * firstNameCol.setCellValueFactory(new Callback<CellDataFeatures<Person, String>, ObservableValue<String>>() {
114 *     public ObservableValue<String> call(CellDataFeatures<Person, String> p) {
115 *         return new ReadOnlyObjectWrapper(p.getValue().getFirstName());
116 *     }
117 *  });}</pre>
118 * 
119 * It is hoped that over time there will be convenience cell value factories 
120 * developed and made available to developers. As of the JavaFX 2.0 release, 
121 * there is one such convenience class: {@link PropertyValueFactory}. This class
122 * removes the need to write the code above, instead relying on reflection to 
123 * look up a given property from a String. Refer to the 
124 * <code>PropertyValueFactory</code> class documentation for more information
125 * on how to use this with a TableColumn.
126 * 
127 * Finally, for more detail on how to use TableColumn, there is further documentation in
128 * the {@link TableView} class documentation.
129 * 
130 * @param <S> The type of the TableView generic type (i.e. S == TableView&lt;S&gt;)
131 * @param <T> The type of the content in all cells in this TableColumn.
132 * @see TableView
133 * @see TableCell
134 * @see TablePosition
135 */
136public class TableColumn<S,T> extends TableColumnBase<S,T> implements EventTarget {
137    
138    /***************************************************************************
139     *                                                                         *
140     * Static properties and methods                                           *
141     *                                                                         *
142     **************************************************************************/
143
144    /**
145     * Parent event for any TableColumn edit event.
146     */
147    @SuppressWarnings("unchecked")
148    public static <S,T> EventType<CellEditEvent<S,T>> editAnyEvent() {
149        return (EventType<CellEditEvent<S,T>>) EDIT_ANY_EVENT;
150    }
151    private static final EventType<?> EDIT_ANY_EVENT =
152            new EventType(Event.ANY, "TABLE_COLUMN_EDIT");
153
154    /**
155     * Indicates that the user has performed some interaction to start an edit
156     * event, or alternatively the {@link TableView#edit(int, javafx.scene.control.TableColumn)}
157     * method has been called.
158     */
159    @SuppressWarnings("unchecked")
160    public static <S,T> EventType<CellEditEvent<S,T>> editStartEvent() {
161        return (EventType<CellEditEvent<S,T>>) EDIT_START_EVENT;
162    }
163    private static final EventType<?> EDIT_START_EVENT =
164            new EventType(editAnyEvent(), "EDIT_START");
165
166    /**
167     * Indicates that the editing has been canceled, meaning that no change should
168     * be made to the backing data source.
169     */
170    @SuppressWarnings("unchecked")
171    public static <S,T> EventType<CellEditEvent<S,T>> editCancelEvent() {
172        return (EventType<CellEditEvent<S,T>>) EDIT_CANCEL_EVENT;
173    }
174    private static final EventType<?> EDIT_CANCEL_EVENT =
175            new EventType(editAnyEvent(), "EDIT_CANCEL");
176
177    /**
178     * Indicates that the editing has been committed by the user, meaning that
179     * a change should be made to the backing data source to reflect the new
180     * data.
181     */
182    @SuppressWarnings("unchecked")
183    public static <S,T> EventType<CellEditEvent<S,T>> editCommitEvent() {
184        return (EventType<CellEditEvent<S,T>>) EDIT_COMMIT_EVENT;
185    }
186    private static final EventType<?> EDIT_COMMIT_EVENT =
187            new EventType(editAnyEvent(), "EDIT_COMMIT");
188    
189    
190    
191    /**
192     * If no cellFactory is specified on a TableColumn instance, then this one
193     * will be used by default. At present it simply renders the TableCell item 
194     * property within the {@link TableCell#graphicProperty() graphic} property
195     * if the {@link Cell#item item} is a Node, or it simply calls 
196     * <code>toString()</code> if it is not null, setting the resulting string
197     * inside the {@link Cell#textProperty() text} property.
198     */
199    public static final Callback<TableColumn<?,?>, TableCell<?,?>> DEFAULT_CELL_FACTORY = 
200            new Callback<TableColumn<?,?>, TableCell<?,?>>() {
201                
202        @Override public TableCell<?,?> call(TableColumn<?,?> param) {
203            return new TableCell<Object,Object>() {
204                @Override protected void updateItem(Object item, boolean empty) {
205                    if (item == getItem()) return;
206
207                    super.updateItem(item, empty);
208
209                    if (item == null) {
210                        super.setText(null);
211                        super.setGraphic(null);
212                    } else if (item instanceof Node) {
213                        super.setText(null);
214                        super.setGraphic((Node)item);
215                    } else {
216                        super.setText(item.toString());
217                        super.setGraphic(null);
218                    }
219                }
220            };
221        }
222    };
223
224    
225    
226    /***************************************************************************
227     *                                                                         *
228     * Constructors                                                            *
229     *                                                                         *
230     **************************************************************************/    
231
232    /**
233     * Creates a default TableColumn with default cell factory, comparator, and
234     * onEditCommit implementation.
235     */
236    public TableColumn() {
237        getStyleClass().add(DEFAULT_STYLE_CLASS);
238        
239        setOnEditCommit(DEFAULT_EDIT_COMMIT_HANDLER);
240
241        // we listen to the columns list here to ensure that widths are
242        // maintained properly, and to also set the column hierarchy such that
243        // all children columns know that this TableColumn is their parent.
244        getColumns().addListener(weakColumnsListener);
245
246        tableViewProperty().addListener(new InvalidationListener() {
247            @Override public void invalidated(Observable observable) {
248                // set all children of this tableView to have the same TableView
249                // as this column
250                for (TableColumn<S, ?> tc : getColumns()) {
251                    tc.setTableView(getTableView());
252                }
253                
254                // This code was commented out due to RT-22391, with this enabled
255                // the parent column will be null, which is not desired
256//                // set the parent of this column to also have this tableView
257//                if (getParentColumn() != null) {
258//                    getParentColumn().setTableView(getTableView());
259//                }
260            }
261        });
262    }
263
264    /**
265     * Creates a TableColumn with the text set to the provided string, with
266     * default cell factory, comparator, and onEditCommit implementation.
267     * @param text The string to show when the TableColumn is placed within the TableView.
268     */
269    public TableColumn(String text) {
270        this();
271        setText(text);
272    }
273    
274    
275    
276    /***************************************************************************
277     *                                                                         *
278     * Listeners                                                               *
279     *                                                                         *
280     **************************************************************************/
281    
282    private EventHandler<CellEditEvent<S,T>> DEFAULT_EDIT_COMMIT_HANDLER = new EventHandler<CellEditEvent<S,T>>() {
283        @Override public void handle(CellEditEvent<S,T> t) {
284            int index = t.getTablePosition().getRow();
285            List<S> list = t.getTableView().getItems();
286            if (list == null || index < 0 || index >= list.size()) return;
287            S rowData = list.get(index);
288            ObservableValue<T> ov = getCellObservableValue(rowData);
289            
290            if (ov instanceof WritableValue) {
291                ((WritableValue)ov).setValue(t.getNewValue());
292            }
293        }
294    };
295    
296    private ListChangeListener<TableColumn<S,?>> columnsListener = new ListChangeListener<TableColumn<S,?>>() {
297        @Override public void onChanged(Change<? extends TableColumn<S,?>> c) {
298            while (c.next()) {
299                // update the TableColumn.tableView property
300                for (TableColumn<S,?> tc : c.getRemoved()) {
301                    // Fix for RT-16978. In TableColumnHeader we add before we
302                    // remove when moving a TableColumn. This means that for
303                    // a very brief moment the tc is duplicated, and we can prevent
304                    // nulling out the tableview and parent column. Without this
305                    // here, in a very special circumstance it is possible to null
306                    // out the entire content of a column by reordering and then
307                    // sorting another column.
308                    if (getColumns().contains(tc)) continue;
309                    
310                    tc.setTableView(null);
311                    tc.setParentColumn(null);
312                }
313                for (TableColumn<S,?> tc : c.getAddedSubList()) {
314                    tc.setTableView(getTableView());
315                }
316
317                updateColumnWidths();
318            }
319        }
320    };
321    
322    private WeakListChangeListener<TableColumn<S,?>> weakColumnsListener = 
323            new WeakListChangeListener<TableColumn<S,?>>(columnsListener);
324
325    
326    
327    /***************************************************************************
328     *                                                                         *
329     * Instance Variables                                                      *
330     *                                                                         *
331     **************************************************************************/
332
333    // Contains any children columns that should be nested within this column
334    private final ObservableList<TableColumn<S,?>> columns = FXCollections.<TableColumn<S,?>>observableArrayList();
335
336    
337    
338    /***************************************************************************
339     *                                                                         *
340     * Properties                                                              *
341     *                                                                         *
342     **************************************************************************/
343
344    // --- TableView
345    /**
346     * The TableView that this TableColumn belongs to.
347     */
348    private ReadOnlyObjectWrapper<TableView<S>> tableView = new ReadOnlyObjectWrapper<TableView<S>>(this, "tableView");
349    public final ReadOnlyObjectProperty<TableView<S>> tableViewProperty() {
350        return tableView.getReadOnlyProperty();
351    }
352    final void setTableView(TableView<S> value) { tableView.set(value); }
353    public final TableView<S> getTableView() { return tableView.get(); }
354
355    
356    
357    // --- Cell value factory
358    /**
359     * The cell value factory needs to be set to specify how to populate all
360     * cells within a single TableColumn. A cell value factory is a {@link Callback}
361     * that provides a {@link CellDataFeatures} instance, and expects an
362     * {@link ObservableValue} to be returned. The returned ObservableValue instance
363     * will be observed internally to allow for immediate updates to the value
364     * to be reflected on screen.
365     * 
366     * An example of how to set a cell value factory is:
367     * 
368     * <pre><code>
369     * lastNameCol.setCellValueFactory(new Callback&lt;CellDataFeatures&lt;Person, String&gt;, ObservableValue&lt;String&gt;&gt;() {
370     *     public ObservableValue&lt;String&gt; call(CellDataFeatures&lt;Person, String&gt; p) {
371     *         // p.getValue() returns the Person instance for a particular TableView row
372     *         return p.getValue().lastNameProperty();
373     *     }
374     *  });
375     * }
376     * </code></pre>
377     * 
378     * A common approach is to want to populate cells in a TableColumn using
379     * a single value from a Java bean. To support this common scenario, there
380     * is the {@link PropertyValueFactory} class. Refer to this class for more 
381     * information on how to use it, but briefly here is how the above use case
382     * could be simplified using the PropertyValueFactory class:
383     * 
384     * <pre><code>
385     * lastNameCol.setCellValueFactory(new PropertyValueFactory&lt;Person,String&gt;("lastName"));
386     * </code></pre>
387     * 
388     * @see PropertyValueFactory
389     */
390    private ObjectProperty<Callback<CellDataFeatures<S,T>, ObservableValue<T>>> cellValueFactory;
391    public final void setCellValueFactory(Callback<CellDataFeatures<S,T>, ObservableValue<T>> value) {
392        cellValueFactoryProperty().set(value);
393    }
394    public final Callback<CellDataFeatures<S,T>, ObservableValue<T>> getCellValueFactory() {
395        return cellValueFactory == null ? null : cellValueFactory.get();
396    }
397    public final ObjectProperty<Callback<CellDataFeatures<S,T>, ObservableValue<T>>> cellValueFactoryProperty() {
398        if (cellValueFactory == null) {
399            cellValueFactory = new SimpleObjectProperty<Callback<CellDataFeatures<S,T>, ObservableValue<T>>>(this, "cellValueFactory");
400        }
401        return cellValueFactory;
402    }
403    
404    
405    // --- Cell Factory
406    /**
407     * The cell factory for all cells in this column. The cell factory
408     * is responsible for rendering the data contained within each TableCell for
409     * a single table column.
410     * 
411     * <p>By default TableColumn uses the {@link #DEFAULT_CELL_FACTORY default cell
412     * factory}, but this can be replaced with a custom implementation, for 
413     * example to show data in a different way or to support editing.There is a 
414     * lot of documentation on creating custom cell factories
415     * elsewhere (see {@link Cell} and {@link TableView} for example).</p>
416     *
417     * <p>Finally, there are a number of pre-built cell factories available in the
418     * {@link javafx.scene.control.cell} package.
419     */
420    private final ObjectProperty<Callback<TableColumn<S,T>, TableCell<S,T>>> cellFactory =
421        new SimpleObjectProperty<Callback<TableColumn<S,T>, TableCell<S,T>>>(
422            this, "cellFactory", (Callback<TableColumn<S,T>, TableCell<S,T>>) ((Callback) DEFAULT_CELL_FACTORY)) {
423                @Override protected void invalidated() {
424                    TableView table = getTableView();
425                    if (table == null) return;
426                    Map<Object,Object> properties = table.getProperties();
427                    if (properties.containsKey(TableViewSkinBase.RECREATE)) {
428                        properties.remove(TableViewSkinBase.RECREATE);
429                    }
430                    properties.put(TableViewSkinBase.RECREATE, Boolean.TRUE);
431                }
432            };
433
434    public final void setCellFactory(Callback<TableColumn<S,T>, TableCell<S,T>> value) {
435        cellFactory.set(value);
436    }
437
438    public final Callback<TableColumn<S,T>, TableCell<S,T>> getCellFactory() {
439        return cellFactory.get();
440    }
441
442    public final ObjectProperty<Callback<TableColumn<S,T>, TableCell<S,T>>> cellFactoryProperty() {
443        return cellFactory;
444    }
445
446    
447    
448    // --- Sort Type
449    /**
450     * Used to state whether this column, if it is part of a sort order (see
451     * {@link TableView#getSortOrder()} for more details), should be sorted in 
452     * ascending or descending order. 
453     * Simply toggling this property will result in the sort order changing in 
454     * the TableView, assuming of course that this column is in the 
455     * sortOrder ObservableList to begin with.
456     */
457    private ObjectProperty<SortType> sortType;
458    public final ObjectProperty<SortType> sortTypeProperty() {
459        if (sortType == null) {
460            sortType = new SimpleObjectProperty<SortType>(this, "sortType", SortType.ASCENDING);
461        }
462        return sortType;
463    }
464    public final void setSortType(SortType value) {
465        sortTypeProperty().set(value);
466    }
467    public final SortType getSortType() {
468        return sortType == null ? SortType.ASCENDING : sortType.get();
469    }
470    
471    
472    
473    // --- On Edit Start
474    private ObjectProperty<EventHandler<CellEditEvent<S,T>>> onEditStart;
475    public final void setOnEditStart(EventHandler<CellEditEvent<S,T>> value) {
476        onEditStartProperty().set(value);
477    }
478    public final EventHandler<CellEditEvent<S,T>> getOnEditStart() {
479        return onEditStart == null ? null : onEditStart.get();
480    }
481    /**
482     * This event handler will be fired when the user successfully initiates
483     * editing.
484     */
485    public final ObjectProperty<EventHandler<CellEditEvent<S,T>>> onEditStartProperty() {
486        if (onEditStart == null) {
487            onEditStart = new SimpleObjectProperty<EventHandler<CellEditEvent<S,T>>>(this, "onEditStart") {
488                @Override protected void invalidated() {
489                    eventHandlerManager.setEventHandler(TableColumn.<S,T>editStartEvent(), get());
490                }
491            };
492        }
493        return onEditStart;
494    }
495
496
497    // --- On Edit Commit
498    private ObjectProperty<EventHandler<CellEditEvent<S,T>>> onEditCommit;
499    public final void setOnEditCommit(EventHandler<CellEditEvent<S,T>> value) {
500        onEditCommitProperty().set(value);
501    }
502    public final EventHandler<CellEditEvent<S,T>> getOnEditCommit() {
503        return onEditCommit == null ? null : onEditCommit.get();
504    }
505    /**
506     * This event handler will be fired when the user successfully commits their
507     * editing.
508     */
509    public final ObjectProperty<EventHandler<CellEditEvent<S,T>>> onEditCommitProperty() {
510        if (onEditCommit == null) {
511            onEditCommit = new SimpleObjectProperty<EventHandler<CellEditEvent<S,T>>>(this, "onEditCommit") {
512                @Override protected void invalidated() {
513                    eventHandlerManager.setEventHandler(TableColumn.<S,T>editCommitEvent(), get());
514                }
515            };
516        }
517        return onEditCommit;
518    }
519
520
521    // --- On Edit Cancel
522    private ObjectProperty<EventHandler<CellEditEvent<S,T>>> onEditCancel;
523    public final void setOnEditCancel(EventHandler<CellEditEvent<S,T>> value) {
524        onEditCancelProperty().set(value);
525    }
526    public final EventHandler<CellEditEvent<S,T>> getOnEditCancel() {
527        return onEditCancel == null ? null : onEditCancel.get();
528    }
529    /**
530     * This event handler will be fired when the user cancels editing a cell.
531     */
532    public final ObjectProperty<EventHandler<CellEditEvent<S,T>>> onEditCancelProperty() {
533        if (onEditCancel == null) {
534            onEditCancel = new SimpleObjectProperty<EventHandler<CellEditEvent<S, T>>>(this, "onEditCancel") {
535                @Override protected void invalidated() {
536                    eventHandlerManager.setEventHandler(TableColumn.<S,T>editCancelEvent(), get());
537                }
538            };
539        }
540        return onEditCancel;
541    }
542
543    
544    
545    /***************************************************************************
546     *                                                                         *
547     * Public API                                                              *
548     *                                                                         *
549     **************************************************************************/    
550    
551    /** {@inheritDoc} */
552    @Override public final ObservableList<TableColumn<S,?>> getColumns() {
553        return columns;
554    }
555
556    /** {@inheritDoc} */
557    @Override public final ObservableValue<T> getCellObservableValue(int index) {
558        if (index < 0) return null;
559        
560        // Get the table
561        final TableView<S> table = getTableView();
562        if (table == null || table.getItems() == null) return null;
563        
564        // Get the rowData
565        final List<S> items = table.getItems();
566        if (index >= items.size()) return null; // Out of range
567        
568        final S rowData = items.get(index);
569        return getCellObservableValue(rowData);
570    }
571
572    /** {@inheritDoc} */
573    @Override public final ObservableValue<T> getCellObservableValue(S item) {
574        // Get the factory
575        final Callback<CellDataFeatures<S,T>, ObservableValue<T>> factory = getCellValueFactory();
576        if (factory == null) return null;
577        
578        // Get the table
579        final TableView<S> table = getTableView();
580        if (table == null) return null;
581        
582        // Call the factory
583        final CellDataFeatures<S,T> cdf = new CellDataFeatures<S,T>(table, this, item);
584        return factory.call(cdf);
585    }
586
587    
588    
589    /***************************************************************************
590     *                                                                         *
591     * Stylesheet Handling                                                     *
592     *                                                                         *
593     **************************************************************************/
594
595    private static final String DEFAULT_STYLE_CLASS = "table-column";
596
597    /**
598     * {@inheritDoc}
599     * @return "TableColumn"
600     */
601    @Override
602    public String getTypeSelector() {
603        return "TableColumn";
604    }
605
606    /**
607     * {@inheritDoc}
608     * @return {@code getTableView()}
609     */
610    @Override
611    public Styleable getStyleableParent() {
612        return getTableView();    }
613
614
615    /**
616     * {@inheritDoc}
617    */
618    @Override
619    public List<CssMetaData<? extends Styleable, ?>> getCssMetaData() {
620        return getClassCssMetaData();
621    }                
622
623   public static List<CssMetaData<? extends Styleable, ?>> getClassCssMetaData() {
624        return Collections.emptyList();
625    }                
626   
627    /**
628     * @treatAsPrivate implementation detail
629     * @deprecated This is an internal API that is not intended for use and will be removed in the next version
630     */
631    @Deprecated    
632    // SB-dependency: RT-21094 has been filed to track this   
633   public Node impl_styleableGetNode() {
634        if (! (getTableView().getSkin() instanceof TableViewSkin)) return null;
635        TableViewSkin<?> skin = (TableViewSkin<?>) getTableView().getSkin();
636
637        TableHeaderRow tableHeader = skin.getTableHeaderRow();
638        NestedTableColumnHeader rootHeader = tableHeader.getRootHeader();
639
640        // we now need to do a search for the header. We'll go depth-first.
641        return scan(rootHeader);
642    }
643
644    private TableColumnHeader scan(TableColumnHeader header) {
645        // firstly test that the parent isn't what we are looking for
646        if (TableColumn.this.equals(header.getTableColumn())) {
647            return header;
648        }
649
650        if (header instanceof NestedTableColumnHeader) {
651            NestedTableColumnHeader parent = (NestedTableColumnHeader) header;
652            for (int i = 0; i < parent.getColumnHeaders().size(); i++) {
653                TableColumnHeader result = scan(parent.getColumnHeaders().get(i));
654                if (result != null) {
655                    return result;
656                }
657            }
658        }
659
660        return null;
661    }
662
663    
664    
665    /***************************************************************************
666     *                                                                         *
667     * Support Interfaces                                                      *
668     *                                                                         *
669     **************************************************************************/
670
671    /**
672     * A support class used in TableColumn as a wrapper class 
673     * to provide all necessary information for a particular {@link Cell}. Once
674     * instantiated, this class is immutable.
675     * 
676     * @param <S> The TableView type
677     * @param <T> The TableColumn type
678     */
679    public static class CellDataFeatures<S,T> {
680        private final TableView<S> tableView;
681        private final TableColumn<S,T> tableColumn;
682        private final S value;
683
684        /**
685         * Instantiates a CellDataFeatures instance with the given properties
686         * set as read-only values of this instance.
687         * 
688         * @param tableView The TableView that this instance refers to.
689         * @param tableColumn The TableColumn that this instance refers to.
690         * @param value The value for a row in the TableView.
691         */
692        public CellDataFeatures(TableView<S> tableView,
693                TableColumn<S,T> tableColumn, S value) {
694            this.tableView = tableView;
695            this.tableColumn = tableColumn;
696            this.value = value;
697        }
698
699        /**
700         * Returns the value passed in to the constructor.
701         */
702        public S getValue() {
703            return value;
704        }
705
706        /**
707         * Returns the {@link TableColumn} passed in to the constructor.
708         */
709        public TableColumn<S,T> getTableColumn() {
710            return tableColumn;
711        }
712
713        /**
714         * Returns the {@link TableView} passed in to the constructor.
715         */
716        public TableView<S> getTableView() {
717            return tableView;
718        }
719    }
720    
721    
722    
723    /**
724     * An event that is fired when a user performs an edit on a table cell.
725     */
726    public static class CellEditEvent<S,T> extends Event {
727        private static final long serialVersionUID = -609964441682677579L;
728
729        /**
730         * Common supertype for all cell edit event types.
731         */
732        public static final EventType<?> ANY = EDIT_ANY_EVENT;
733
734        // represents the new value input by the end user. This is NOT the value
735        // to go back into the TableView.items list - this new value represents
736        // just the input for a single cell, so it is likely that it needs to go
737        // back into a property within an item in the TableView.items list.
738        private final T newValue;
739
740        // The location of the edit event
741        private transient final TablePosition<S,T> pos;
742
743        /**
744         * Creates a new event that can be subsequently fired to the relevant listeners.
745         *
746         * @param table The TableView on which this event occurred.
747         * @param pos The position upon which this event occurred.
748         * @param eventType The type of event that occurred.
749         * @param newValue The value input by the end user.
750         */
751        public CellEditEvent(TableView<S> table, TablePosition<S,T> pos,
752                EventType<CellEditEvent<S,T>> eventType, T newValue) {
753            super(table, Event.NULL_SOURCE_TARGET, eventType);
754
755            if (table == null) {
756                throw new NullPointerException("TableView can not be null");
757            }
758            if (pos == null) {
759                throw new NullPointerException("TablePosition can not be null");
760            }
761            this.pos = pos;
762            this.newValue = newValue;
763        }
764
765        /**
766         * Returns the TableView upon which this event occurred.
767         * @return The TableView control upon which this event occurred.
768         */
769        public TableView<S> getTableView() {
770            return pos.getTableView();
771        }
772
773        /**
774         * Returns the TableColumn upon which this event occurred.
775         *
776         * @return The TableColumn that the edit occurred in.
777         */
778        public TableColumn<S,T> getTableColumn() {
779            return pos.getTableColumn();
780        }
781
782        /**
783         * Returns the position upon which this event occurred.
784         * @return The position upon which this event occurred.
785         */
786        public TablePosition<S,T> getTablePosition() {
787            return pos;
788        }
789
790        /**
791         * Returns the new value input by the end user. This is <b>not</b> the value
792         * to go back into the TableView.items list - this new value represents
793         * just the input for a single cell, so it is likely that it needs to go
794         * back into a property within an item in the TableView.items list.
795         *
796         * @return An Object representing the new value input by the user.
797         */
798        public T getNewValue() {
799            return newValue;
800        }
801
802        /**
803         * Attempts to return the old value at the position referred to in the
804         * TablePosition returned by {@link #getTablePosition()}. This may return
805         * null for a number of reasons.
806         *
807         * @return Returns the value stored in the position being edited, or null
808         *     if it can not be retrieved.
809         */
810        public T getOldValue() {
811            S rowData = getRowValue();
812            if (rowData == null || pos.getTableColumn() == null) {
813                return null;
814            }
815
816            // if we are here, we now need to get the data for the specific column
817            return (T) pos.getTableColumn().getCellData(rowData);
818        }
819        
820        /**
821         * Convenience method that returns the value for the row (that is, from
822         * the TableView {@link TableView#itemsProperty() items} list), for the
823         * row contained within the {@link TablePosition} returned in
824         * {@link #getTablePosition()}.
825         */
826        public S getRowValue() {
827            List<S> items = getTableView().getItems();
828            if (items == null) return null;
829
830            int row = pos.getRow();
831            if (row < 0 || row >= items.size()) return null;
832
833            return items.get(row);
834        }
835    }
836    
837    /**
838     * Enumeration that specifies the type of sorting being applied to a specific
839     * column.
840     */
841    public static enum SortType {
842        /**
843         * Column will be sorted in an ascending order.
844         */
845        ASCENDING,
846        
847        /**
848         * Column will be sorted in a descending order.
849         */
850        DESCENDING;
851        
852        // UNSORTED
853    }
854}