modules/controls/src/main/java/javafx/scene/control/skin/TableViewSkin.java

Print this page
rev 9240 : 8076423: JEP 253: Prepare JavaFX UI Controls & CSS APIs for Modularization

*** 21,43 **** * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ ! package com.sun.javafx.scene.control.skin; import java.util.ArrayList; import java.util.List; import javafx.beans.property.BooleanProperty; import javafx.beans.property.ObjectProperty; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.event.EventHandler; import javafx.scene.AccessibleAction; import javafx.scene.AccessibleAttribute; import javafx.scene.Node; import javafx.scene.control.ResizeFeaturesBase; import javafx.scene.control.TableCell; import javafx.scene.control.TableColumn; import javafx.scene.control.TablePosition; import javafx.scene.control.TableRow; --- 21,48 ---- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ ! package javafx.scene.control.skin; import java.util.ArrayList; import java.util.List; + import com.sun.javafx.scene.control.Properties; + import com.sun.javafx.scene.control.behavior.BehaviorBase; + import com.sun.javafx.scene.control.skin.Utils; import javafx.beans.property.BooleanProperty; import javafx.beans.property.ObjectProperty; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.event.EventHandler; import javafx.scene.AccessibleAction; import javafx.scene.AccessibleAttribute; import javafx.scene.Node; + import javafx.scene.control.Button; + import javafx.scene.control.Control; import javafx.scene.control.ResizeFeaturesBase; import javafx.scene.control.TableCell; import javafx.scene.control.TableColumn; import javafx.scene.control.TablePosition; import javafx.scene.control.TableRow;
*** 49,216 **** import javafx.scene.layout.Region; import javafx.util.Callback; import com.sun.javafx.scene.control.behavior.TableViewBehavior; ! public class TableViewSkin<T> extends TableViewSkinBase<T, T, TableView<T>, TableViewBehavior<T>, TableRow<T>, TableColumn<T, ?>> { ! private final TableView<T> tableView; - public TableViewSkin(final TableView<T> tableView) { - super(tableView, new TableViewBehavior<T>(tableView)); - this.tableView = tableView; - flow.setFixedCellSize(tableView.getFixedCellSize()); ! super.init(tableView); EventHandler<MouseEvent> ml = event -> { // RT-15127: cancel editing on scroll. This is a bit extreme // (we are cancelling editing on touching the scrollbars). // This can be improved at a later date. ! if (tableView.getEditingCell() != null) { ! tableView.edit(-1, null); } // This ensures that the table maintains the focus, even when the vbar // and hbar controls inside the flow are clicked. Without this, the // focus border will not be shown when the user interacts with the // scrollbars, and more importantly, keyboard navigation won't be // available to the user. ! if (tableView.isFocusTraversable()) { ! tableView.requestFocus(); } }; flow.getVbar().addEventFilter(MouseEvent.MOUSE_PRESSED, ml); flow.getHbar().addEventFilter(MouseEvent.MOUSE_PRESSED, ml); // init the behavior 'closures' ! TableViewBehavior<T> behavior = getBehavior(); ! behavior.setOnFocusPreviousRow(() -> { onFocusPreviousCell(); }); ! behavior.setOnFocusNextRow(() -> { onFocusNextCell(); }); ! behavior.setOnMoveToFirstCell(() -> { onMoveToFirstCell(); }); ! behavior.setOnMoveToLastCell(() -> { onMoveToLastCell(); }); behavior.setOnScrollPageDown(isFocusDriven -> onScrollPageDown(isFocusDriven)); behavior.setOnScrollPageUp(isFocusDriven -> onScrollPageUp(isFocusDriven)); ! behavior.setOnSelectPreviousRow(() -> { onSelectPreviousCell(); }); ! behavior.setOnSelectNextRow(() -> { onSelectNextCell(); }); ! behavior.setOnSelectLeftCell(() -> { onSelectLeftCell(); }); ! behavior.setOnSelectRightCell(() -> { onSelectRightCell(); }); ! registerChangeListener(tableView.fixedCellSizeProperty(), "FIXED_CELL_SIZE"); } - @Override protected void handleControlPropertyChanged(String p) { - super.handleControlPropertyChanged(p); - if ("FIXED_CELL_SIZE".equals(p)) { - flow.setFixedCellSize(getSkinnable().getFixedCellSize()); - } - } /*************************************************************************** * * ! * Listeners * * * **************************************************************************/ ! /*************************************************************************** ! * * ! * Internal Fields * ! * * ! **************************************************************************/ /*************************************************************************** * * ! * Public API * * * **************************************************************************/ /** {@inheritDoc} */ ! @Override protected ObservableList<TableColumn<T, ?>> getVisibleLeafColumns() { ! return tableView.getVisibleLeafColumns(); } ! @Override protected int getVisibleLeafIndex(TableColumn<T, ?> tc) { ! return tableView.getVisibleLeafIndex(tc); } ! @Override protected TableColumn<T, ?> getVisibleLeafColumn(int col) { ! return tableView.getVisibleLeafColumn(col); } /** {@inheritDoc} */ ! @Override protected TableViewFocusModel<T> getFocusModel() { ! return tableView.getFocusModel(); } /** {@inheritDoc} */ ! @Override protected TablePosition<T, ?> getFocusedCell() { ! return tableView.getFocusModel().getFocusedCell(); } /** {@inheritDoc} */ ! @Override protected TableSelectionModel<T> getSelectionModel() { ! return tableView.getSelectionModel(); } /** {@inheritDoc} */ ! @Override protected ObjectProperty<Callback<TableView<T>, TableRow<T>>> rowFactoryProperty() { ! return tableView.rowFactoryProperty(); } /** {@inheritDoc} */ ! @Override protected ObjectProperty<Node> placeholderProperty() { ! return tableView.placeholderProperty(); } /** {@inheritDoc} */ ! @Override protected ObjectProperty<ObservableList<T>> itemsProperty() { ! return tableView.itemsProperty(); } /** {@inheritDoc} */ ! @Override protected ObservableList<TableColumn<T, ?>> getColumns() { ! return tableView.getColumns(); } /** {@inheritDoc} */ ! @Override protected BooleanProperty tableMenuButtonVisibleProperty() { ! return tableView.tableMenuButtonVisibleProperty(); } /** {@inheritDoc} */ ! @Override protected ObjectProperty<Callback<ResizeFeaturesBase, Boolean>> columnResizePolicyProperty() { ! // TODO Ugly! ! return (ObjectProperty<Callback<ResizeFeaturesBase, Boolean>>) (Object) tableView.columnResizePolicyProperty(); } /** {@inheritDoc} */ ! @Override protected ObservableList<TableColumn<T,?>> getSortOrder() { ! return tableView.getSortOrder(); } ! @Override protected boolean resizeColumn(TableColumn<T, ?> tc, double delta) { ! return tableView.resizeColumn(tc, delta); } ! @Override protected void edit(int index, TableColumn<T, ?> column) { ! tableView.edit(index, (TableColumn<T,?>)column); } /* * FIXME: Naive implementation ahead * Attempts to resize column based on the pref width of all items contained * in this column. This can be potentially very expensive if the number of * rows is large. */ ! @Override protected void resizeColumnToFitContent(TableColumn<T, ?> tc, int maxRows) { if (!tc.isResizable()) return; // final TableColumn<T, ?> col = tc; List<?> items = itemsProperty().get(); if (items == null || items.isEmpty()) return; --- 54,320 ---- import javafx.scene.layout.Region; import javafx.util.Callback; import com.sun.javafx.scene.control.behavior.TableViewBehavior; ! /** ! * Default skin implementation for the {@link TableView} control. ! * ! * @see TableView ! * @since 9 ! */ ! public class TableViewSkin<T> extends TableViewSkinBase<T, T, TableView<T>, TableRow<T>, TableColumn<T, ?>> { ! ! /*************************************************************************** ! * * ! * Private Fields * ! * * ! **************************************************************************/ ! private final TableViewBehavior<T> behavior; ! /*************************************************************************** ! * * ! * Constructors * ! * * ! **************************************************************************/ ! ! /** ! * Creates a new TableViewSkin instance, installing the necessary child ! * nodes into the Control {@link Control#getChildren() children} list, as ! * well as the necessary input mappings for handling key, mouse, etc events. ! * ! * @param control The control that this skin should be installed onto. ! */ ! public TableViewSkin(final TableView<T> control) { ! super(control); ! ! // install default input map for the TableView control ! behavior = new TableViewBehavior<>(control); ! // control.setInputMap(behavior.getInputMap()); ! ! flow.setFixedCellSize(control.getFixedCellSize()); ! flow.setCellFactory(flow -> createCell()); EventHandler<MouseEvent> ml = event -> { // RT-15127: cancel editing on scroll. This is a bit extreme // (we are cancelling editing on touching the scrollbars). // This can be improved at a later date. ! if (control.getEditingCell() != null) { ! control.edit(-1, null); } // This ensures that the table maintains the focus, even when the vbar // and hbar controls inside the flow are clicked. Without this, the // focus border will not be shown when the user interacts with the // scrollbars, and more importantly, keyboard navigation won't be // available to the user. ! if (control.isFocusTraversable()) { ! control.requestFocus(); } }; flow.getVbar().addEventFilter(MouseEvent.MOUSE_PRESSED, ml); flow.getHbar().addEventFilter(MouseEvent.MOUSE_PRESSED, ml); // init the behavior 'closures' ! behavior.setOnFocusPreviousRow(() -> onFocusPreviousCell()); ! behavior.setOnFocusNextRow(() -> onFocusNextCell()); ! behavior.setOnMoveToFirstCell(() -> onMoveToFirstCell()); ! behavior.setOnMoveToLastCell(() -> onMoveToLastCell()); behavior.setOnScrollPageDown(isFocusDriven -> onScrollPageDown(isFocusDriven)); behavior.setOnScrollPageUp(isFocusDriven -> onScrollPageUp(isFocusDriven)); ! behavior.setOnSelectPreviousRow(() -> onSelectPreviousCell()); ! behavior.setOnSelectNextRow(() -> onSelectNextCell()); ! behavior.setOnSelectLeftCell(() -> onSelectLeftCell()); ! behavior.setOnSelectRightCell(() -> onSelectRightCell()); ! registerChangeListener(control.fixedCellSizeProperty(), e -> flow.setFixedCellSize(getSkinnable().getFixedCellSize())); } /*************************************************************************** * * ! * Public API * * * **************************************************************************/ + /** {@inheritDoc} */ + @Override public void dispose() { + super.dispose(); + if (behavior != null) { + behavior.dispose(); + } + } ! /** {@inheritDoc} */ ! @Override public Object queryAccessibleAttribute(AccessibleAttribute attribute, Object... parameters) { ! switch (attribute) { ! case SELECTED_ITEMS: { ! List<Node> selection = new ArrayList<>(); ! TableViewSelectionModel<T> sm = getSkinnable().getSelectionModel(); ! for (TablePosition<T,?> pos : sm.getSelectedCells()) { ! TableRow<T> row = flow.getPrivateCell(pos.getRow()); ! if (row != null) selection.add(row); ! } ! return FXCollections.observableArrayList(selection); ! } ! default: return super.queryAccessibleAttribute(attribute, parameters); ! } ! } ! ! /** {@inheritDoc} */ ! @Override protected void executeAccessibleAction(AccessibleAction action, Object... parameters) { ! switch (action) { ! case SHOW_ITEM: { ! Node item = (Node)parameters[0]; ! if (item instanceof TableCell) { ! @SuppressWarnings("unchecked") ! TableCell<T, ?> cell = (TableCell<T, ?>)item; ! flow.scrollTo(cell.getIndex()); ! } ! break; ! } ! case SET_SELECTED_ITEMS: { ! @SuppressWarnings("unchecked") ! ObservableList<Node> items = (ObservableList<Node>)parameters[0]; ! if (items != null) { ! TableSelectionModel<T> sm = getSkinnable().getSelectionModel(); ! if (sm != null) { ! sm.clearSelection(); ! for (Node item : items) { ! if (item instanceof TableCell) { ! @SuppressWarnings("unchecked") ! TableCell<T, ?> cell = (TableCell<T, ?>)item; ! sm.select(cell.getIndex(), cell.getTableColumn()); ! } ! } ! } ! } ! break; ! } ! default: super.executeAccessibleAction(action, parameters); ! } ! } /*************************************************************************** * * ! * Private methods * * * **************************************************************************/ /** {@inheritDoc} */ ! private TableRow<T> createCell() { ! TableRow<T> cell; ! ! TableView<T> tableView = getSkinnable(); ! if (tableView.getRowFactory() != null) { ! cell = tableView.getRowFactory().call(tableView); ! } else { ! cell = new TableRow<T>(); } ! cell.updateTableView(tableView); ! return cell; } ! /** {@inheritDoc} */ ! @Override int getItemCount() { ! TableView<T> tableView = getSkinnable(); ! return tableView.getItems() == null ? 0 : tableView.getItems().size(); } /** {@inheritDoc} */ ! @Override void horizontalScroll() { ! super.horizontalScroll(); ! if (getSkinnable().getFixedCellSize() > 0) { ! flow.requestCellLayout(); ! } } /** {@inheritDoc} */ ! @Override ObservableList<TableColumn<T, ?>> getVisibleLeafColumns() { ! return getSkinnable().getVisibleLeafColumns(); ! } ! ! @Override int getVisibleLeafIndex(TableColumn<T, ?> tc) { ! return getSkinnable().getVisibleLeafIndex(tc); ! } ! ! @Override TableColumn<T, ?> getVisibleLeafColumn(int col) { ! return getSkinnable().getVisibleLeafColumn(col); } /** {@inheritDoc} */ ! @Override TableViewFocusModel<T> getFocusModel() { ! return getSkinnable().getFocusModel(); } /** {@inheritDoc} */ ! @Override TablePosition<T, ?> getFocusedCell() { ! return getSkinnable().getFocusModel().getFocusedCell(); } /** {@inheritDoc} */ ! @Override TableSelectionModel<T> getSelectionModel() { ! return getSkinnable().getSelectionModel(); } /** {@inheritDoc} */ ! @Override ObjectProperty<Callback<TableView<T>, TableRow<T>>> rowFactoryProperty() { ! return getSkinnable().rowFactoryProperty(); } /** {@inheritDoc} */ ! @Override ObjectProperty<Node> placeholderProperty() { ! return getSkinnable().placeholderProperty(); } /** {@inheritDoc} */ ! @Override ObjectProperty<ObservableList<T>> itemsProperty() { ! return getSkinnable().itemsProperty(); } /** {@inheritDoc} */ ! @Override ObservableList<TableColumn<T, ?>> getColumns() { ! return getSkinnable().getColumns(); } /** {@inheritDoc} */ ! @Override BooleanProperty tableMenuButtonVisibleProperty() { ! return getSkinnable().tableMenuButtonVisibleProperty(); } ! /** {@inheritDoc} */ ! @Override ObjectProperty<Callback<ResizeFeaturesBase, Boolean>> columnResizePolicyProperty() { ! return (ObjectProperty<Callback<ResizeFeaturesBase, Boolean>>) (Object) getSkinnable().columnResizePolicyProperty(); ! } ! ! /** {@inheritDoc} */ ! @Override ObservableList<TableColumn<T,?>> getSortOrder() { ! return getSkinnable().getSortOrder(); } ! /** {@inheritDoc} */ ! @Override boolean resizeColumn(TableColumn<T, ?> tc, double delta) { ! return getSkinnable().resizeColumn(tc, delta); } /* * FIXME: Naive implementation ahead * Attempts to resize column based on the pref width of all items contained * in this column. This can be potentially very expensive if the number of * rows is large. */ ! /** {@inheritDoc} */ ! @Override void resizeColumnToFitContent(TableColumn<T, ?> tc, int maxRows) { if (!tc.isResizable()) return; // final TableColumn<T, ?> col = tc; List<?> items = itemsProperty().get(); if (items == null || items.isEmpty()) return;
*** 221,231 **** TableCell<T,?> cell = (TableCell<T, ?>) cellFactory.call(tc); if (cell == null) return; // set this property to tell the TableCell we want to know its actual // preferred width, not the width of the associated TableColumnBase ! cell.getProperties().put(TableCellSkin.DEFER_TO_PARENT_PREF_WIDTH, Boolean.TRUE); // determine cell padding double padding = 10; Node n = cell.getSkin() == null ? null : cell.getSkin().getNode(); if (n instanceof Region) { --- 325,335 ---- TableCell<T,?> cell = (TableCell<T, ?>) cellFactory.call(tc); if (cell == null) return; // set this property to tell the TableCell we want to know its actual // preferred width, not the width of the associated TableColumnBase ! cell.getProperties().put(Properties.DEFER_TO_PARENT_PREF_WIDTH, Boolean.TRUE); // determine cell padding double padding = 10; Node n = cell.getSkin() == null ? null : cell.getSkin().getNode(); if (n instanceof Region) {
*** 235,245 **** int rows = maxRows == -1 ? items.size() : Math.min(items.size(), maxRows); double maxWidth = 0; for (int row = 0; row < rows; row++) { cell.updateTableColumn(tc); ! cell.updateTableView(tableView); cell.updateIndex(row); if ((cell.getText() != null && !cell.getText().isEmpty()) || cell.getGraphic() != null) { getChildren().add(cell); cell.applyCss(); --- 339,349 ---- int rows = maxRows == -1 ? items.size() : Math.min(items.size(), maxRows); double maxWidth = 0; for (int row = 0; row < rows; row++) { cell.updateTableColumn(tc); ! cell.updateTableView(getSkinnable()); cell.updateIndex(row); if ((cell.getText() != null && !cell.getText().isEmpty()) || cell.getGraphic() != null) { getChildren().add(cell); cell.applyCss();
*** 260,362 **** double headerWidth = headerTextWidth + headerGraphicWidth + 10 + header.snappedLeftInset() + header.snappedRightInset(); maxWidth = Math.max(maxWidth, headerWidth); // RT-23486 maxWidth += padding; ! if(tableView.getColumnResizePolicy() == TableView.CONSTRAINED_RESIZE_POLICY) { maxWidth = Math.max(maxWidth, tc.getWidth()); } tc.impl_setWidth(maxWidth); } - - /** {@inheritDoc} */ - @Override public int getItemCount() { - return tableView.getItems() == null ? 0 : tableView.getItems().size(); - } - - /** {@inheritDoc} */ - @Override public TableRow<T> createCell() { - TableRow<T> cell; - - if (tableView.getRowFactory() != null) { - cell = tableView.getRowFactory().call(tableView); - } else { - cell = new TableRow<T>(); - } - - cell.updateTableView(tableView); - return cell; - } - - @Override protected void horizontalScroll() { - super.horizontalScroll(); - if (getSkinnable().getFixedCellSize() > 0) { - flow.requestCellLayout(); - } - } - - @Override - public Object queryAccessibleAttribute(AccessibleAttribute attribute, Object... parameters) { - switch (attribute) { - case SELECTED_ITEMS: { - List<Node> selection = new ArrayList<>(); - TableViewSelectionModel<T> sm = getSkinnable().getSelectionModel(); - for (TablePosition<T,?> pos : sm.getSelectedCells()) { - TableRow<T> row = flow.getPrivateCell(pos.getRow()); - if (row != null) selection.add(row); - } - return FXCollections.observableArrayList(selection); - } - default: return super.queryAccessibleAttribute(attribute, parameters); - } - } - - @Override - protected void executeAccessibleAction(AccessibleAction action, Object... parameters) { - switch (action) { - case SHOW_ITEM: { - Node item = (Node)parameters[0]; - if (item instanceof TableCell) { - @SuppressWarnings("unchecked") - TableCell<T, ?> cell = (TableCell<T, ?>)item; - flow.show(cell.getIndex()); - } - break; - } - case SET_SELECTED_ITEMS: { - @SuppressWarnings("unchecked") - ObservableList<Node> items = (ObservableList<Node>)parameters[0]; - if (items != null) { - TableSelectionModel<T> sm = getSkinnable().getSelectionModel(); - if (sm != null) { - sm.clearSelection(); - for (Node item : items) { - if (item instanceof TableCell) { - @SuppressWarnings("unchecked") - TableCell<T, ?> cell = (TableCell<T, ?>)item; - sm.select(cell.getIndex(), cell.getTableColumn()); - } - } - } - } - break; - } - default: super.executeAccessibleAction(action, parameters); - } - } - - /*************************************************************************** - * * - * Layout * - * * - **************************************************************************/ - - - - /*************************************************************************** - * * - * Private methods * - * * - **************************************************************************/ - } --- 364,375 ---- double headerWidth = headerTextWidth + headerGraphicWidth + 10 + header.snappedLeftInset() + header.snappedRightInset(); maxWidth = Math.max(maxWidth, headerWidth); // RT-23486 maxWidth += padding; ! if(getSkinnable().getColumnResizePolicy() == TableView.CONSTRAINED_RESIZE_POLICY) { maxWidth = Math.max(maxWidth, tc.getWidth()); } tc.impl_setWidth(maxWidth); } }