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,31 **** * 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.lang.ref.Reference; import java.lang.ref.WeakReference; import java.util.*; --- 21,31 ---- * 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.lang.ref.Reference; import java.lang.ref.WeakReference; import java.util.*;
*** 45,61 **** 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; public abstract class TableRowSkinBase<T, C extends IndexedCell/*<T>*/, ! B extends CellBehaviorBase<C>, ! R extends IndexedCell> extends CellSkinBase<C,B> { /*************************************************************************** * * * Static Fields * * * --- 45,76 ---- import javafx.scene.control.Control; import javafx.scene.control.IndexedCell; import javafx.scene.control.TableColumnBase; import javafx.util.Duration; 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>*/, ! R extends IndexedCell> extends CellSkinBase<C> { /*************************************************************************** * * * Static Fields * * *
*** 107,125 **** * 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; // This observableArrayList contains the currently visible table cells for this row. ! protected final List<R> cells = new ArrayList<R>(); private int fullRefreshCounter = DEFAULT_FULL_REFRESH_COUNTER; ! protected boolean isDirty = false; ! protected boolean updateCells = false; private double fixedCellSize; private boolean fixedCellSizeEnabled; --- 122,140 ---- * 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. */ ! WeakHashMap<TableColumnBase, Reference<R>> cellsMap; // This observableArrayList contains the currently visible table cells for this row. ! final List<R> cells = new ArrayList<>(); private int fullRefreshCounter = DEFAULT_FULL_REFRESH_COUNTER; ! boolean isDirty = false; ! boolean updateCells = false; private double fixedCellSize; private boolean fixedCellSizeEnabled;
*** 128,148 **** * * * 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) { getSkinnable().setPickOnBounds(false); recreateCells(); updateCells(true); --- 143,161 ---- * * * Constructors * * * **************************************************************************/ ! /** ! * 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,168 **** // 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"); if (fixedCellSizeProperty() != null) { ! registerChangeListener(fixedCellSizeProperty(), "FIXED_CELL_SIZE"); fixedCellSize = fixedCellSizeProperty().get(); fixedCellSizeEnabled = fixedCellSize > 0; } } --- 168,192 ---- // 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(), 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(), e -> { ! fixedCellSize = fixedCellSizeProperty().get(); ! fixedCellSizeEnabled = fixedCellSize > 0; ! }); fixedCellSize = fixedCellSizeProperty().get(); fixedCellSizeEnabled = fixedCellSize > 0; } }
*** 194,246 **** * 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(); // return TableView / TreeTableView / etc ! protected abstract Control getVirtualFlowOwner(); ! protected abstract ObservableList<? extends TableColumnBase/*<T,?>*/> getVisibleLeafColumns(); // cell.updateTableRow(skinnable); (i.e cell.updateTableRow(row)) ! protected abstract void updateCell(R cell, C row); ! protected abstract DoubleProperty fixedCellSizeProperty(); ! protected abstract boolean isColumnPartiallyOrFullyVisible(TableColumnBase tc); ! protected abstract R getCell(TableColumnBase tc); ! protected 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; ! } ! } ! @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(); --- 218,254 ---- * 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. */ ! abstract ObjectProperty<Node> graphicProperty(); // return TableView / TreeTableView / etc ! abstract Control getVirtualFlowOwner(); ! abstract ObservableList<? extends TableColumnBase/*<T,?>*/> getVisibleLeafColumns(); // cell.updateTableRow(skinnable); (i.e cell.updateTableRow(row)) ! abstract void updateCell(R cell, C row); ! abstract DoubleProperty fixedCellSizeProperty(); ! abstract boolean isColumnPartiallyOrFullyVisible(TableColumnBase tc); ! abstract R getCell(TableColumnBase tc); ! abstract TableColumnBase<T,?> getTableColumnBase(R cell); /*************************************************************************** * * * Public Methods * * * **************************************************************************/ ! /** {@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,497 **** x += width; } } ! protected int getIndentationLevel(C control) { return 0; } ! protected 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() { 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() { return null; } ! protected 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() { return false; } ! protected boolean isShowRoot() { return true; } ! protected 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) { // 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) { --- 448,505 ---- x += width; } } ! int getIndentationLevel(C control) { return 0; } ! double getIndentationPerLevel() { return 0; } /** * Used to represent whether the current virtual flow owner is wanting * indentation to be used in this table row. */ ! 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. */ ! TableColumnBase getTreeColumn() { return null; } ! 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. */ ! boolean isDisclosureNodeVisible() { return false; } ! boolean isShowRoot() { return true; } ! TableColumnBase<T,?> getVisibleLeafColumn(int column) { final List<? extends TableColumnBase/*<T,?>*/> visibleLeafColumns = getVisibleLeafColumns(); if (column < 0 || column >= visibleLeafColumns.size()) return null; return visibleLeafColumns.get(column); } ! 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,582 **** // 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) { return getCellSize(); } // FIXME according to profiling, this method is slow and should // be optimised --- 580,590 ---- // 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() < DEFAULT_CELL_SIZE) { return getCellSize(); } // FIXME according to profiling, this method is slow and should // be optimised
*** 601,611 **** // 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) { return getCellSize(); } // FIXME according to profiling, this method is slow and should // be optimised --- 609,619 ---- // 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() < DEFAULT_CELL_SIZE) { return getCellSize(); } // FIXME according to profiling, this method is slow and should // be optimised
*** 623,634 **** 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() { if (isDirty) { updateCells(true); isDirty = false; } else if (updateCells) { updateCells(false); --- 631,641 ---- return fixedCellSize; } return super.computeMaxHeight(width, topInset, rightInset, bottomInset, leftInset); } ! final void checkState() { if (isDirty) { updateCells(true); isDirty = false; } else if (updateCells) { updateCells(false);