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

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

@@ -1,7 +1,7 @@
 /*
- * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License version 2 only, as
  * published by the Free Software Foundation.  Oracle designates this

@@ -21,15 +21,18 @@
  * 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 com.sun.javafx.collections.NonIterableChange;
+import com.sun.javafx.scene.control.Properties;
 import com.sun.javafx.scene.control.ReadOnlyUnbackedObservableList;
 
+import com.sun.javafx.scene.control.behavior.BehaviorBase;
+import com.sun.javafx.scene.control.skin.Utils;
 import javafx.event.WeakEventHandler;
 import javafx.scene.control.*;
 
 import com.sun.javafx.scene.control.behavior.TreeTableViewBehavior;
 

@@ -51,270 +54,382 @@
 import javafx.scene.input.MouseEvent;
 import javafx.scene.layout.Region;
 import javafx.scene.layout.StackPane;
 import javafx.util.Callback;
 
-public class TreeTableViewSkin<S> extends TableViewSkinBase<S, TreeItem<S>, TreeTableView<S>, TreeTableViewBehavior<S>, TreeTableRow<S>, TreeTableColumn<S,?>> {
+/**
+ * Default skin implementation for the {@link TreeTableView} control.
+ *
+ * @see TreeTableView
+ * @since 9
+ */
+public class TreeTableViewSkin<T> extends TableViewSkinBase<T, TreeItem<T>, TreeTableView<T>, TreeTableRow<T>, TreeTableColumn<T,?>> {
+
+    /***************************************************************************
+     *                                                                         *
+     * Private Fields                                                          *
+     *                                                                         *
+     **************************************************************************/
+
+    private TreeTableViewBackingList<T> tableBackingList;
+    private ObjectProperty<ObservableList<TreeItem<T>>> tableBackingListProperty;
+    private WeakReference<TreeItem<T>> weakRootRef;
+    private final TreeTableViewBehavior<T>  behavior;
+
+
+
+    /***************************************************************************
+     *                                                                         *
+     * Listeners                                                               *
+     *                                                                         *
+     **************************************************************************/
+
+    private EventHandler<TreeItem.TreeModificationEvent<T>> rootListener = e -> {
+        if (e.wasAdded() && e.wasRemoved() && e.getAddedSize() == e.getRemovedSize()) {
+            // Fix for RT-14842, where the children of a TreeItem were changing,
+            // but because the overall item count was staying the same, there was
+            // no event being fired to the skin to be informed that the items
+            // had changed. So, here we just watch for the case where the number
+            // of items being added is equal to the number of items being removed.
+            rowCountDirty = true;
+            getSkinnable().requestLayout();
+        } else if (e.getEventType().equals(TreeItem.valueChangedEvent())) {
+            // Fix for RT-14971 and RT-15338.
+            needCellsRebuilt = true;
+            getSkinnable().requestLayout();
+        } else {
+            // Fix for RT-20090. We are checking to see if the event coming
+            // from the TreeItem root is an event where the count has changed.
+            EventType<?> eventType = e.getEventType();
+            while (eventType != null) {
+                if (eventType.equals(TreeItem.<T>expandedItemCountChangeEvent())) {
+                    rowCountDirty = true;
+                    getSkinnable().requestLayout();
+                    break;
+                }
+                eventType = eventType.getSuperType();
+            }
+        }
     
-    public TreeTableViewSkin(final TreeTableView<S> treeTableView) {
-        super(treeTableView, new TreeTableViewBehavior<S>(treeTableView));
+        // fix for RT-37853
+        getSkinnable().edit(-1, null);
+    };
+
+    private WeakEventHandler<TreeModificationEvent<T>> weakRootListener;
+
+
+
+    /***************************************************************************
+     *                                                                         *
+     * Constructors                                                            *
+     *                                                                         *
+     **************************************************************************/
         
-        this.treeTableView = treeTableView;
-        this.tableBackingList = new TreeTableViewBackingList<S>(treeTableView);
-        this.tableBackingListProperty = new SimpleObjectProperty<ObservableList<TreeItem<S>>>(tableBackingList);
+    /**
+     * Creates a new TreeTableViewSkin 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 TreeTableViewSkin(final TreeTableView<T> control) {
+        super(control);
         
-        flow.setFixedCellSize(treeTableView.getFixedCellSize());
+        // install default input map for the TreeTableView control
+        behavior = new TreeTableViewBehavior<>(control);
+//        control.setInputMap(behavior.getInputMap());
         
-        super.init(treeTableView);
+        flow.setFixedCellSize(control.getFixedCellSize());
+        flow.setCellFactory(flow -> createCell());
         
         setRoot(getSkinnable().getRoot());
 
         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 (treeTableView.getEditingCell() != null) {
-                treeTableView.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 (treeTableView.isFocusTraversable()) {
-                treeTableView.requestFocus();
+            if (control.isFocusTraversable()) {
+                control.requestFocus();
             }
         };
         flow.getVbar().addEventFilter(MouseEvent.MOUSE_PRESSED, ml);
         flow.getHbar().addEventFilter(MouseEvent.MOUSE_PRESSED, ml);
 
         // init the behavior 'closures'
-        TreeTableViewBehavior<S> 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(); });
-        
-        registerChangeListener(treeTableView.rootProperty(), "ROOT");
-        registerChangeListener(treeTableView.showRootProperty(), "SHOW_ROOT");
-        registerChangeListener(treeTableView.rowFactoryProperty(), "ROW_FACTORY");
-        registerChangeListener(treeTableView.expandedItemCountProperty(), "TREE_ITEM_COUNT");
-        registerChangeListener(treeTableView.fixedCellSizeProperty(), "FIXED_CELL_SIZE");
-    }
+        behavior.setOnSelectPreviousRow(() -> onSelectPreviousCell());
+        behavior.setOnSelectNextRow(() -> onSelectNextCell());
+        behavior.setOnSelectLeftCell(() -> onSelectLeftCell());
+        behavior.setOnSelectRightCell(() -> onSelectRightCell());
 
-    @Override protected void handleControlPropertyChanged(String p) {
-        super.handleControlPropertyChanged(p);
-        
-        if ("ROOT".equals(p)) {
+        registerChangeListener(control.rootProperty(), e -> {
             // fix for RT-37853
             getSkinnable().edit(-1, null);
 
             setRoot(getSkinnable().getRoot());
-        } else if ("SHOW_ROOT".equals(p)) {
+        });
+        registerChangeListener(control.showRootProperty(), e -> {
             // if we turn off showing the root, then we must ensure the root
             // is expanded - otherwise we end up with no visible items in
             // the tree.
             if (! getSkinnable().isShowRoot() && getRoot() != null) {
                  getRoot().setExpanded(true);
             }
             // update the item count in the flow and behavior instances
             updateRowCount();
-        } else if ("ROW_FACTORY".equals(p)) {
-            flow.recreateCells();
-        } else if ("TREE_ITEM_COUNT".equals(p)) {
-            rowCountDirty = true;
-        } else if ("FIXED_CELL_SIZE".equals(p)) {
-            flow.setFixedCellSize(getSkinnable().getFixedCellSize());
-        }
+        });
+        registerChangeListener(control.rowFactoryProperty(), e -> flow.recreateCells());
+        registerChangeListener(control.expandedItemCountProperty(), e -> rowCountDirty = true);
+        registerChangeListener(control.fixedCellSizeProperty(), e -> flow.setFixedCellSize(getSkinnable().getFixedCellSize()));
     }
     
+
+
     /***************************************************************************
      *                                                                         *
-     * Listeners                                                               *
+     * Public API                                                              *
      *                                                                         *
      **************************************************************************/
     
+    /** {@inheritDoc} */
+    @Override public void dispose() {
+        super.dispose();
+
+        if (behavior != null) {
+            behavior.dispose();
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override protected Object queryAccessibleAttribute(AccessibleAttribute attribute, Object... parameters) {
+        switch (attribute) {
+            case ROW_AT_INDEX: {
+                final int rowIndex = (Integer)parameters[0];
+                return rowIndex < 0 ? null : flow.getPrivateCell(rowIndex);
+            }
+            case SELECTED_ITEMS: {
+                List<Node> selection = new ArrayList<>();
+                TreeTableView.TreeTableViewSelectionModel<T> sm = getSkinnable().getSelectionModel();
+                for (TreeTablePosition<T,?> pos : sm.getSelectedCells()) {
+                    TreeTableRow<T> row = flow.getPrivateCell(pos.getRow());
+                    if (row != null) selection.add(row);
+                }
+                return FXCollections.observableArrayList(selection);
+            }
+            case FOCUS_ITEM: // TableViewSkinBase
+            case CELL_AT_ROW_COLUMN: // TableViewSkinBase
+            case COLUMN_AT_INDEX: // TableViewSkinBase
+            case HEADER: // TableViewSkinBase
+            case VERTICAL_SCROLLBAR: // TableViewSkinBase
+            case HORIZONTAL_SCROLLBAR: // TableViewSkinBase
+            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 TreeTableCell) {
+                    @SuppressWarnings("unchecked")
+                    TreeTableCell<T, ?> cell = (TreeTableCell<T, ?>)item;
+                    flow.scrollTo(cell.getIndex());
+                }
+                break;
+            }
+            case SET_SELECTED_ITEMS: {
+                @SuppressWarnings("unchecked")
+                ObservableList<Node> items = (ObservableList<Node>)parameters[0];
+                if (items != null) {
+                    TreeTableView.TreeTableViewSelectionModel<T> sm = getSkinnable().getSelectionModel();
+                    if (sm != null) {
+                        sm.clearSelection();
+                        for (Node item : items) {
+                            if (item instanceof TreeTableCell) {
+                                @SuppressWarnings("unchecked")
+                                TreeTableCell<T, ?> cell = (TreeTableCell<T, ?>)item;
+                                sm.select(cell.getIndex(), cell.getTableColumn());
+                            }
+                        }
+                    }
+                }
+                break;
+            }
+            default: super.executeAccessibleAction(action, parameters);
+        }
+    }
+
     
     
     /***************************************************************************
      *                                                                         *
-     * Internal Fields                                                         *
+     * Private methods                                                         *
      *                                                                         *
      **************************************************************************/
 
-    private TreeTableViewBackingList<S> tableBackingList;
-    private ObjectProperty<ObservableList<TreeItem<S>>> tableBackingListProperty;
-    private TreeTableView<S> treeTableView;
-    private WeakReference<TreeItem<S>> weakRootRef;
+    /** {@inheritDoc} */
+    private TreeTableRow<T> createCell() {
+        TreeTableRow<T> cell;
     
-    private EventHandler<TreeItem.TreeModificationEvent<S>> rootListener = e -> {
-        if (e.wasAdded() && e.wasRemoved() && e.getAddedSize() == e.getRemovedSize()) {
-            // Fix for RT-14842, where the children of a TreeItem were changing,
-            // but because the overall item count was staying the same, there was
-            // no event being fired to the skin to be informed that the items
-            // had changed. So, here we just watch for the case where the number
-            // of items being added is equal to the number of items being removed.
-            rowCountDirty = true;
-            getSkinnable().requestLayout();
-        } else if (e.getEventType().equals(TreeItem.valueChangedEvent())) {
-            // Fix for RT-14971 and RT-15338.
-            needCellsRebuilt = true;
-            getSkinnable().requestLayout();
+        TreeTableView<T> treeTableView = getSkinnable();
+        if (treeTableView.getRowFactory() != null) {
+            cell = treeTableView.getRowFactory().call(treeTableView);
         } else {
-            // Fix for RT-20090. We are checking to see if the event coming
-            // from the TreeItem root is an event where the count has changed.
-            EventType<?> eventType = e.getEventType();
-            while (eventType != null) {
-                if (eventType.equals(TreeItem.<S>expandedItemCountChangeEvent())) {
-                    rowCountDirty = true;
-                    getSkinnable().requestLayout();
-                    break;
-                }
-                eventType = eventType.getSuperType();
-            }
+            cell = new TreeTableRow<T>();
         }
 
-        // fix for RT-37853
-        getSkinnable().edit(-1, null);
-    };
+        // If there is no disclosure node, then add one of my own
+        if (cell.getDisclosureNode() == null) {
+            final StackPane disclosureNode = new StackPane();
+            disclosureNode.getStyleClass().setAll("tree-disclosure-node");
+            disclosureNode.setMouseTransparent(true);
     
-    private WeakEventHandler<TreeModificationEvent<S>> weakRootListener;
+            final StackPane disclosureNodeArrow = new StackPane();
+            disclosureNodeArrow.getStyleClass().setAll("arrow");
+            disclosureNode.getChildren().add(disclosureNodeArrow);
             
+            cell.setDisclosureNode(disclosureNode);
+        }
     
-//    private WeakReference<TreeItem> weakRoot;
-    private TreeItem<S> getRoot() {
+        cell.updateTreeTableView(treeTableView);
+        return cell;
+    }
+
+    private TreeItem<T> getRoot() {
         return weakRootRef == null ? null : weakRootRef.get();
     }
-    private void setRoot(TreeItem<S> newRoot) {
+    private void setRoot(TreeItem<T> newRoot) {
         if (getRoot() != null && weakRootListener != null) {
-            getRoot().removeEventHandler(TreeItem.<S>treeNotificationEvent(), weakRootListener);
+            getRoot().removeEventHandler(TreeItem.<T>treeNotificationEvent(), weakRootListener);
         }
         weakRootRef = new WeakReference<>(newRoot);
         if (getRoot() != null) {
             weakRootListener = new WeakEventHandler<>(rootListener);
-            getRoot().addEventHandler(TreeItem.<S>treeNotificationEvent(), weakRootListener);
+            getRoot().addEventHandler(TreeItem.<T>treeNotificationEvent(), weakRootListener);
         }
         
         updateRowCount();
     }
     
-    
-    /***************************************************************************
-     *                                                                         *
-     * Public API                                                              *
-     *                                                                         *
-     **************************************************************************/  
-    
     /** {@inheritDoc} */
-    @Override protected ObservableList<TreeTableColumn<S, ?>> getVisibleLeafColumns() {
-        return treeTableView.getVisibleLeafColumns();
+    @Override ObservableList<TreeTableColumn<T, ?>> getVisibleLeafColumns() {
+        return getSkinnable().getVisibleLeafColumns();
     }
     
-    @Override protected int getVisibleLeafIndex(TreeTableColumn<S,?> tc) {
-        return treeTableView.getVisibleLeafIndex(tc);
+    @Override int getVisibleLeafIndex(TreeTableColumn<T,?> tc) {
+        return getSkinnable().getVisibleLeafIndex(tc);
     }
 
-    @Override protected TreeTableColumn<S,?> getVisibleLeafColumn(int col) {
-        return treeTableView.getVisibleLeafColumn(col);
+    @Override TreeTableColumn<T,?> getVisibleLeafColumn(int col) {
+        return getSkinnable().getVisibleLeafColumn(col);
     }
 
     /** {@inheritDoc} */
-    @Override protected TreeTableView.TreeTableViewFocusModel<S> getFocusModel() {
-        return treeTableView.getFocusModel();
+    @Override TreeTableView.TreeTableViewFocusModel<T> getFocusModel() {
+        return getSkinnable().getFocusModel();
     }
     
     /** {@inheritDoc} */
-    @Override protected TreeTablePosition<S, ?> getFocusedCell() {
-        return treeTableView.getFocusModel().getFocusedCell();
+    @Override TreeTablePosition<T, ?> getFocusedCell() {
+        return getSkinnable().getFocusModel().getFocusedCell();
     }
 
     /** {@inheritDoc} */
-        @Override protected TableSelectionModel<TreeItem<S>> getSelectionModel() {
-        return treeTableView.getSelectionModel();
+    @Override TableSelectionModel<TreeItem<T>> getSelectionModel() {
+        return getSkinnable().getSelectionModel();
     }
 
     /** {@inheritDoc} */
-    @Override protected ObjectProperty<Callback<TreeTableView<S>, TreeTableRow<S>>> rowFactoryProperty() {
-        return treeTableView.rowFactoryProperty();
+    @Override ObjectProperty<Callback<TreeTableView<T>, TreeTableRow<T>>> rowFactoryProperty() {
+        return getSkinnable().rowFactoryProperty();
     }
 
     /** {@inheritDoc} */
-    @Override protected ObjectProperty<Node> placeholderProperty() {
-        return treeTableView.placeholderProperty();
+    @Override ObjectProperty<Node> placeholderProperty() {
+        return getSkinnable().placeholderProperty();
     }
 
     /** {@inheritDoc} */
-    @Override protected ObjectProperty<ObservableList<TreeItem<S>>> itemsProperty() {
+    @Override ObjectProperty<ObservableList<TreeItem<T>>> itemsProperty() {
+        if (tableBackingListProperty == null) {
+            this.tableBackingList = new TreeTableViewBackingList<>(getSkinnable());
+            this.tableBackingListProperty = new SimpleObjectProperty<>(tableBackingList);
+        }
         return tableBackingListProperty;
     }
 
     /** {@inheritDoc} */
-    @Override protected ObservableList<TreeTableColumn<S,?>> getColumns() {
-        return treeTableView.getColumns();
+    @Override ObservableList<TreeTableColumn<T,?>> getColumns() {
+        return getSkinnable().getColumns();
     }
     
     /** {@inheritDoc} */
-    @Override protected BooleanProperty tableMenuButtonVisibleProperty() {
-        return treeTableView.tableMenuButtonVisibleProperty();
+    @Override BooleanProperty tableMenuButtonVisibleProperty() {
+        return getSkinnable().tableMenuButtonVisibleProperty();
     }
 
     /** {@inheritDoc} */
-    @Override protected ObjectProperty<Callback<ResizeFeaturesBase, Boolean>> columnResizePolicyProperty() {
-        // TODO Ugly!
-        return (ObjectProperty<Callback<ResizeFeaturesBase, Boolean>>) (Object) treeTableView.columnResizePolicyProperty();
+    @Override ObjectProperty<Callback<ResizeFeaturesBase, Boolean>> columnResizePolicyProperty() {
+        return (ObjectProperty<Callback<ResizeFeaturesBase, Boolean>>) (Object) getSkinnable().columnResizePolicyProperty();
     }
 
     /** {@inheritDoc} */
-    @Override protected ObservableList<TreeTableColumn<S,?>> getSortOrder() {
-        return treeTableView.getSortOrder();
-    }
-    
-    @Override protected boolean resizeColumn(TreeTableColumn<S,?> tc, double delta) {
-        return treeTableView.resizeColumn(tc, delta);
+    @Override ObservableList<TreeTableColumn<T,?>> getSortOrder() {
+        return getSkinnable().getSortOrder();
     }
 
-    @Override protected void edit(int index, TreeTableColumn<S, ?> column) {
-        treeTableView.edit(index, column);
+    @Override boolean resizeColumn(TreeTableColumn<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(TreeTableColumn<S,?> tc, int maxRows) {
+    @Override void resizeColumnToFitContent(TreeTableColumn<T,?> tc, int maxRows) {
         final TreeTableColumn col = tc;
         List<?> items = itemsProperty().get();
         if (items == null || items.isEmpty()) return;
     
         Callback cellFactory = col.getCellFactory();
         if (cellFactory == null) return;
     
-        TreeTableCell<S,?> cell = (TreeTableCell) cellFactory.call(col);
+        TreeTableCell<T,?> cell = (TreeTableCell) cellFactory.call(col);
         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) {
             Region r = (Region) n;
             padding = r.snappedLeftInset() + r.snappedRightInset();
         } 
         
-        TreeTableRow<S> treeTableRow = new TreeTableRow<>();
+        final TreeTableView<T> treeTableView = getSkinnable();
+
+        TreeTableRow<T> treeTableRow = new TreeTableRow<>();
         treeTableRow.updateTreeTableView(treeTableView);
         
         int rows = maxRows == -1 ? items.size() : Math.min(items.size(), maxRows);
         double maxWidth = 0;
         for (int row = 0; row < rows; row++) {

@@ -357,124 +472,24 @@
 
         col.impl_setWidth(maxWidth);
     }
     
     /** {@inheritDoc} */
-    @Override public int getItemCount() {
-        return treeTableView.getExpandedItemCount();
+    @Override int getItemCount() {
+        return getSkinnable().getExpandedItemCount();
     }
     
     /** {@inheritDoc} */
-    @Override public TreeTableRow<S> createCell() {
-        TreeTableRow<S> cell;
-
-        if (treeTableView.getRowFactory() != null) {
-            cell = treeTableView.getRowFactory().call(treeTableView);
-        } else {
-            cell = new TreeTableRow<S>();
-        }
-
-        // If there is no disclosure node, then add one of my own
-        if (cell.getDisclosureNode() == null) {
-            final StackPane disclosureNode = new StackPane();
-            disclosureNode.getStyleClass().setAll("tree-disclosure-node");
-            disclosureNode.setMouseTransparent(true);
-
-            final StackPane disclosureNodeArrow = new StackPane();
-            disclosureNodeArrow.getStyleClass().setAll("arrow");
-            disclosureNode.getChildren().add(disclosureNodeArrow);
-
-            cell.setDisclosureNode(disclosureNode);
-        }
-
-        cell.updateTreeTableView(treeTableView);
-        return cell;
-    }
-
-    @Override protected void horizontalScroll() {
+    @Override void horizontalScroll() {
         super.horizontalScroll();
         if (getSkinnable().getFixedCellSize() > 0) {
             flow.requestCellLayout();
         }
     }
 
-    @Override
-    protected Object queryAccessibleAttribute(AccessibleAttribute attribute, Object... parameters) {
-        switch (attribute) {
-            case ROW_AT_INDEX: {
-                final int rowIndex = (Integer)parameters[0];
-                return rowIndex < 0 ? null : flow.getPrivateCell(rowIndex);
-            }
-            case SELECTED_ITEMS: {
-                List<Node> selection = new ArrayList<>();
-                TreeTableView.TreeTableViewSelectionModel<S> sm = getSkinnable().getSelectionModel();
-                for (TreeTablePosition<S,?> pos : sm.getSelectedCells()) {
-                    TreeTableRow<S> row = flow.getPrivateCell(pos.getRow());
-                    if (row != null) selection.add(row);
-                }
-                return FXCollections.observableArrayList(selection);
-            }
-            case FOCUS_ITEM: // TableViewSkinBase
-            case CELL_AT_ROW_COLUMN: // TableViewSkinBase
-            case COLUMN_AT_INDEX: // TableViewSkinBase
-            case HEADER: // TableViewSkinBase
-            case VERTICAL_SCROLLBAR: // TableViewSkinBase
-            case HORIZONTAL_SCROLLBAR: // TableViewSkinBase
-            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 TreeTableCell) {
-                    @SuppressWarnings("unchecked")
-                    TreeTableCell<S, ?> cell = (TreeTableCell<S, ?>)item;
-                    flow.show(cell.getIndex());
-                }
-                break;
-            }
-            case SET_SELECTED_ITEMS: {
-                @SuppressWarnings("unchecked")
-                ObservableList<Node> items = (ObservableList<Node>)parameters[0];
-                if (items != null) {
-                    TreeTableView.TreeTableViewSelectionModel<S> sm = getSkinnable().getSelectionModel();
-                    if (sm != null) {
-                        sm.clearSelection();
-                        for (Node item : items) {
-                            if (item instanceof TreeTableCell) {
-                                @SuppressWarnings("unchecked")
-                                TreeTableCell<S, ?> cell = (TreeTableCell<S, ?>)item;
-                                sm.select(cell.getIndex(), cell.getTableColumn());
-                            }
-                        }
-                    }
-                }
-                break;
-            }
-            default: super.executeAccessibleAction(action, parameters);
-        }
-    }
-
-    /***************************************************************************
-     *                                                                         *
-     * Layout                                                                  *
-     *                                                                         *
-     **************************************************************************/    
-    
-
-    
-    
-    /***************************************************************************
-     *                                                                         *
-     * Private methods                                                         *
-     *                                                                         *
-     **************************************************************************/
-    
-    @Override protected void updateRowCount() {
+    /** {@inheritDoc} */
+    @Override void updateRowCount() {
         updatePlaceholderRegionVisibility();
 
         tableBackingList.resetSize();
         
         int oldCount = flow.getCellCount();

@@ -493,33 +508,41 @@
         } else {
             needCellsReconfigured = true;
         }
     }
 
+
+
+    /***************************************************************************
+     *                                                                         *
+     * Support classes                                                         *
+     *                                                                         *
+     **************************************************************************/
+
     /**
      * A simple read only list structure that maps into the TreeTableView tree
      * structure.
      */
-    private static class TreeTableViewBackingList<S> extends ReadOnlyUnbackedObservableList<TreeItem<S>> {
-        private final TreeTableView<S> treeTable;
+    private static class TreeTableViewBackingList<T> extends ReadOnlyUnbackedObservableList<TreeItem<T>> {
+        private final TreeTableView<T> treeTable;
         
         private int size = -1;
         
-        TreeTableViewBackingList(TreeTableView<S> treeTable) {
+        TreeTableViewBackingList(TreeTableView<T> treeTable) {
             this.treeTable = treeTable;
         }
         
         void resetSize() {
             int oldSize = size;
             size = -1;
             
             // TODO we can certainly make this better....but it may not really matter
-            callObservers(new NonIterableChange.GenericAddRemoveChange<TreeItem<S>>(
-                    0, oldSize, FXCollections.<TreeItem<S>>emptyObservableList(), this));
+            callObservers(new NonIterableChange.GenericAddRemoveChange<TreeItem<T>>(
+                    0, oldSize, FXCollections.<TreeItem<T>>emptyObservableList(), this));
         }
         
-        @Override public TreeItem<S> get(int i) {
+        @Override public TreeItem<T> get(int i) {
             return treeTable.getTreeItem(i);
         }
 
         @Override public int size() {
             if (size == -1) {