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

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

@@ -21,11 +21,11 @@
  * 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.lang.ref.Reference;
 import java.lang.ref.WeakReference;
 import java.util.*;

@@ -45,17 +45,32 @@
 import javafx.scene.control.Control;
 import javafx.scene.control.IndexedCell;
 import javafx.scene.control.TableColumnBase;
 import javafx.util.Duration;
 
-import com.sun.javafx.scene.control.behavior.CellBehaviorBase;
 import com.sun.javafx.tk.Toolkit;
 
+/**
+ * TableRowSkinBase is the base skin class used by controls such as
+ * {@link javafx.scene.control.TableRow} and {@link javafx.scene.control.TreeTableRow}
+ * (the concrete classes are {@link TableRowSkin} and {@link TreeTableRowSkin},
+ * respectively).
+ *
+ * @param <T> The type of the cell (i.e. the generic type of the {@link IndexedCell} subclass).
+ * @param <C> The cell type (e.g. TableRow or TreeTableRow)
+ * @param <R> The type of cell that is contained within each row (e.g.
+ *           {@link javafx.scene.control.TableCell or {@link javafx.scene.control.TreeTableCell}}).
+ *
+ * @since 9
+ * @see javafx.scene.control.TableRow
+ * @see javafx.scene.control.TreeTableRow
+ * @see TableRowSkin
+ * @see TreeTableRowSkin
+ */
 public abstract class TableRowSkinBase<T,
                                        C extends IndexedCell/*<T>*/,
