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

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

@@ -21,12 +21,14 @@
  * 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.scene.control.behavior.BehaviorBase;
+import javafx.beans.InvalidationListener;
 import javafx.collections.FXCollections;
 import javafx.scene.control.Control;
 import javafx.scene.control.TableColumnBase;
 import javafx.scene.control.TreeItem;
 import javafx.scene.control.TreeTableCell;

@@ -43,35 +45,39 @@
 import javafx.scene.AccessibleAttribute;
 import javafx.scene.Node;
 import javafx.css.StyleableDoubleProperty;
 import javafx.css.CssMetaData;
 
-import com.sun.javafx.css.converters.SizeConverter;
-import com.sun.javafx.scene.control.MultiplePropertyChangeListenerHandler;
+import javafx.css.converter.SizeConverter;
 import com.sun.javafx.scene.control.behavior.TreeTableRowBehavior;
 
 import javafx.beans.property.ObjectProperty;
-import javafx.beans.property.SimpleObjectProperty;
 import javafx.beans.value.WritableValue;
 import javafx.collections.ObservableList;
 import javafx.css.Styleable;
 import javafx.css.StyleableProperty;
 
-public class TreeTableRowSkin<T> extends TableRowSkinBase<TreeItem<T>, TreeTableRow<T>, TreeTableRowBehavior<T>, TreeTableCell<T,?>> {
+/**
+ * Default skin implementation for the {@link TreeTableRow} control.
+ *
+ * @see TreeTableRow
+ * @since 9
+ */
+public class TreeTableRowSkin<T> extends TableRowSkinBase<TreeItem<T>, TreeTableRow<T>, TreeTableCell<T,?>> {
 
     /***************************************************************************
      *                                                                         *
      * Private Fields                                                          *
      *                                                                         *
      **************************************************************************/
 
     // maps into the TreeTableViewSkin items property via
     // TreeTableViewSkin.treeItemToListMap
-    private SimpleObjectProperty<ObservableList<TreeItem<T>>> itemsProperty;
     private TreeItem<?> treeItem;
     private boolean disclosureNodeDirty = true;
     private Node graphic;
+    private final BehaviorBase<TreeTableRow<T>> behavior;
 
     private TreeTableViewSkin treeTableViewSkin;
 
     private boolean childrenDirty = false;
 

@@ -81,40 +87,53 @@
      *                                                                         *
      * Constructors                                                            *
      *                                                                         *
      **************************************************************************/
     
+    /**
+     * Creates a new TreeTableRowSkin 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 TreeTableRowSkin(TreeTableRow<T> control) {
-        super(control, new TreeTableRowBehavior<T>(control));
+        super(control);
         
-        super.init(control);
+        // install default input map for the TreeTableRow control
+        behavior = new TreeTableRowBehavior<>(control);
+//        control.setInputMap(behavior.getInputMap());
         
         updateTreeItem();
         updateTableViewSkin();
 
-        registerChangeListener(control.treeTableViewProperty(), "TREE_TABLE_VIEW");
-        registerChangeListener(control.indexProperty(), "INDEX");
-        registerChangeListener(control.treeItemProperty(), "TREE_ITEM");
-        registerChangeListener(control.getTreeTableView().treeColumnProperty(), "TREE_COLUMN");
+        registerChangeListener(control.treeTableViewProperty(), e -> updateTableViewSkin());
+        registerChangeListener(control.indexProperty(), e -> updateCells = true);
+        registerChangeListener(control.treeItemProperty(), e -> {
+            updateTreeItem();
+            isDirty = true;
+        });
+        registerChangeListener(control.getTreeTableView().treeColumnProperty(), e -> {
+            // Fix for RT-27782: Need to set isDirty to true, rather than the
+            // cheaper updateCells, as otherwise the text indentation will not
+            // be recalculated in TreeTableCellSkin.leftLabelPadding()
+            isDirty = true;
+            getSkinnable().requestLayout();
+        });
     }
 
 
-
     /***************************************************************************
      *                                                                         *
      * Listeners                                                               *
      *                                                                         *
      **************************************************************************/
 
-    private MultiplePropertyChangeListenerHandler treeItemListener = new MultiplePropertyChangeListenerHandler(p -> {
-        if ("GRAPHIC".equals(p)) {
+    private final InvalidationListener graphicListener = o -> {
             disclosureNodeDirty = true;
             getSkinnable().requestLayout();
-        }
-        return null;
-    });
-
+    };
 
 
     /***************************************************************************
      *                                                                         *
      * Properties                                                              *

@@ -149,33 +168,24 @@
 
 
 
     /***************************************************************************
      *                                                                         *
-     * Public Methods                                                          *
+     * Public API                                                              *
      *                                                                         *
      **************************************************************************/
 
-    @Override protected void handleControlPropertyChanged(String p) {
-        super.handleControlPropertyChanged(p);
+    /** {@inheritDoc} */
+    @Override public void dispose() {
+        super.dispose();
 
-        if ("TREE_ABLE_VIEW".equals(p)) {
-            updateTableViewSkin();
-        } else if ("INDEX".equals(p)) {
-            updateCells = true;
-        } else if ("TREE_ITEM".equals(p)) {
-            updateTreeItem();
-            isDirty = true;
-        } else if ("TREE_COLUMN".equals(p)) {
-            // Fix for RT-27782: Need to set isDirty to true, rather than the
-            // cheaper updateCells, as otherwise the text indentation will not
-            // be recalculated in TreeTableCellSkin.leftLabelPadding()
-            isDirty = true;
-            getSkinnable().requestLayout();
+        if (behavior != null) {
+            behavior.dispose();
         }
     }
 
+    /** {@inheritDoc} */
     @Override protected void updateChildren() {
         super.updateChildren();
 
         updateDisclosureNodeAndGraphic();
 

@@ -190,10 +200,11 @@
                 getChildren().addAll(cells);
             }
         }
     }
 
+    /** {@inheritDoc} */
     @Override protected void layoutChildren(double x, double y, double w, double h) {
         if (disclosureNodeDirty) {
             updateDisclosureNodeAndGraphic();
             disclosureNodeDirty = false;
         }

@@ -204,105 +215,118 @@
         }
 
         super.layoutChildren(x, y, w, h);
     }
 
-    @Override protected TreeTableCell<T, ?> getCell(TableColumnBase tcb) {
+
+
+    /***************************************************************************
+     *                                                                         *
+     * Private Implementation                                                  *
+     *                                                                         *
+     **************************************************************************/
+
+    /** {@inheritDoc} */
+    @Override TreeTableCell<T, ?> getCell(TableColumnBase tcb) {
         TreeTableColumn tableColumn = (TreeTableColumn<T,?>) tcb;
         TreeTableCell cell = (TreeTableCell) tableColumn.getCellFactory().call(tableColumn);
 
         cell.updateTreeTableColumn(tableColumn);
         cell.updateTreeTableView(tableColumn.getTreeTableView());
 
         return cell;
     }
 
-    @Override protected void updateCells(boolean resetChildren) {
+    /** {@inheritDoc} */
+    @Override void updateCells(boolean resetChildren) {
         super.updateCells(resetChildren);
 
         if (resetChildren) {
             childrenDirty = true;
             updateChildren();
         }
     }
 
-    @Override protected boolean isIndentationRequired() {
+    /** {@inheritDoc} */
+    @Override boolean isIndentationRequired() {
         return true;
     }
 
-    @Override protected TableColumnBase getTreeColumn() {
+    /** {@inheritDoc} */
+    @Override TableColumnBase getTreeColumn() {
         return getSkinnable().getTreeTableView().getTreeColumn();
     }
 
-    @Override protected int getIndentationLevel(TreeTableRow<T> control) {
+    /** {@inheritDoc} */
+    @Override int getIndentationLevel(TreeTableRow<T> control) {
         return control.getTreeTableView().getTreeItemLevel(control.getTreeItem());
     }
 
-    @Override protected double getIndentationPerLevel() {
+    /** {@inheritDoc} */
+    @Override double getIndentationPerLevel() {
         return getIndent();
     }
 
-    @Override protected Node getDisclosureNode() {
+    /** {@inheritDoc} */
+    @Override Node getDisclosureNode() {
         return getSkinnable().getDisclosureNode();
     }
 
-    @Override protected boolean isDisclosureNodeVisible() {
+    @Override boolean isDisclosureNodeVisible() {
         return getDisclosureNode() != null && treeItem != null && ! treeItem.isLeaf();
     }
 
-    @Override protected boolean isShowRoot() {
+    @Override boolean isShowRoot() {
         return getSkinnable().getTreeTableView().isShowRoot();
     }
 
-    @Override protected ObservableList<TreeTableColumn<T, ?>> getVisibleLeafColumns() {
+    /** {@inheritDoc} */
+    @Override ObservableList<TreeTableColumn<T, ?>> getVisibleLeafColumns() {
         return getSkinnable().getTreeTableView().getVisibleLeafColumns();
     }
 
-    @Override protected void updateCell(TreeTableCell<T, ?> cell, TreeTableRow<T> row) {
+    /** {@inheritDoc} */
+    @Override void updateCell(TreeTableCell<T, ?> cell, TreeTableRow<T> row) {
         cell.updateTreeTableRow(row);
     }
 
-    @Override protected boolean isColumnPartiallyOrFullyVisible(TableColumnBase tc) {
+    /** {@inheritDoc} */
+    @Override boolean isColumnPartiallyOrFullyVisible(TableColumnBase tc) {
         return treeTableViewSkin == null ? false : treeTableViewSkin.isColumnPartiallyOrFullyVisible(tc);
     }
 
-    @Override protected TreeTableColumn<T, ?> getTableColumnBase(TreeTableCell cell) {
+    /** {@inheritDoc} */
+    @Override TreeTableColumn<T, ?> getTableColumnBase(TreeTableCell cell) {
         return cell.getTableColumn();
     }
 
-    @Override protected ObjectProperty<Node> graphicProperty() {
+    /** {@inheritDoc} */
+    @Override ObjectProperty<Node> graphicProperty() {
         TreeTableRow<T> treeTableRow = getSkinnable();
         if (treeTableRow == null) return null;
         if (treeItem == null) return null;
 
         return treeItem.graphicProperty();
     }
 
-    @Override protected Control getVirtualFlowOwner() {
+    /** {@inheritDoc} */
+    @Override Control getVirtualFlowOwner() {
         return getSkinnable().getTreeTableView();
     }
 
-    @Override protected DoubleProperty fixedCellSizeProperty() {
+    /** {@inheritDoc} */
+    @Override DoubleProperty fixedCellSizeProperty() {
         return getSkinnable().getTreeTableView().fixedCellSizeProperty();
     }
 
-
-
-    /***************************************************************************
-     *                                                                         *
-     * Private Implementation                                                  *
-     *                                                                         *
-     **************************************************************************/
-
     private void updateTreeItem() {
         if (treeItem != null) {
-            treeItemListener.unregisterChangeListener(treeItem.expandedProperty());
-            treeItemListener.unregisterChangeListener(treeItem.graphicProperty());
+            treeItem.graphicProperty().removeListener(graphicListener);
         }
         treeItem = getSkinnable().getTreeItem();
         if (treeItem != null) {
-            treeItemListener.registerChangeListener(treeItem.graphicProperty(), "GRAPHIC");
+            treeItem.graphicProperty().addListener(graphicListener);
         }
     }
     
     private void updateDisclosureNodeAndGraphic() {
         if (getSkinnable().isEmpty()) return;

@@ -385,11 +409,11 @@
             STYLEABLES = Collections.unmodifiableList(styleables);
         }
     }
     
     /**
-     * @return The CssMetaData associated with this class, which may include the
+     * Returns the CssMetaData associated with this class, which may include the
      * CssMetaData of its super classes.
      */
     public static List<CssMetaData<? extends Styleable, ?>> getClassCssMetaData() {
         return StyleableProperties.STYLEABLES;
     }

@@ -400,13 +424,12 @@
     @Override public List<CssMetaData<? extends Styleable, ?>> getCssMetaData() {
         return getClassCssMetaData();
     }
 
 
-
-    @Override
-    protected Object queryAccessibleAttribute(AccessibleAttribute attribute, Object... parameters) {
+    /** {@inheritDoc} */
+    @Override protected Object queryAccessibleAttribute(AccessibleAttribute attribute, Object... parameters) {
         final TreeTableView<T> treeTableView = getSkinnable().getTreeTableView();
         switch (attribute) {
             case SELECTED_ITEMS: {
                 // FIXME this could be optimised to iterate over cellsMap only
                 // (selectedCells could be big, cellsMap is much smaller)