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