-                                       B extends CellBehaviorBase<C>,
-                                       R extends IndexedCell> extends CellSkinBase<C,B> {
+                                       R extends IndexedCell> extends CellSkinBase<C> {
 
     /***************************************************************************
      *                                                                         *
      * Static Fields                                                           *
      *                                                                         *

@@ -107,19 +122,19 @@
      * Note that this means that it is possible for this map to therefore be
      * a memory leak if an application uses TableView and is creating and removing
      * a large number of tableColumns. This is mitigated in the recreateCells()
      * function below - refer to that to learn more.
      */
-    protected WeakHashMap<TableColumnBase, Reference<R>> cellsMap;
+    WeakHashMap<TableColumnBase, Reference<R>> cellsMap;
 
     // This observableArrayList contains the currently visible table cells for this row.
-    protected final List<R> cells = new ArrayList<R>();
+    final List<R> cells = new ArrayList<>();
 
     private int fullRefreshCounter = DEFAULT_FULL_REFRESH_COUNTER;
 
-    protected boolean isDirty = false;
-    protected boolean updateCells = false;
+    boolean isDirty = false;
+    boolean updateCells = false;
 
     private double fixedCellSize;
     private boolean fixedCellSizeEnabled;
 
 

@@ -128,21 +143,19 @@
      *                                                                         *
      * Constructors                                                            *
      *                                                                         *
      **************************************************************************/
 
-    public TableRowSkinBase(C control, B behavior) {
-        super(control, behavior);
-
-        // init(control) should not be called here - it should be called by the
-        // subclass after initialising itself. This is to prevent NPEs (for
-        // example, getVisibleLeafColumns() throws a NPE as the control itself
-        // is not yet set in subclasses).
-    }
-
-    // init isn't a constructor, but it is part of the initialisation routine
-    protected void init(C control) {
+    /**
+     * Creates a new instance of TableRowSkinBase, although note that this
+     * instance does not handle any behavior / input mappings - this needs to be
+     * handled appropriately by subclasses.
+     *
+     * @param control The control that this skin should be installed onto.
+     */
+    public TableRowSkinBase(C control) {
+        super(control);
         getSkinnable().setPickOnBounds(false);
 
         recreateCells();
         updateCells(true);
 

@@ -155,14 +168,25 @@
 
 
         // use invalidation listener here to update even when item equality is true
         // (e.g. see RT-22463)
         control.itemProperty().addListener(o -> requestCellUpdate());
-        registerChangeListener(control.indexProperty(), "INDEX");
+        registerChangeListener(control.indexProperty(), e -> {
+            // Fix for RT-36661, where empty table cells were showing content, as they
+            // had incorrect table cell indices (but the table row index was correct).
+            // Note that we only do the update on empty cells to avoid the issue
+            // noted below in requestCellUpdate().
+            if (getSkinnable().isEmpty()) {
+                requestCellUpdate();
+            }
+        });
 
         if (fixedCellSizeProperty() != null) {
-            registerChangeListener(fixedCellSizeProperty(), "FIXED_CELL_SIZE");
+            registerChangeListener(fixedCellSizeProperty(), e -> {
+                fixedCellSize = fixedCellSizeProperty().get();
+                fixedCellSizeEnabled = fixedCellSize > 0;
+            });
             fixedCellSize = fixedCellSizeProperty().get();
             fixedCellSizeEnabled = fixedCellSize > 0;
         }
     }
 

@@ -194,53 +218,37 @@
      * Returns the graphic to draw on the inside of the disclosure node. Null
      * is acceptable when no graphic should be shown. Commonly this is the
      * graphic associated with a TreeItem (i.e. treeItem.getGraphic()), rather
      * than a graphic associated with a cell.
      */
-    protected abstract ObjectProperty<Node> graphicProperty();
+    abstract ObjectProperty<Node> graphicProperty();
 
     // return TableView / TreeTableView / etc
-    protected abstract Control getVirtualFlowOwner();
+    abstract Control getVirtualFlowOwner();
 
-    protected abstract ObservableList<? extends TableColumnBase/*<T,?>*/> getVisibleLeafColumns();
+    abstract ObservableList<? extends TableColumnBase/*<T,?>*/> getVisibleLeafColumns();
 
     // cell.updateTableRow(skinnable); (i.e cell.updateTableRow(row))
-    protected abstract void updateCell(R cell, C row);
+    abstract void updateCell(R cell, C row);
 
-    protected abstract DoubleProperty fixedCellSizeProperty();
+    abstract DoubleProperty fixedCellSizeProperty();
 
-    protected abstract boolean isColumnPartiallyOrFullyVisible(TableColumnBase tc);
+    abstract boolean isColumnPartiallyOrFullyVisible(TableColumnBase tc);
 
-    protected abstract R getCell(TableColumnBase tc);
+    abstract R getCell(TableColumnBase tc);
 
-    protected abstract TableColumnBase<T,?> getTableColumnBase(R cell);
+    abstract TableColumnBase<T,?> getTableColumnBase(R cell);
 
 
 
     /***************************************************************************
      *                                                                         *
      * Public Methods                                                          *
      *                                                                         *
      **************************************************************************/
 
-    @Override protected void handleControlPropertyChanged(String p) {
-        super.handleControlPropertyChanged(p);
-
-        if ("INDEX".equals(p)) {
-            // Fix for RT-36661, where empty table cells were showing content, as they
-            // had incorrect table cell indices (but the table row index was correct).
-            // Note that we only do the update on empty cells to avoid the issue
-            // noted below in requestCellUpdate().
-            if (getSkinnable().isEmpty()) {
-                requestCellUpdate();
-            }
-        } else if ("FIXED_CELL_SIZE".equals(p)) {
-            fixedCellSize = fixedCellSizeProperty().get();
-            fixedCellSizeEnabled = fixedCellSize > 0;
-        }
-    }
-
+    /** {@inheritDoc} */
     @Override protected void layoutChildren(double x, final double y, final double w, final double h) {
         checkState();
         if (cellsMap.isEmpty()) return;
 
         ObservableList<? extends TableColumnBase> visibleLeafColumns = getVisibleLeafColumns();

@@ -440,58 +448,58 @@
 
             x += width;
         }
     }
 
-    protected int getIndentationLevel(C control) {
+    int getIndentationLevel(C control) {
         return 0;
     }
 
-    protected double getIndentationPerLevel() {
+    double getIndentationPerLevel() {
         return 0;
     }
 
     /**
      * Used to represent whether the current virtual flow owner is wanting
      * indentation to be used in this table row.
      */
-    protected boolean isIndentationRequired() {
+    boolean isIndentationRequired() {
         return false;
     }
 
     /**
      * Returns the table column that should show the disclosure nodes and / or
      * a graphic. By default this is the left-most column.
      */
-    protected TableColumnBase getTreeColumn() {
+    TableColumnBase getTreeColumn() {
         return null;
     }
 
-    protected Node getDisclosureNode() {
+    Node getDisclosureNode() {
         return null;
     }
 
     /**
      * Used to represent whether a disclosure node is visible for _this_
      * table row. Not to be confused with isIndentationRequired(), which is the
      * more general API.
      */
-    protected boolean isDisclosureNodeVisible() {
+    boolean isDisclosureNodeVisible() {
         return false;
     }
 
-    protected boolean isShowRoot() {
+    boolean isShowRoot() {
         return true;
     }
 
-    protected TableColumnBase<T,?> getVisibleLeafColumn(int column) {
+    TableColumnBase<T,?> getVisibleLeafColumn(int column) {
         final List<? extends TableColumnBase/*<T,?>*/> visibleLeafColumns = getVisibleLeafColumns();
         if (column < 0 || column >= visibleLeafColumns.size()) return null;
         return visibleLeafColumns.get(column);
     }
 
-    protected void updateCells(boolean resetChildren) {
+    void updateCells(boolean resetChildren) {
         // To avoid a potential memory leak (when the TableColumns in the
         // TableView are created/inserted/removed/deleted, we have a 'refresh
         // counter' that when we reach 0 will delete all cells in this row
         // and recreate all of them.
         if (resetChildren) {

@@ -572,11 +580,11 @@
 
         // Support for RT-18467: making it easier to specify a height for
         // cells via CSS, where the desired height is less than the height
         // of the TableCells. Essentially, -fx-cell-size is given higher
         // precedence now
-        if (getCellSize() < CellSkinBase.DEFAULT_CELL_SIZE) {
+        if (getCellSize() < DEFAULT_CELL_SIZE) {
             return getCellSize();
         }
 
         // FIXME according to profiling, this method is slow and should
         // be optimised

@@ -601,11 +609,11 @@
 
         // Support for RT-18467: making it easier to specify a height for
         // cells via CSS, where the desired height is less than the height
         // of the TableCells. Essentially, -fx-cell-size is given higher
         // precedence now
-        if (getCellSize() < CellSkinBase.DEFAULT_CELL_SIZE) {
+        if (getCellSize() < DEFAULT_CELL_SIZE) {
             return getCellSize();
         }
 
         // FIXME according to profiling, this method is slow and should
         // be optimised

@@ -623,12 +631,11 @@
             return fixedCellSize;
         }
         return super.computeMaxHeight(width, topInset, rightInset, bottomInset, leftInset);
     }
 
-    // protected to allow subclasses to ensure a consistent state during layout
-    protected final void checkState() {
+    final void checkState() {
         if (isDirty) {
             updateCells(true);
             isDirty = false;
         } else if (updateCells) {
             updateCells(false);