< prev index next >

modules/javafx.controls/src/main/java/javafx/scene/control/TableView.java

Print this page




  90  * <ul>
  91  * <li>Powerful {@link TableColumn} API:
  92  *   <ul>
  93  *   <li>Support for {@link TableColumn#cellFactoryProperty() cell factories} to
  94  *      easily customize {@link Cell cell} contents in both rendering and editing
  95  *      states.
  96  *   <li>Specification of {@link TableColumn#minWidthProperty() minWidth}/
  97  *      {@link TableColumn#prefWidthProperty() prefWidth}/
  98  *      {@link TableColumn#maxWidthProperty() maxWidth},
  99  *      and also {@link TableColumn#resizableProperty() fixed width columns}.
 100  *   <li>Width resizing by the user at runtime.
 101  *   <li>Column reordering by the user at runtime.
 102  *   <li>Built-in support for {@link TableColumn#getColumns() column nesting}
 103  *   </ul>
 104  * <li>Different {@link #columnResizePolicyProperty() resizing policies} to
 105  *      dictate what happens when the user resizes columns.
 106  * <li>Support for {@link #getSortOrder() multiple column sorting} by clicking
 107  *      the column header (hold down Shift keyboard key whilst clicking on a
 108  *      header to sort by multiple columns).
 109  * </ul>
 110  * </p>
 111  *
 112  * <p>Note that TableView is intended to be used to visualize data - it is not
 113  * intended to be used for laying out your user interface. If you want to lay
 114  * your user interface out in a grid-like fashion, consider the
 115  * {@link javafx.scene.layout.GridPane} layout instead.</p>
 116  *
 117  * <h2>Creating a TableView</h2>
 118  *
 119  * <p>Creating a TableView is a multi-step process, and also depends on the

 120  * underlying data model needing to be represented. For this example we'll use
 121  * an ObservableList<Person>, as it is the simplest way of showing data in a
 122  * TableView. The <code>Person</code> class will consist of a first
 123  * name and last name properties. That is:
 124  *
 125  * <pre>
 126  * {@code
 127  * public class Person {
 128  *     private StringProperty firstName;
 129  *     public void setFirstName(String value) { firstNameProperty().set(value); }
 130  *     public String getFirstName() { return firstNameProperty().get(); }
 131  *     public StringProperty firstNameProperty() {
 132  *         if (firstName == null) firstName = new SimpleStringProperty(this, "firstName");
 133  *         return firstName;
 134  *     }
 135  *
 136  *     private StringProperty lastName;
 137  *     public void setLastName(String value) { lastNameProperty().set(value); }
 138  *     public String getLastName() { return lastNameProperty().get(); }
 139  *     public StringProperty lastNameProperty() {
 140  *         if (lastName == null) lastName = new SimpleStringProperty(this, "lastName");
 141  *         return lastName;
 142  *     }
 143  * }}</pre>
 144  *
 145  * <p>Firstly, a TableView instance needs to be defined, as such:
 146  *
 147  * <pre>
 148  * {@code
 149  * TableView<Person> table = new TableView<Person>();}</pre>
 150  *

 151  * <p>With the basic table defined, we next focus on the data model. As mentioned,
 152  * for this example, we'll be using a ObservableList<Person>. We can immediately
 153  * set such a list directly in to the TableView, as such:
 154  *
 155  * <pre>
 156  * {@code
 157  * ObservableList<Person> teamMembers = getTeamMembers();
 158  * table.setItems(teamMembers);}</pre>
 159  *
 160  * <p>With the items set as such, TableView will automatically update whenever
 161  * the <code>teamMembers</code> list changes. If the items list is available
 162  * before the TableView is instantiated, it is possible to pass it directly into
 163  * the constructor.
 164  *
 165  * <p>At this point we now have a TableView hooked up to observe the
 166  * <code>teamMembers</code> observableList. The missing ingredient
 167  * now is the means of splitting out the data contained within the model and
 168  * representing it in one or more {@link TableColumn TableColumn} instances. To
 169  * create a two-column TableView to show the firstName and lastName properties,
 170  * we extend the last code sample as follows:
 171  *
 172  * <pre>
 173  * {@code


 817 
 818     private final WeakListChangeListener<TableColumn<S,?>> weakColumnsObserver =
 819             new WeakListChangeListener<TableColumn<S,?>>(columnsObserver);
 820 
 821     private final WeakInvalidationListener weakCellSelectionModelInvalidationListener =
 822             new WeakInvalidationListener(cellSelectionModelInvalidationListener);
 823 
 824 
 825 
 826     /***************************************************************************
 827      *                                                                         *
 828      * Properties                                                              *
 829      *                                                                         *
 830      **************************************************************************/
 831 
 832 
 833     // --- Items
 834     /**
 835      * The underlying data model for the TableView. Note that it has a generic
 836      * type that must match the type of the TableView itself.

 837      */
 838     public final ObjectProperty<ObservableList<S>> itemsProperty() { return items; }
 839     private ObjectProperty<ObservableList<S>> items =
 840         new SimpleObjectProperty<ObservableList<S>>(this, "items") {
 841             WeakReference<ObservableList<S>> oldItemsRef;
 842 
 843             @Override protected void invalidated() {
 844                 final ObservableList<S> oldItems = oldItemsRef == null ? null : oldItemsRef.get();
 845                 final ObservableList<S> newItems = getItems();
 846 
 847                 // Fix for RT-36425
 848                 if (newItems != null && newItems == oldItems) {
 849                     return;
 850                 }
 851 
 852                 // Fix for RT-35763
 853                 if (! (newItems instanceof SortedList)) {
 854                     getSortOrder().clear();
 855                 }
 856 
 857                 oldItemsRef = new WeakReference<>(newItems);
 858             }
 859         };
 860     public final void setItems(ObservableList<S> value) { itemsProperty().set(value); }
 861     public final ObservableList<S> getItems() {return items.get(); }
 862 
 863 
 864     // --- Table menu button visible
 865     private BooleanProperty tableMenuButtonVisible;
 866     /**
 867      * This controls whether a menu button is available when the user clicks
 868      * in a designated space within the TableView, within which is a radio menu
 869      * item for each TableColumn in this table. This menu allows for the user to
 870      * show and hide all TableColumns easily.

 871      */
 872     public final BooleanProperty tableMenuButtonVisibleProperty() {
 873         if (tableMenuButtonVisible == null) {
 874             tableMenuButtonVisible = new SimpleBooleanProperty(this, "tableMenuButtonVisible");
 875         }
 876         return tableMenuButtonVisible;
 877     }
 878     public final void setTableMenuButtonVisible (boolean value) {
 879         tableMenuButtonVisibleProperty().set(value);
 880     }
 881     public final boolean isTableMenuButtonVisible() {
 882         return tableMenuButtonVisible == null ? false : tableMenuButtonVisible.get();
 883     }
 884 
 885 
 886     // --- Column Resize Policy
 887     private ObjectProperty<Callback<ResizeFeatures, Boolean>> columnResizePolicy;
 888     public final void setColumnResizePolicy(Callback<ResizeFeatures, Boolean> callback) {
 889         columnResizePolicyProperty().set(callback);
 890     }
 891     public final Callback<ResizeFeatures, Boolean> getColumnResizePolicy() {
 892         return columnResizePolicy == null ? UNCONSTRAINED_RESIZE_POLICY : columnResizePolicy.get();
 893     }
 894 
 895     /**
 896      * This is the function called when the user completes a column-resize
 897      * operation. The two most common policies are available as static functions
 898      * in the TableView class: {@link #UNCONSTRAINED_RESIZE_POLICY} and
 899      * {@link #CONSTRAINED_RESIZE_POLICY}.

 900      */
 901     public final ObjectProperty<Callback<ResizeFeatures, Boolean>> columnResizePolicyProperty() {
 902         if (columnResizePolicy == null) {
 903             columnResizePolicy = new SimpleObjectProperty<Callback<ResizeFeatures, Boolean>>(this, "columnResizePolicy", UNCONSTRAINED_RESIZE_POLICY) {
 904                 private Callback<ResizeFeatures, Boolean> oldPolicy;
 905 
 906                 @Override protected void invalidated() {
 907                     if (isInited) {
 908                         get().call(new ResizeFeatures(TableView.this, null, 0.0));
 909 
 910                         if (oldPolicy != null) {
 911                             PseudoClass state = PseudoClass.getPseudoClass(oldPolicy.toString());
 912                             pseudoClassStateChanged(state, false);
 913                         }
 914                         if (get() != null) {
 915                             PseudoClass state = PseudoClass.getPseudoClass(get().toString());
 916                             pseudoClassStateChanged(state, true);
 917                         }
 918                         oldPolicy = get();
 919                     }


 924     }
 925 
 926 
 927     // --- Row Factory
 928     private ObjectProperty<Callback<TableView<S>, TableRow<S>>> rowFactory;
 929 
 930     /**
 931      * A function which produces a TableRow. The system is responsible for
 932      * reusing TableRows. Return from this function a TableRow which
 933      * might be usable for representing a single row in a TableView.
 934      * <p>
 935      * Note that a TableRow is <b>not</b> a TableCell. A TableRow is
 936      * simply a container for a TableCell, and in most circumstances it is more
 937      * likely that you'll want to create custom TableCells, rather than
 938      * TableRows. The primary use case for creating custom TableRow
 939      * instances would most probably be to introduce some form of column
 940      * spanning support.
 941      * <p>
 942      * You can create custom TableCell instances per column by assigning the
 943      * appropriate function to the cellFactory property in the TableColumn class.

 944      */
 945     public final ObjectProperty<Callback<TableView<S>, TableRow<S>>> rowFactoryProperty() {
 946         if (rowFactory == null) {
 947             rowFactory = new SimpleObjectProperty<Callback<TableView<S>, TableRow<S>>>(this, "rowFactory");
 948         }
 949         return rowFactory;
 950     }
 951     public final void setRowFactory(Callback<TableView<S>, TableRow<S>> value) {
 952         rowFactoryProperty().set(value);
 953     }
 954     public final Callback<TableView<S>, TableRow<S>> getRowFactory() {
 955         return rowFactory == null ? null : rowFactory.get();
 956     }
 957 
 958 
 959     // --- Placeholder Node
 960     private ObjectProperty<Node> placeholder;
 961     /**
 962      * This Node is shown to the user when the table has no content to show.
 963      * This may be the case because the table model has no data in the first
 964      * place, that a filter has been applied to the table model, resulting
 965      * in there being nothing to show the user, or that there are no currently
 966      * visible columns.

 967      */
 968     public final ObjectProperty<Node> placeholderProperty() {
 969         if (placeholder == null) {
 970             placeholder = new SimpleObjectProperty<Node>(this, "placeholder");
 971         }
 972         return placeholder;
 973     }
 974     public final void setPlaceholder(Node value) {
 975         placeholderProperty().set(value);
 976     }
 977     public final Node getPlaceholder() {
 978         return placeholder == null ? null : placeholder.get();
 979     }
 980 
 981 
 982     // --- Selection Model
 983     private ObjectProperty<TableViewSelectionModel<S>> selectionModel
 984             = new SimpleObjectProperty<TableViewSelectionModel<S>>(this, "selectionModel") {
 985 
 986         TableViewSelectionModel<S> oldValue = null;


 993                 if (oldValue instanceof TableViewArrayListSelectionModel) {
 994                     ((TableViewArrayListSelectionModel)oldValue).dispose();
 995                 }
 996             }
 997 
 998             oldValue = get();
 999 
1000             if (oldValue != null) {
1001                 oldValue.cellSelectionEnabledProperty().addListener(weakCellSelectionModelInvalidationListener);
1002                 // fake an invalidation to ensure updated pseudo-class state
1003                 weakCellSelectionModelInvalidationListener.invalidated(oldValue.cellSelectionEnabledProperty());
1004             }
1005         }
1006     };
1007 
1008     /**
1009      * The SelectionModel provides the API through which it is possible
1010      * to select single or multiple items within a TableView, as  well as inspect
1011      * which items have been selected by the user. Note that it has a generic
1012      * type that must match the type of the TableView itself.

1013      */
1014     public final ObjectProperty<TableViewSelectionModel<S>> selectionModelProperty() {
1015         return selectionModel;
1016     }
1017     public final void setSelectionModel(TableViewSelectionModel<S> value) {
1018         selectionModelProperty().set(value);
1019     }
1020 
1021     public final TableViewSelectionModel<S> getSelectionModel() {
1022         return selectionModel.get();
1023     }
1024 
1025 
1026     // --- Focus Model
1027     private ObjectProperty<TableViewFocusModel<S>> focusModel;
1028     public final void setFocusModel(TableViewFocusModel<S> value) {
1029         focusModelProperty().set(value);
1030     }
1031     public final TableViewFocusModel<S> getFocusModel() {
1032         return focusModel == null ? null : focusModel.get();
1033     }
1034     /**
1035      * Represents the currently-installed {@link TableViewFocusModel} for this
1036      * TableView. Under almost all circumstances leaving this as the default
1037      * focus model will suffice.

1038      */
1039     public final ObjectProperty<TableViewFocusModel<S>> focusModelProperty() {
1040         if (focusModel == null) {
1041             focusModel = new SimpleObjectProperty<TableViewFocusModel<S>>(this, "focusModel");
1042         }
1043         return focusModel;
1044     }
1045 
1046 
1047 //    // --- Span Model
1048 //    private ObjectProperty<SpanModel<S>> spanModel
1049 //            = new SimpleObjectProperty<SpanModel<S>>(this, "spanModel") {
1050 //
1051 //        @Override protected void invalidated() {
1052 //            ObservableList<String> styleClass = getStyleClass();
1053 //            if (getSpanModel() == null) {
1054 //                styleClass.remove(CELL_SPAN_TABLE_VIEW_STYLE_CLASS);
1055 //            } else if (! styleClass.contains(CELL_SPAN_TABLE_VIEW_STYLE_CLASS)) {
1056 //                styleClass.add(CELL_SPAN_TABLE_VIEW_STYLE_CLASS);
1057 //            }


1064 //    public final void setSpanModel(SpanModel<S> value) {
1065 //        spanModelProperty().set(value);
1066 //    }
1067 //
1068 //    public final SpanModel<S> getSpanModel() {
1069 //        return spanModel.get();
1070 //    }
1071 
1072     // --- Editable
1073     private BooleanProperty editable;
1074     public final void setEditable(boolean value) {
1075         editableProperty().set(value);
1076     }
1077     public final boolean isEditable() {
1078         return editable == null ? false : editable.get();
1079     }
1080     /**
1081      * Specifies whether this TableView is editable - only if the TableView, the
1082      * TableColumn (if applicable) and the TableCells within it are both
1083      * editable will a TableCell be able to go into their editing state.

1084      */
1085     public final BooleanProperty editableProperty() {
1086         if (editable == null) {
1087             editable = new SimpleBooleanProperty(this, "editable", false);
1088         }
1089         return editable;
1090     }
1091 
1092 
1093     // --- Fixed cell size
1094     private DoubleProperty fixedCellSize;
1095 
1096     /**
1097      * Sets the new fixed cell size for this control. Any value greater than
1098      * zero will enable fixed cell size mode, whereas a zero or negative value
1099      * (or Region.USE_COMPUTED_SIZE) will be used to disabled fixed cell size
1100      * mode.
1101      *
1102      * @param value The new fixed cell size value, or a value less than or equal
1103      *              to zero (or Region.USE_COMPUTED_SIZE) to disable.


1121     }
1122     /**
1123      * Specifies whether this control has cells that are a fixed height (of the
1124      * specified value). If this value is less than or equal to zero,
1125      * then all cells are individually sized and positioned. This is a slow
1126      * operation. Therefore, when performance matters and developers are not
1127      * dependent on variable cell sizes it is a good idea to set the fixed cell
1128      * size value. Generally cells are around 24px, so setting a fixed cell size
1129      * of 24 is likely to result in very little difference in visuals, but a
1130      * improvement to performance.
1131      *
1132      * <p>To set this property via CSS, use the -fx-fixed-cell-size property.
1133      * This should not be confused with the -fx-cell-size property. The difference
1134      * between these two CSS properties is that -fx-cell-size will size all
1135      * cells to the specified size, but it will not enforce that this is the
1136      * only size (thus allowing for variable cell sizes, and preventing the
1137      * performance gains from being possible). Therefore, when performance matters
1138      * use -fx-fixed-cell-size, instead of -fx-cell-size. If both properties are
1139      * specified in CSS, -fx-fixed-cell-size takes precedence.</p>
1140      *

1141      * @since JavaFX 8.0
1142      */
1143     public final DoubleProperty fixedCellSizeProperty() {
1144         if (fixedCellSize == null) {
1145             fixedCellSize = new StyleableDoubleProperty(Region.USE_COMPUTED_SIZE) {
1146                 @Override public CssMetaData<TableView<?>,Number> getCssMetaData() {
1147                     return StyleableProperties.FIXED_CELL_SIZE;
1148                 }
1149 
1150                 @Override public Object getBean() {
1151                     return TableView.this;
1152                 }
1153 
1154                 @Override public String getName() {
1155                     return "fixedCellSize";
1156                 }
1157             };
1158         }
1159         return fixedCellSize;
1160     }
1161 
1162 
1163     // --- Editing Cell
1164     private ReadOnlyObjectWrapper<TablePosition<S,?>> editingCell;
1165     private void setEditingCell(TablePosition<S,?> value) {
1166         editingCellPropertyImpl().set(value);
1167     }
1168     public final TablePosition<S,?> getEditingCell() {
1169         return editingCell == null ? null : editingCell.get();
1170     }
1171 
1172     /**
1173      * Represents the current cell being edited, or null if
1174      * there is no cell being edited.

1175      */
1176     public final ReadOnlyObjectProperty<TablePosition<S,?>> editingCellProperty() {
1177         return editingCellPropertyImpl().getReadOnlyProperty();
1178     }
1179 
1180     private ReadOnlyObjectWrapper<TablePosition<S,?>> editingCellPropertyImpl() {
1181         if (editingCell == null) {
1182             editingCell = new ReadOnlyObjectWrapper<TablePosition<S,?>>(this, "editingCell");
1183         }
1184         return editingCell;
1185     }
1186 
1187 
1188     // --- Comparator (built via sortOrder list, so read-only)
1189     /**
1190      * The comparator property is a read-only property that is representative of the
1191      * current state of the {@link #getSortOrder() sort order} list. The sort
1192      * order list contains the columns that have been added to it either programmatically
1193      * or via a user clicking on the headers themselves.
1194      * @since JavaFX 8.0


1286                     return "onSort";
1287                 }
1288             };
1289         }
1290         return onSort;
1291     }
1292 
1293 
1294     /***************************************************************************
1295      *                                                                         *
1296      * Public API                                                              *
1297      *                                                                         *
1298      **************************************************************************/
1299     /**
1300      * The TableColumns that are part of this TableView. As the user reorders
1301      * the TableView columns, this list will be updated to reflect the current
1302      * visual ordering.
1303      *
1304      * <p>Note: to display any data in a TableView, there must be at least one
1305      * TableColumn in this ObservableList.</p>

1306      */
1307     public final ObservableList<TableColumn<S,?>> getColumns() {
1308         return columns;
1309     }
1310 
1311     /**
1312      * The sortOrder list defines the order in which {@link TableColumn} instances
1313      * are sorted. An empty sortOrder list means that no sorting is being applied
1314      * on the TableView. If the sortOrder list has one TableColumn within it,
1315      * the TableView will be sorted using the
1316      * {@link TableColumn#sortTypeProperty() sortType} and
1317      * {@link TableColumn#comparatorProperty() comparator} properties of this
1318      * TableColumn (assuming
1319      * {@link TableColumn#sortableProperty() TableColumn.sortable} is true).
1320      * If the sortOrder list contains multiple TableColumn instances, then
1321      * the TableView is firstly sorted based on the properties of the first
1322      * TableColumn. If two elements are considered equal, then the second
1323      * TableColumn in the list is used to determine ordering. This repeats until
1324      * the results from all TableColumn comparators are considered, if necessary.
1325      *


1434                 @Override protected void invalidated() {
1435                     EventType<ScrollToEvent<TableColumn<S, ?>>> type = ScrollToEvent.scrollToColumn();
1436                     setEventHandler(type, get());
1437                 }
1438 
1439                 @Override public Object getBean() {
1440                     return TableView.this;
1441                 }
1442 
1443                 @Override public String getName() {
1444                     return "onScrollToColumn";
1445                 }
1446             };
1447         }
1448         return onScrollToColumn;
1449     }
1450 
1451     /**
1452      * Applies the currently installed resize policy against the given column,
1453      * resizing it based on the delta value provided.



1454      */
1455     public boolean resizeColumn(TableColumn<S,?> column, double delta) {
1456         if (column == null || Double.compare(delta, 0.0) == 0) return false;
1457 
1458         boolean allowed = getColumnResizePolicy().call(new ResizeFeatures<S>(TableView.this, column, delta));
1459         if (!allowed) return false;
1460 
1461         return true;
1462     }
1463 
1464     /**
1465      * Causes the cell at the given row/column view indexes to switch into
1466      * its editing state, if it is not already in it, and assuming that the
1467      * TableView and column are also editable.
1468      *
1469      * <p><strong>Note:</strong> This method will cancel editing if the given row
1470      * value is less than zero and the given column is null.</p>


1471      */
1472     public void edit(int row, TableColumn<S,?> column) {
1473         if (!isEditable() || (column != null && ! column.isEditable())) {
1474             return;
1475         }
1476 
1477         if (row < 0 && column == null) {
1478             setEditingCell(null);
1479         } else {
1480             setEditingCell(new TablePosition<>(this, row, column));
1481         }
1482     }
1483 
1484     /**
1485      * Returns an unmodifiable list containing the currently visible leaf columns.

1486      */
1487     public ObservableList<TableColumn<S,?>> getVisibleLeafColumns() {
1488         return unmodifiableVisibleLeafColumns;
1489     }
1490 
1491     /**
1492      * Returns the position of the given column, relative to all other
1493      * visible leaf columns.



1494      */
1495     public int getVisibleLeafIndex(TableColumn<S,?> column) {
1496         return visibleLeafColumns.indexOf(column);
1497     }
1498 
1499     /**
1500      * Returns the TableColumn in the given column index, relative to all other
1501      * visible leaf columns.



1502      */
1503     public TableColumn<S,?> getVisibleLeafColumn(int column) {
1504         if (column < 0 || column >= visibleLeafColumns.size()) return null;
1505         return visibleLeafColumns.get(column);
1506     }
1507 
1508     /** {@inheritDoc} */
1509     @Override protected Skin<?> createDefaultSkin() {
1510         return new TableViewSkin<S>(this);
1511     }
1512 
1513     /**
1514      * The sort method forces the TableView to re-run its sorting algorithm. More
1515      * often than not it is not necessary to call this method directly, as it is
1516      * automatically called when the {@link #getSortOrder() sort order},
1517      * {@link #sortPolicyProperty() sort policy}, or the state of the
1518      * TableColumn {@link TableColumn#sortTypeProperty() sort type} properties
1519      * change. In other words, this method should only be called directly when
1520      * something external changes and a sort is required.
1521      * @since JavaFX 8.0


1808          *      TableView resize operation.
1809          * @param delta The amount of horizontal space added or removed in the
1810          *      resize operation.
1811          */
1812         public ResizeFeatures(TableView<S> table, TableColumn<S,?> column, Double delta) {
1813             super(column, delta);
1814             this.table = table;
1815         }
1816 
1817         /**
1818          * Returns the column upon which the resize is occurring, or null
1819          * if this ResizeFeatures instance was created as a result of a
1820          * TableView resize operation.
1821          */
1822         @Override public TableColumn<S,?> getColumn() {
1823             return (TableColumn<S,?>) super.getColumn();
1824         }
1825 
1826         /**
1827          * Returns the TableView upon which the resize operation is occurring.

1828          */
1829         public TableView<S> getTable() {
1830             return table;
1831         }
1832     }
1833 
1834 
1835 
1836     /***************************************************************************
1837      *                                                                         *
1838      * Support Classes                                                         *
1839      *                                                                         *
1840      **************************************************************************/
1841 
1842 
1843     /**
1844      * A simple extension of the {@link SelectionModel} abstract class to
1845      * allow for special support for TableView controls.
1846      * @since JavaFX 2.0
1847      */


1875         public TableViewSelectionModel(final TableView<S> tableView) {
1876             if (tableView == null) {
1877                 throw new NullPointerException("TableView can not be null");
1878             }
1879 
1880             this.tableView = tableView;
1881         }
1882 
1883 
1884 
1885         /***********************************************************************
1886          *                                                                     *
1887          * Abstract API                                                        *
1888          *                                                                     *
1889          **********************************************************************/
1890 
1891         /**
1892          * A read-only ObservableList representing the currently selected cells
1893          * in this TableView. Rather than directly modify this list, please
1894          * use the other methods provided in the TableViewSelectionModel.


1895          */
1896         public abstract ObservableList<TablePosition> getSelectedCells();
1897 
1898 
1899         /***********************************************************************
1900          *                                                                     *
1901          * Generic (type erasure) bridging                                     *
1902          *                                                                     *
1903          **********************************************************************/
1904 
1905         // --- isSelected
1906         /** {@inheritDoc} */
1907         @Override public boolean isSelected(int row, TableColumnBase<S, ?> column) {
1908             return isSelected(row, (TableColumn<S,?>)column);
1909         }
1910 
1911         /**
1912          * Convenience function which tests whether the given row and column index
1913          * is currently selected in this table instance.



1914          */
1915         public abstract boolean isSelected(int row, TableColumn<S, ?> column);
1916 
1917 
1918         // --- select
1919         /** {@inheritDoc} */
1920         @Override public void select(int row, TableColumnBase<S, ?> column) {
1921             select(row, (TableColumn<S,?>)column);
1922         }
1923 
1924         /**
1925          * Selects the cell at the given row/column intersection.


1926          */
1927         public abstract void select(int row, TableColumn<S, ?> column);
1928 
1929 
1930         // --- clearAndSelect
1931         /** {@inheritDoc} */
1932         @Override public void clearAndSelect(int row, TableColumnBase<S,?> column) {
1933             clearAndSelect(row, (TableColumn<S,?>) column);
1934         }
1935 
1936         /**
1937          * Clears all selection, and then selects the cell at the given row/column
1938          * intersection.


1939          */
1940         public abstract void clearAndSelect(int row, TableColumn<S,?> column);
1941 
1942 
1943         // --- clearSelection
1944         /** {@inheritDoc} */
1945         @Override public void clearSelection(int row, TableColumnBase<S,?> column) {
1946             clearSelection(row, (TableColumn<S,?>) column);
1947         }
1948 
1949         /**
1950          * Removes selection from the specified row/column position (in view indexes).
1951          * If this particular cell (or row if the column value is -1) is not selected,
1952          * nothing happens.


1953          */
1954         public abstract void clearSelection(int row, TableColumn<S, ?> column);
1955 
1956         /** {@inheritDoc} */
1957         @Override public void selectRange(int minRow, TableColumnBase<S,?> minColumn,
1958                                           int maxRow, TableColumnBase<S,?> maxColumn) {
1959             final int minColumnIndex = tableView.getVisibleLeafIndex((TableColumn<S,?>)minColumn);
1960             final int maxColumnIndex = tableView.getVisibleLeafIndex((TableColumn<S,?>)maxColumn);
1961             for (int _row = minRow; _row <= maxRow; _row++) {
1962                 for (int _col = minColumnIndex; _col <= maxColumnIndex; _col++) {
1963                     select(_row, tableView.getVisibleLeafColumn(_col));
1964                 }
1965             }
1966         }
1967 
1968 
1969 
1970         /***********************************************************************
1971          *                                                                     *
1972          * Public API                                                          *
1973          *                                                                     *
1974          **********************************************************************/
1975 
1976         /**
1977          * Returns the TableView instance that this selection model is installed in.

1978          */
1979         public TableView<S> getTableView() {
1980             return tableView;
1981         }
1982 
1983         /**
1984          * Convenience method that returns getTableView().getItems().
1985          * @return The items list of the current TableView.
1986          */
1987         protected List<S> getTableModel()  {
1988             return tableView.getItems();
1989         }
1990 
1991         /** {@inheritDoc} */
1992         @Override protected S getModelItem(int index) {
1993             if (index < 0 || index >= getItemCount()) return null;
1994             return tableView.getItems().get(index);
1995         }
1996 
1997         /** {@inheritDoc} */


3201          *                                                                     *
3202          **********************************************************************/
3203 
3204         /**
3205          * Tests whether the row / cell at the given location currently has the
3206          * focus within the TableView.
3207          */
3208         @Override public boolean isFocused(int row, TableColumn<S,?> column) {
3209             if (row < 0 || row >= getItemCount()) return false;
3210 
3211             TablePosition cell = getFocusedCell();
3212             boolean columnMatch = column == null || column.equals(cell.getTableColumn());
3213 
3214             return cell.getRow() == row && columnMatch;
3215         }
3216 
3217         /**
3218          * Causes the item at the given index to receive the focus. This does not
3219          * cause the current selection to change. Updates the focusedItem and
3220          * focusedIndex properties such that <code>focusedIndex = -1</code> unless
3221          * <pre><code>0 <= index < model size</code></pre>.
3222          *
3223          * @param index The index of the item to get focus.
3224          */
3225         @Override public void focus(int index) {
3226             if (index < 0 || index >= getItemCount()) {
3227                 setFocusedCell(EMPTY_CELL);
3228             } else {
3229                 setFocusedCell(new TablePosition<>(tableView, index, null));
3230             }
3231         }
3232 
3233         /**
3234          * Attempts to move focus to the cell above the currently focused cell.
3235          */
3236         @Override public void focusAboveCell() {
3237             TablePosition cell = getFocusedCell();
3238 
3239             if (getFocusedIndex() == -1) {
3240                 focus(getItemCount() - 1, cell.getTableColumn());
3241             } else if (getFocusedIndex() > 0) {




  90  * <ul>
  91  * <li>Powerful {@link TableColumn} API:
  92  *   <ul>
  93  *   <li>Support for {@link TableColumn#cellFactoryProperty() cell factories} to
  94  *      easily customize {@link Cell cell} contents in both rendering and editing
  95  *      states.
  96  *   <li>Specification of {@link TableColumn#minWidthProperty() minWidth}/
  97  *      {@link TableColumn#prefWidthProperty() prefWidth}/
  98  *      {@link TableColumn#maxWidthProperty() maxWidth},
  99  *      and also {@link TableColumn#resizableProperty() fixed width columns}.
 100  *   <li>Width resizing by the user at runtime.
 101  *   <li>Column reordering by the user at runtime.
 102  *   <li>Built-in support for {@link TableColumn#getColumns() column nesting}
 103  *   </ul>
 104  * <li>Different {@link #columnResizePolicyProperty() resizing policies} to
 105  *      dictate what happens when the user resizes columns.
 106  * <li>Support for {@link #getSortOrder() multiple column sorting} by clicking
 107  *      the column header (hold down Shift keyboard key whilst clicking on a
 108  *      header to sort by multiple columns).
 109  * </ul>

 110  *
 111  * <p>Note that TableView is intended to be used to visualize data - it is not
 112  * intended to be used for laying out your user interface. If you want to lay
 113  * your user interface out in a grid-like fashion, consider the
 114  * {@link javafx.scene.layout.GridPane} layout instead.</p>
 115  *
 116  * <h2>Creating a TableView</h2>
 117  *
 118  * <p>
 119  * {@literal Creating a TableView is a multi-step process, and also depends on the
 120  * underlying data model needing to be represented. For this example we'll use
 121  * an ObservableList<Person>, as it is the simplest way of showing data in a
 122  * TableView. The <code>Person</code> class will consist of a first
 123  * name and last name properties. That is:}
 124  *
 125  * <pre>
 126  * {@code
 127  * public class Person {
 128  *     private StringProperty firstName;
 129  *     public void setFirstName(String value) { firstNameProperty().set(value); }
 130  *     public String getFirstName() { return firstNameProperty().get(); }
 131  *     public StringProperty firstNameProperty() {
 132  *         if (firstName == null) firstName = new SimpleStringProperty(this, "firstName");
 133  *         return firstName;
 134  *     }
 135  *
 136  *     private StringProperty lastName;
 137  *     public void setLastName(String value) { lastNameProperty().set(value); }
 138  *     public String getLastName() { return lastNameProperty().get(); }
 139  *     public StringProperty lastNameProperty() {
 140  *         if (lastName == null) lastName = new SimpleStringProperty(this, "lastName");
 141  *         return lastName;
 142  *     }
 143  * }}</pre>
 144  *
 145  * <p>Firstly, a TableView instance needs to be defined, as such:
 146  *
 147  * <pre>
 148  * {@code
 149  * TableView<Person> table = new TableView<Person>();}</pre>
 150  *
 151  * {@literal
 152  * <p>With the basic table defined, we next focus on the data model. As mentioned,
 153  * for this example, we'll be using a ObservableList<Person>. We can immediately
 154  * set such a list directly in to the TableView, as such:}
 155  *
 156  * <pre>
 157  * {@code
 158  * ObservableList<Person> teamMembers = getTeamMembers();
 159  * table.setItems(teamMembers);}</pre>
 160  *
 161  * <p>With the items set as such, TableView will automatically update whenever
 162  * the <code>teamMembers</code> list changes. If the items list is available
 163  * before the TableView is instantiated, it is possible to pass it directly into
 164  * the constructor.
 165  *
 166  * <p>At this point we now have a TableView hooked up to observe the
 167  * <code>teamMembers</code> observableList. The missing ingredient
 168  * now is the means of splitting out the data contained within the model and
 169  * representing it in one or more {@link TableColumn TableColumn} instances. To
 170  * create a two-column TableView to show the firstName and lastName properties,
 171  * we extend the last code sample as follows:
 172  *
 173  * <pre>
 174  * {@code


 818 
 819     private final WeakListChangeListener<TableColumn<S,?>> weakColumnsObserver =
 820             new WeakListChangeListener<TableColumn<S,?>>(columnsObserver);
 821 
 822     private final WeakInvalidationListener weakCellSelectionModelInvalidationListener =
 823             new WeakInvalidationListener(cellSelectionModelInvalidationListener);
 824 
 825 
 826 
 827     /***************************************************************************
 828      *                                                                         *
 829      * Properties                                                              *
 830      *                                                                         *
 831      **************************************************************************/
 832 
 833 
 834     // --- Items
 835     /**
 836      * The underlying data model for the TableView. Note that it has a generic
 837      * type that must match the type of the TableView itself.
 838      * @return the items property
 839      */
 840     public final ObjectProperty<ObservableList<S>> itemsProperty() { return items; }
 841     private ObjectProperty<ObservableList<S>> items =
 842         new SimpleObjectProperty<ObservableList<S>>(this, "items") {
 843             WeakReference<ObservableList<S>> oldItemsRef;
 844 
 845             @Override protected void invalidated() {
 846                 final ObservableList<S> oldItems = oldItemsRef == null ? null : oldItemsRef.get();
 847                 final ObservableList<S> newItems = getItems();
 848 
 849                 // Fix for RT-36425
 850                 if (newItems != null && newItems == oldItems) {
 851                     return;
 852                 }
 853 
 854                 // Fix for RT-35763
 855                 if (! (newItems instanceof SortedList)) {
 856                     getSortOrder().clear();
 857                 }
 858 
 859                 oldItemsRef = new WeakReference<>(newItems);
 860             }
 861         };
 862     public final void setItems(ObservableList<S> value) { itemsProperty().set(value); }
 863     public final ObservableList<S> getItems() {return items.get(); }
 864 
 865 
 866     // --- Table menu button visible
 867     private BooleanProperty tableMenuButtonVisible;
 868     /**
 869      * This controls whether a menu button is available when the user clicks
 870      * in a designated space within the TableView, within which is a radio menu
 871      * item for each TableColumn in this table. This menu allows for the user to
 872      * show and hide all TableColumns easily.
 873      * @return the tableMenuButtonVisible property
 874      */
 875     public final BooleanProperty tableMenuButtonVisibleProperty() {
 876         if (tableMenuButtonVisible == null) {
 877             tableMenuButtonVisible = new SimpleBooleanProperty(this, "tableMenuButtonVisible");
 878         }
 879         return tableMenuButtonVisible;
 880     }
 881     public final void setTableMenuButtonVisible (boolean value) {
 882         tableMenuButtonVisibleProperty().set(value);
 883     }
 884     public final boolean isTableMenuButtonVisible() {
 885         return tableMenuButtonVisible == null ? false : tableMenuButtonVisible.get();
 886     }
 887 
 888 
 889     // --- Column Resize Policy
 890     private ObjectProperty<Callback<ResizeFeatures, Boolean>> columnResizePolicy;
 891     public final void setColumnResizePolicy(Callback<ResizeFeatures, Boolean> callback) {
 892         columnResizePolicyProperty().set(callback);
 893     }
 894     public final Callback<ResizeFeatures, Boolean> getColumnResizePolicy() {
 895         return columnResizePolicy == null ? UNCONSTRAINED_RESIZE_POLICY : columnResizePolicy.get();
 896     }
 897 
 898     /**
 899      * This is the function called when the user completes a column-resize
 900      * operation. The two most common policies are available as static functions
 901      * in the TableView class: {@link #UNCONSTRAINED_RESIZE_POLICY} and
 902      * {@link #CONSTRAINED_RESIZE_POLICY}.
 903      * @return columnResizePolicy property
 904      */
 905     public final ObjectProperty<Callback<ResizeFeatures, Boolean>> columnResizePolicyProperty() {
 906         if (columnResizePolicy == null) {
 907             columnResizePolicy = new SimpleObjectProperty<Callback<ResizeFeatures, Boolean>>(this, "columnResizePolicy", UNCONSTRAINED_RESIZE_POLICY) {
 908                 private Callback<ResizeFeatures, Boolean> oldPolicy;
 909 
 910                 @Override protected void invalidated() {
 911                     if (isInited) {
 912                         get().call(new ResizeFeatures(TableView.this, null, 0.0));
 913 
 914                         if (oldPolicy != null) {
 915                             PseudoClass state = PseudoClass.getPseudoClass(oldPolicy.toString());
 916                             pseudoClassStateChanged(state, false);
 917                         }
 918                         if (get() != null) {
 919                             PseudoClass state = PseudoClass.getPseudoClass(get().toString());
 920                             pseudoClassStateChanged(state, true);
 921                         }
 922                         oldPolicy = get();
 923                     }


 928     }
 929 
 930 
 931     // --- Row Factory
 932     private ObjectProperty<Callback<TableView<S>, TableRow<S>>> rowFactory;
 933 
 934     /**
 935      * A function which produces a TableRow. The system is responsible for
 936      * reusing TableRows. Return from this function a TableRow which
 937      * might be usable for representing a single row in a TableView.
 938      * <p>
 939      * Note that a TableRow is <b>not</b> a TableCell. A TableRow is
 940      * simply a container for a TableCell, and in most circumstances it is more
 941      * likely that you'll want to create custom TableCells, rather than
 942      * TableRows. The primary use case for creating custom TableRow
 943      * instances would most probably be to introduce some form of column
 944      * spanning support.
 945      * <p>
 946      * You can create custom TableCell instances per column by assigning the
 947      * appropriate function to the cellFactory property in the TableColumn class.
 948      * @return rowFactory property
 949      */
 950     public final ObjectProperty<Callback<TableView<S>, TableRow<S>>> rowFactoryProperty() {
 951         if (rowFactory == null) {
 952             rowFactory = new SimpleObjectProperty<Callback<TableView<S>, TableRow<S>>>(this, "rowFactory");
 953         }
 954         return rowFactory;
 955     }
 956     public final void setRowFactory(Callback<TableView<S>, TableRow<S>> value) {
 957         rowFactoryProperty().set(value);
 958     }
 959     public final Callback<TableView<S>, TableRow<S>> getRowFactory() {
 960         return rowFactory == null ? null : rowFactory.get();
 961     }
 962 
 963 
 964     // --- Placeholder Node
 965     private ObjectProperty<Node> placeholder;
 966     /**
 967      * This Node is shown to the user when the table has no content to show.
 968      * This may be the case because the table model has no data in the first
 969      * place, that a filter has been applied to the table model, resulting
 970      * in there being nothing to show the user, or that there are no currently
 971      * visible columns.
 972      * @return placeholder property
 973      */
 974     public final ObjectProperty<Node> placeholderProperty() {
 975         if (placeholder == null) {
 976             placeholder = new SimpleObjectProperty<Node>(this, "placeholder");
 977         }
 978         return placeholder;
 979     }
 980     public final void setPlaceholder(Node value) {
 981         placeholderProperty().set(value);
 982     }
 983     public final Node getPlaceholder() {
 984         return placeholder == null ? null : placeholder.get();
 985     }
 986 
 987 
 988     // --- Selection Model
 989     private ObjectProperty<TableViewSelectionModel<S>> selectionModel
 990             = new SimpleObjectProperty<TableViewSelectionModel<S>>(this, "selectionModel") {
 991 
 992         TableViewSelectionModel<S> oldValue = null;


 999                 if (oldValue instanceof TableViewArrayListSelectionModel) {
1000                     ((TableViewArrayListSelectionModel)oldValue).dispose();
1001                 }
1002             }
1003 
1004             oldValue = get();
1005 
1006             if (oldValue != null) {
1007                 oldValue.cellSelectionEnabledProperty().addListener(weakCellSelectionModelInvalidationListener);
1008                 // fake an invalidation to ensure updated pseudo-class state
1009                 weakCellSelectionModelInvalidationListener.invalidated(oldValue.cellSelectionEnabledProperty());
1010             }
1011         }
1012     };
1013 
1014     /**
1015      * The SelectionModel provides the API through which it is possible
1016      * to select single or multiple items within a TableView, as  well as inspect
1017      * which items have been selected by the user. Note that it has a generic
1018      * type that must match the type of the TableView itself.
1019      * @return selectionModel property
1020      */
1021     public final ObjectProperty<TableViewSelectionModel<S>> selectionModelProperty() {
1022         return selectionModel;
1023     }
1024     public final void setSelectionModel(TableViewSelectionModel<S> value) {
1025         selectionModelProperty().set(value);
1026     }
1027 
1028     public final TableViewSelectionModel<S> getSelectionModel() {
1029         return selectionModel.get();
1030     }
1031 
1032 
1033     // --- Focus Model
1034     private ObjectProperty<TableViewFocusModel<S>> focusModel;
1035     public final void setFocusModel(TableViewFocusModel<S> value) {
1036         focusModelProperty().set(value);
1037     }
1038     public final TableViewFocusModel<S> getFocusModel() {
1039         return focusModel == null ? null : focusModel.get();
1040     }
1041     /**
1042      * Represents the currently-installed {@link TableViewFocusModel} for this
1043      * TableView. Under almost all circumstances leaving this as the default
1044      * focus model will suffice.
1045      * @return focusModel property
1046      */
1047     public final ObjectProperty<TableViewFocusModel<S>> focusModelProperty() {
1048         if (focusModel == null) {
1049             focusModel = new SimpleObjectProperty<TableViewFocusModel<S>>(this, "focusModel");
1050         }
1051         return focusModel;
1052     }
1053 
1054 
1055 //    // --- Span Model
1056 //    private ObjectProperty<SpanModel<S>> spanModel
1057 //            = new SimpleObjectProperty<SpanModel<S>>(this, "spanModel") {
1058 //
1059 //        @Override protected void invalidated() {
1060 //            ObservableList<String> styleClass = getStyleClass();
1061 //            if (getSpanModel() == null) {
1062 //                styleClass.remove(CELL_SPAN_TABLE_VIEW_STYLE_CLASS);
1063 //            } else if (! styleClass.contains(CELL_SPAN_TABLE_VIEW_STYLE_CLASS)) {
1064 //                styleClass.add(CELL_SPAN_TABLE_VIEW_STYLE_CLASS);
1065 //            }


1072 //    public final void setSpanModel(SpanModel<S> value) {
1073 //        spanModelProperty().set(value);
1074 //    }
1075 //
1076 //    public final SpanModel<S> getSpanModel() {
1077 //        return spanModel.get();
1078 //    }
1079 
1080     // --- Editable
1081     private BooleanProperty editable;
1082     public final void setEditable(boolean value) {
1083         editableProperty().set(value);
1084     }
1085     public final boolean isEditable() {
1086         return editable == null ? false : editable.get();
1087     }
1088     /**
1089      * Specifies whether this TableView is editable - only if the TableView, the
1090      * TableColumn (if applicable) and the TableCells within it are both
1091      * editable will a TableCell be able to go into their editing state.
1092      * @return the editable property
1093      */
1094     public final BooleanProperty editableProperty() {
1095         if (editable == null) {
1096             editable = new SimpleBooleanProperty(this, "editable", false);
1097         }
1098         return editable;
1099     }
1100 
1101 
1102     // --- Fixed cell size
1103     private DoubleProperty fixedCellSize;
1104 
1105     /**
1106      * Sets the new fixed cell size for this control. Any value greater than
1107      * zero will enable fixed cell size mode, whereas a zero or negative value
1108      * (or Region.USE_COMPUTED_SIZE) will be used to disabled fixed cell size
1109      * mode.
1110      *
1111      * @param value The new fixed cell size value, or a value less than or equal
1112      *              to zero (or Region.USE_COMPUTED_SIZE) to disable.


1130     }
1131     /**
1132      * Specifies whether this control has cells that are a fixed height (of the
1133      * specified value). If this value is less than or equal to zero,
1134      * then all cells are individually sized and positioned. This is a slow
1135      * operation. Therefore, when performance matters and developers are not
1136      * dependent on variable cell sizes it is a good idea to set the fixed cell
1137      * size value. Generally cells are around 24px, so setting a fixed cell size
1138      * of 24 is likely to result in very little difference in visuals, but a
1139      * improvement to performance.
1140      *
1141      * <p>To set this property via CSS, use the -fx-fixed-cell-size property.
1142      * This should not be confused with the -fx-cell-size property. The difference
1143      * between these two CSS properties is that -fx-cell-size will size all
1144      * cells to the specified size, but it will not enforce that this is the
1145      * only size (thus allowing for variable cell sizes, and preventing the
1146      * performance gains from being possible). Therefore, when performance matters
1147      * use -fx-fixed-cell-size, instead of -fx-cell-size. If both properties are
1148      * specified in CSS, -fx-fixed-cell-size takes precedence.</p>
1149      *
1150      * @return fixedCellSize property
1151      * @since JavaFX 8.0
1152      */
1153     public final DoubleProperty fixedCellSizeProperty() {
1154         if (fixedCellSize == null) {
1155             fixedCellSize = new StyleableDoubleProperty(Region.USE_COMPUTED_SIZE) {
1156                 @Override public CssMetaData<TableView<?>,Number> getCssMetaData() {
1157                     return StyleableProperties.FIXED_CELL_SIZE;
1158                 }
1159 
1160                 @Override public Object getBean() {
1161                     return TableView.this;
1162                 }
1163 
1164                 @Override public String getName() {
1165                     return "fixedCellSize";
1166                 }
1167             };
1168         }
1169         return fixedCellSize;
1170     }
1171 
1172 
1173     // --- Editing Cell
1174     private ReadOnlyObjectWrapper<TablePosition<S,?>> editingCell;
1175     private void setEditingCell(TablePosition<S,?> value) {
1176         editingCellPropertyImpl().set(value);
1177     }
1178     public final TablePosition<S,?> getEditingCell() {
1179         return editingCell == null ? null : editingCell.get();
1180     }
1181 
1182     /**
1183      * Represents the current cell being edited, or null if
1184      * there is no cell being edited.
1185      * @return the editingCell property
1186      */
1187     public final ReadOnlyObjectProperty<TablePosition<S,?>> editingCellProperty() {
1188         return editingCellPropertyImpl().getReadOnlyProperty();
1189     }
1190 
1191     private ReadOnlyObjectWrapper<TablePosition<S,?>> editingCellPropertyImpl() {
1192         if (editingCell == null) {
1193             editingCell = new ReadOnlyObjectWrapper<TablePosition<S,?>>(this, "editingCell");
1194         }
1195         return editingCell;
1196     }
1197 
1198 
1199     // --- Comparator (built via sortOrder list, so read-only)
1200     /**
1201      * The comparator property is a read-only property that is representative of the
1202      * current state of the {@link #getSortOrder() sort order} list. The sort
1203      * order list contains the columns that have been added to it either programmatically
1204      * or via a user clicking on the headers themselves.
1205      * @since JavaFX 8.0


1297                     return "onSort";
1298                 }
1299             };
1300         }
1301         return onSort;
1302     }
1303 
1304 
1305     /***************************************************************************
1306      *                                                                         *
1307      * Public API                                                              *
1308      *                                                                         *
1309      **************************************************************************/
1310     /**
1311      * The TableColumns that are part of this TableView. As the user reorders
1312      * the TableView columns, this list will be updated to reflect the current
1313      * visual ordering.
1314      *
1315      * <p>Note: to display any data in a TableView, there must be at least one
1316      * TableColumn in this ObservableList.</p>
1317      * @return the columns
1318      */
1319     public final ObservableList<TableColumn<S,?>> getColumns() {
1320         return columns;
1321     }
1322 
1323     /**
1324      * The sortOrder list defines the order in which {@link TableColumn} instances
1325      * are sorted. An empty sortOrder list means that no sorting is being applied
1326      * on the TableView. If the sortOrder list has one TableColumn within it,
1327      * the TableView will be sorted using the
1328      * {@link TableColumn#sortTypeProperty() sortType} and
1329      * {@link TableColumn#comparatorProperty() comparator} properties of this
1330      * TableColumn (assuming
1331      * {@link TableColumn#sortableProperty() TableColumn.sortable} is true).
1332      * If the sortOrder list contains multiple TableColumn instances, then
1333      * the TableView is firstly sorted based on the properties of the first
1334      * TableColumn. If two elements are considered equal, then the second
1335      * TableColumn in the list is used to determine ordering. This repeats until
1336      * the results from all TableColumn comparators are considered, if necessary.
1337      *


1446                 @Override protected void invalidated() {
1447                     EventType<ScrollToEvent<TableColumn<S, ?>>> type = ScrollToEvent.scrollToColumn();
1448                     setEventHandler(type, get());
1449                 }
1450 
1451                 @Override public Object getBean() {
1452                     return TableView.this;
1453                 }
1454 
1455                 @Override public String getName() {
1456                     return "onScrollToColumn";
1457                 }
1458             };
1459         }
1460         return onScrollToColumn;
1461     }
1462 
1463     /**
1464      * Applies the currently installed resize policy against the given column,
1465      * resizing it based on the delta value provided.
1466      * @param column the column
1467      * @param delta the delta
1468      * @return true if column resize is allowed
1469      */
1470     public boolean resizeColumn(TableColumn<S,?> column, double delta) {
1471         if (column == null || Double.compare(delta, 0.0) == 0) return false;
1472 
1473         boolean allowed = getColumnResizePolicy().call(new ResizeFeatures<S>(TableView.this, column, delta));
1474         if (!allowed) return false;
1475 
1476         return true;
1477     }
1478 
1479     /**
1480      * Causes the cell at the given row/column view indexes to switch into
1481      * its editing state, if it is not already in it, and assuming that the
1482      * TableView and column are also editable.
1483      *
1484      * <p><strong>Note:</strong> This method will cancel editing if the given row
1485      * value is less than zero and the given column is null.</p>
1486      * @param row the row
1487      * @param column the column
1488      */
1489     public void edit(int row, TableColumn<S,?> column) {
1490         if (!isEditable() || (column != null && ! column.isEditable())) {
1491             return;
1492         }
1493 
1494         if (row < 0 && column == null) {
1495             setEditingCell(null);
1496         } else {
1497             setEditingCell(new TablePosition<>(this, row, column));
1498         }
1499     }
1500 
1501     /**
1502      * Returns an unmodifiable list containing the currently visible leaf columns.
1503      * @return an unmodifiable list containing the currently visible leaf columns
1504      */
1505     public ObservableList<TableColumn<S,?>> getVisibleLeafColumns() {
1506         return unmodifiableVisibleLeafColumns;
1507     }
1508 
1509     /**
1510      * Returns the position of the given column, relative to all other
1511      * visible leaf columns.
1512      * @param column the column
1513      * @return the position of the given column, relative to all other
1514      * visible leaf columns
1515      */
1516     public int getVisibleLeafIndex(TableColumn<S,?> column) {
1517         return visibleLeafColumns.indexOf(column);
1518     }
1519 
1520     /**
1521      * Returns the TableColumn in the given column index, relative to all other
1522      * visible leaf columns.
1523      * @param column the column
1524      * @return the TableColumn in the given column index, relative to all other
1525      * visible leaf columns
1526      */
1527     public TableColumn<S,?> getVisibleLeafColumn(int column) {
1528         if (column < 0 || column >= visibleLeafColumns.size()) return null;
1529         return visibleLeafColumns.get(column);
1530     }
1531 
1532     /** {@inheritDoc} */
1533     @Override protected Skin<?> createDefaultSkin() {
1534         return new TableViewSkin<S>(this);
1535     }
1536 
1537     /**
1538      * The sort method forces the TableView to re-run its sorting algorithm. More
1539      * often than not it is not necessary to call this method directly, as it is
1540      * automatically called when the {@link #getSortOrder() sort order},
1541      * {@link #sortPolicyProperty() sort policy}, or the state of the
1542      * TableColumn {@link TableColumn#sortTypeProperty() sort type} properties
1543      * change. In other words, this method should only be called directly when
1544      * something external changes and a sort is required.
1545      * @since JavaFX 8.0


1832          *      TableView resize operation.
1833          * @param delta The amount of horizontal space added or removed in the
1834          *      resize operation.
1835          */
1836         public ResizeFeatures(TableView<S> table, TableColumn<S,?> column, Double delta) {
1837             super(column, delta);
1838             this.table = table;
1839         }
1840 
1841         /**
1842          * Returns the column upon which the resize is occurring, or null
1843          * if this ResizeFeatures instance was created as a result of a
1844          * TableView resize operation.
1845          */
1846         @Override public TableColumn<S,?> getColumn() {
1847             return (TableColumn<S,?>) super.getColumn();
1848         }
1849 
1850         /**
1851          * Returns the TableView upon which the resize operation is occurring.
1852          * @return the TableView
1853          */
1854         public TableView<S> getTable() {
1855             return table;
1856         }
1857     }
1858 
1859 
1860 
1861     /***************************************************************************
1862      *                                                                         *
1863      * Support Classes                                                         *
1864      *                                                                         *
1865      **************************************************************************/
1866 
1867 
1868     /**
1869      * A simple extension of the {@link SelectionModel} abstract class to
1870      * allow for special support for TableView controls.
1871      * @since JavaFX 2.0
1872      */


1900         public TableViewSelectionModel(final TableView<S> tableView) {
1901             if (tableView == null) {
1902                 throw new NullPointerException("TableView can not be null");
1903             }
1904 
1905             this.tableView = tableView;
1906         }
1907 
1908 
1909 
1910         /***********************************************************************
1911          *                                                                     *
1912          * Abstract API                                                        *
1913          *                                                                     *
1914          **********************************************************************/
1915 
1916         /**
1917          * A read-only ObservableList representing the currently selected cells
1918          * in this TableView. Rather than directly modify this list, please
1919          * use the other methods provided in the TableViewSelectionModel.
1920          * @return a read-only ObservableList representing the currently
1921          * selected cells in this TableView
1922          */
1923         public abstract ObservableList<TablePosition> getSelectedCells();
1924 
1925 
1926         /***********************************************************************
1927          *                                                                     *
1928          * Generic (type erasure) bridging                                     *
1929          *                                                                     *
1930          **********************************************************************/
1931 
1932         // --- isSelected
1933         /** {@inheritDoc} */
1934         @Override public boolean isSelected(int row, TableColumnBase<S, ?> column) {
1935             return isSelected(row, (TableColumn<S,?>)column);
1936         }
1937 
1938         /**
1939          * Convenience function which tests whether the given row and column index
1940          * is currently selected in this table instance.
1941          * @param row the row
1942          * @param column the column
1943          * @return true if row and column index is currently selected
1944          */
1945         public abstract boolean isSelected(int row, TableColumn<S, ?> column);
1946 
1947 
1948         // --- select
1949         /** {@inheritDoc} */
1950         @Override public void select(int row, TableColumnBase<S, ?> column) {
1951             select(row, (TableColumn<S,?>)column);
1952         }
1953 
1954         /**
1955          * Selects the cell at the given row/column intersection.
1956          * @param row the row
1957          * @param column the column
1958          */
1959         public abstract void select(int row, TableColumn<S, ?> column);
1960 
1961 
1962         // --- clearAndSelect
1963         /** {@inheritDoc} */
1964         @Override public void clearAndSelect(int row, TableColumnBase<S,?> column) {
1965             clearAndSelect(row, (TableColumn<S,?>) column);
1966         }
1967 
1968         /**
1969          * Clears all selection, and then selects the cell at the given row/column
1970          * intersection.
1971          * @param row the row
1972          * @param column the column
1973          */
1974         public abstract void clearAndSelect(int row, TableColumn<S,?> column);
1975 
1976 
1977         // --- clearSelection
1978         /** {@inheritDoc} */
1979         @Override public void clearSelection(int row, TableColumnBase<S,?> column) {
1980             clearSelection(row, (TableColumn<S,?>) column);
1981         }
1982 
1983         /**
1984          * Removes selection from the specified row/column position (in view indexes).
1985          * If this particular cell (or row if the column value is -1) is not selected,
1986          * nothing happens.
1987          * @param row the row
1988          * @param column the column
1989          */
1990         public abstract void clearSelection(int row, TableColumn<S, ?> column);
1991 
1992         /** {@inheritDoc} */
1993         @Override public void selectRange(int minRow, TableColumnBase<S,?> minColumn,
1994                                           int maxRow, TableColumnBase<S,?> maxColumn) {
1995             final int minColumnIndex = tableView.getVisibleLeafIndex((TableColumn<S,?>)minColumn);
1996             final int maxColumnIndex = tableView.getVisibleLeafIndex((TableColumn<S,?>)maxColumn);
1997             for (int _row = minRow; _row <= maxRow; _row++) {
1998                 for (int _col = minColumnIndex; _col <= maxColumnIndex; _col++) {
1999                     select(_row, tableView.getVisibleLeafColumn(_col));
2000                 }
2001             }
2002         }
2003 
2004 
2005 
2006         /***********************************************************************
2007          *                                                                     *
2008          * Public API                                                          *
2009          *                                                                     *
2010          **********************************************************************/
2011 
2012         /**
2013          * Returns the TableView instance that this selection model is installed in.
2014          * @return the TableView
2015          */
2016         public TableView<S> getTableView() {
2017             return tableView;
2018         }
2019 
2020         /**
2021          * Convenience method that returns getTableView().getItems().
2022          * @return The items list of the current TableView.
2023          */
2024         protected List<S> getTableModel()  {
2025             return tableView.getItems();
2026         }
2027 
2028         /** {@inheritDoc} */
2029         @Override protected S getModelItem(int index) {
2030             if (index < 0 || index >= getItemCount()) return null;
2031             return tableView.getItems().get(index);
2032         }
2033 
2034         /** {@inheritDoc} */


3238          *                                                                     *
3239          **********************************************************************/
3240 
3241         /**
3242          * Tests whether the row / cell at the given location currently has the
3243          * focus within the TableView.
3244          */
3245         @Override public boolean isFocused(int row, TableColumn<S,?> column) {
3246             if (row < 0 || row >= getItemCount()) return false;
3247 
3248             TablePosition cell = getFocusedCell();
3249             boolean columnMatch = column == null || column.equals(cell.getTableColumn());
3250 
3251             return cell.getRow() == row && columnMatch;
3252         }
3253 
3254         /**
3255          * Causes the item at the given index to receive the focus. This does not
3256          * cause the current selection to change. Updates the focusedItem and
3257          * focusedIndex properties such that <code>focusedIndex = -1</code> unless
3258          * <pre><code>0 &lt;= index &lt; model size</code></pre>.
3259          *
3260          * @param index The index of the item to get focus.
3261          */
3262         @Override public void focus(int index) {
3263             if (index < 0 || index >= getItemCount()) {
3264                 setFocusedCell(EMPTY_CELL);
3265             } else {
3266                 setFocusedCell(new TablePosition<>(tableView, index, null));
3267             }
3268         }
3269 
3270         /**
3271          * Attempts to move focus to the cell above the currently focused cell.
3272          */
3273         @Override public void focusAboveCell() {
3274             TablePosition cell = getFocusedCell();
3275 
3276             if (getFocusedIndex() == -1) {
3277                 focus(getItemCount() - 1, cell.getTableColumn());
3278             } else if (getFocusedIndex() > 0) {


< prev index next >