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,23 +21,28 @@
  * 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;
+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,168 +54,267 @@
 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, ?>> {
+/**
+ * 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 TableView<T> tableView;
+    private final TableViewBehavior<T>  behavior;
 
-    public TableViewSkin(final TableView<T> tableView) {
-        super(tableView, new TableViewBehavior<T>(tableView));
         
-        this.tableView = tableView;
-        flow.setFixedCellSize(tableView.getFixedCellSize());
         
-        super.init(tableView);
+    /***************************************************************************
+     *                                                                         *
+     * 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 (tableView.getEditingCell() != null) {
-                tableView.edit(-1, null);
+            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 (tableView.isFocusTraversable()) {
-                tableView.requestFocus();
+            if (control.isFocusTraversable()) {
+                control.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.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(); });
+        behavior.setOnSelectPreviousRow(() -> onSelectPreviousCell());
+        behavior.setOnSelectNextRow(() -> onSelectNextCell());
+        behavior.setOnSelectLeftCell(() -> onSelectLeftCell());
+        behavior.setOnSelectRightCell(() -> onSelectRightCell());
 
-        registerChangeListener(tableView.fixedCellSizeProperty(), "FIXED_CELL_SIZE");
+        registerChangeListener(control.fixedCellSizeProperty(), e -> flow.setFixedCellSize(getSkinnable().getFixedCellSize()));
 
     }
 
-    @Override protected void handleControlPropertyChanged(String p) {
-        super.handleControlPropertyChanged(p);
 
-        if ("FIXED_CELL_SIZE".equals(p)) {
-            flow.setFixedCellSize(getSkinnable().getFixedCellSize());
-        }
-    }
 
     /***************************************************************************
      *                                                                         *
-     * Listeners                                                               *
+     * Public API                                                              *
      *                                                                         *
      **************************************************************************/
     
+    /** {@inheritDoc} */
+    @Override public void dispose() {
+        super.dispose();
     
+        if (behavior != null) {
+            behavior.dispose();
+        }
+    }
     
-    /***************************************************************************
-     *                                                                         *
-     * Internal Fields                                                         *
-     *                                                                         *
-     **************************************************************************/
+    /** {@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);
+        }
+    }
 
     
     
     /***************************************************************************
      *                                                                         *
-     * Public API                                                              *
+     * Private methods                                                         *
      *                                                                         *
      **************************************************************************/  
     
     /** {@inheritDoc} */
-    @Override protected ObservableList<TableColumn<T, ?>> getVisibleLeafColumns() {
-        return tableView.getVisibleLeafColumns();
+    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>();
     }
 
-    @Override protected int getVisibleLeafIndex(TableColumn<T, ?> tc) {
-        return tableView.getVisibleLeafIndex(tc);
+        cell.updateTableView(tableView);
+        return cell;
     }
     
-    @Override protected TableColumn<T, ?> getVisibleLeafColumn(int col) {
-        return tableView.getVisibleLeafColumn(col);
+    /** {@inheritDoc} */
+    @Override int getItemCount() {
+        TableView<T> tableView = getSkinnable();
+        return tableView.getItems() == null ? 0 : tableView.getItems().size();
     }
     
     /** {@inheritDoc} */
-    @Override protected TableViewFocusModel<T> getFocusModel() {
-        return tableView.getFocusModel();
+    @Override void horizontalScroll() {
+        super.horizontalScroll();
+        if (getSkinnable().getFixedCellSize() > 0) {
+            flow.requestCellLayout();
+        }
     }
 
     /** {@inheritDoc} */
-    @Override protected TablePosition<T, ?> getFocusedCell() {
-        return tableView.getFocusModel().getFocusedCell();
+    @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 protected TableSelectionModel<T> getSelectionModel() {
-        return tableView.getSelectionModel();
+    @Override TableViewFocusModel<T> getFocusModel() {
+        return getSkinnable().getFocusModel();
     }
 
     /** {@inheritDoc} */
-    @Override protected ObjectProperty<Callback<TableView<T>, TableRow<T>>> rowFactoryProperty() {
-        return tableView.rowFactoryProperty();
+    @Override TablePosition<T, ?> getFocusedCell() {
+        return getSkinnable().getFocusModel().getFocusedCell();
     }
 
     /** {@inheritDoc} */
-    @Override protected ObjectProperty<Node> placeholderProperty() {
-        return tableView.placeholderProperty();
+    @Override TableSelectionModel<T> getSelectionModel() {
+        return getSkinnable().getSelectionModel();
     }
 
     /** {@inheritDoc} */
-    @Override protected ObjectProperty<ObservableList<T>> itemsProperty() {
-        return tableView.itemsProperty();
+    @Override ObjectProperty<Callback<TableView<T>, TableRow<T>>> rowFactoryProperty() {
+        return getSkinnable().rowFactoryProperty();
     }
 
     /** {@inheritDoc} */
-    @Override protected ObservableList<TableColumn<T, ?>> getColumns() {
-        return tableView.getColumns();
+    @Override ObjectProperty<Node> placeholderProperty() {
+        return getSkinnable().placeholderProperty();
     }
 
     /** {@inheritDoc} */
-    @Override protected BooleanProperty tableMenuButtonVisibleProperty() {
-        return tableView.tableMenuButtonVisibleProperty();
+    @Override ObjectProperty<ObservableList<T>> itemsProperty() {
+        return getSkinnable().itemsProperty();
     }
 
     /** {@inheritDoc} */
-    @Override protected ObjectProperty<Callback<ResizeFeaturesBase, Boolean>> columnResizePolicyProperty() {
-        // TODO Ugly!
-        return (ObjectProperty<Callback<ResizeFeaturesBase, Boolean>>) (Object) tableView.columnResizePolicyProperty();
+    @Override ObservableList<TableColumn<T, ?>> getColumns() {
+        return getSkinnable().getColumns();
     }
 
     /** {@inheritDoc} */
-    @Override protected ObservableList<TableColumn<T,?>> getSortOrder() {
-        return tableView.getSortOrder();
+    @Override BooleanProperty tableMenuButtonVisibleProperty() {
+        return getSkinnable().tableMenuButtonVisibleProperty();
     }
 
-    @Override protected boolean resizeColumn(TableColumn<T, ?> tc, double delta) {
-        return tableView.resizeColumn(tc, delta);
+    /** {@inheritDoc} */
+    @Override ObjectProperty<Callback<ResizeFeaturesBase, Boolean>> columnResizePolicyProperty() {
+        return (ObjectProperty<Callback<ResizeFeaturesBase, Boolean>>) (Object) getSkinnable().columnResizePolicyProperty();
+    }
+
+    /** {@inheritDoc} */
+    @Override ObservableList<TableColumn<T,?>> getSortOrder() {
+        return getSkinnable().getSortOrder();
     }
 
-    @Override protected void edit(int index, TableColumn<T, ?> column) {
-        tableView.edit(index, (TableColumn<T,?>)column);
+    /** {@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.
      */
-    @Override protected void resizeColumnToFitContent(TableColumn<T, ?> tc, int maxRows) {
+    /** {@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,11 +325,11 @@
         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);
+        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,11 +339,11 @@
         
         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.updateTableView(getSkinnable());
             cell.updateIndex(row);
             
             if ((cell.getText() != null && !cell.getText().isEmpty()) || cell.getGraphic() != null) {
                 getChildren().add(cell);
                 cell.applyCss();

@@ -260,103 +364,12 @@
         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) {
+        if(getSkinnable().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                                                         *
-     *                                                                         *
-     **************************************************************************/
-    
 }