Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8207957: TableSkinUtils should not contain actual code implementation #6

Closed
wants to merge 14 commits into from
@@ -25,28 +25,28 @@

package javafx.scene.control.skin;

import com.sun.javafx.scene.control.skin.Utils;
import javafx.beans.property.ObjectProperty;
import javafx.collections.WeakListChangeListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.atomic.AtomicBoolean;

import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.collections.WeakListChangeListener;
import javafx.event.EventHandler;
import javafx.geometry.NodeOrientation;
import javafx.scene.Cursor;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.control.ResizeFeaturesBase;
import javafx.scene.control.TableColumnBase;
import javafx.scene.control.TableView;
import javafx.scene.control.TreeTableView;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.util.Callback;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;

/**
* <p>This class is used to construct the header of a TableView. We take the approach
* that every TableView header is nested - even if it isn't. This allows for us
@@ -165,7 +165,11 @@ public NestedTableColumnHeader(final TableColumnBase tc) {
if (me.getClickCount() == 2 && me.isPrimaryButtonDown()) {
// the user wants to resize the column such that its
// width is equal to the widest element in the column
TableSkinUtils.resizeColumnToFitContent(header.getTableSkin(), column, -1);
TableHeaderRow tableHeader = header.getTableHeaderRow();
TableColumnHeader columnHeader = tableHeader.getColumnHeaderFor(column);
if (columnHeader != null) {
columnHeader.resizeColumnToFitContent(-1);
}
} else {
// rather than refer to the rect variable, we just grab
// it from the source to prevent a small memory leak.
@@ -28,6 +28,8 @@
import com.sun.javafx.scene.control.LambdaMultiplePropertyChangeListenerHandler;
import com.sun.javafx.scene.control.Properties;
import com.sun.javafx.scene.control.TableColumnBaseHelper;
import com.sun.javafx.scene.control.TreeTableViewBackingList;
import com.sun.javafx.scene.control.skin.Utils;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.ReadOnlyObjectWrapper;
@@ -40,6 +42,7 @@
import javafx.css.Styleable;
import javafx.css.StyleableDoubleProperty;
import javafx.css.StyleableProperty;
import javafx.css.converter.SizeConverter;
import javafx.event.EventHandler;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
@@ -50,22 +53,27 @@
import javafx.scene.Node;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Label;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumnBase;
import javafx.scene.control.TableView;
import javafx.scene.control.TreeTableCell;
import javafx.scene.control.TreeTableColumn;
import javafx.scene.control.TreeTableRow;
import javafx.scene.control.TreeTableView;
import javafx.scene.input.ContextMenuEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;
import javafx.util.Callback;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;

import javafx.css.converter.SizeConverter;

import static com.sun.javafx.scene.control.TableColumnSortTypeWrapper.getSortTypeName;
import static com.sun.javafx.scene.control.TableColumnSortTypeWrapper.getSortTypeProperty;
import static com.sun.javafx.scene.control.TableColumnSortTypeWrapper.isAscending;
@@ -529,7 +537,7 @@ private void updateScene() {
if (getTableColumn() == null || getTableColumn().getWidth() != DEFAULT_COLUMN_WIDTH || getScene() == null) {
return;
}
doColumnAutoSize(getTableColumn(), n);
doColumnAutoSize(n);
autoSizeComplete = true;
}
}
@@ -581,13 +589,190 @@ private void initUI() {
}
}

private void doColumnAutoSize(TableColumnBase<?,?> column, int cellsToMeasure) {
double prefWidth = column.getPrefWidth();
private void doColumnAutoSize(int cellsToMeasure) {
double prefWidth = getTableColumn().getPrefWidth();

// if the prefWidth has been set, we do _not_ autosize columns
if (prefWidth == DEFAULT_COLUMN_WIDTH) {
TableSkinUtils.resizeColumnToFitContent(getTableSkin(), column, cellsToMeasure);
// getTableViewSkin().resizeColumnToFitContent(column, cellsToMeasure);
resizeColumnToFitContent(cellsToMeasure);
}
}

/**
* Resizes this {@code TableColumnHeader}'s column to fit the width of its content.
*
* @implSpec The resulting column width for this implementation is the maximum of the preferred width of the header
* cell and the preferred width of the first {@code maxRow} cells.
* <p>
* Subclasses can either use this method or override it (without the need to call {@code super()}) to provide their
* custom implementation (such as ones that exclude the header, exclude {@code null} content, compute the minimum
* width, etc.).
*
* @param maxRows the number of rows considered when resizing. If -1 is given, all rows are considered.
* @since 14
This conversation was marked as resolved by kevinrushforth

This comment has been minimized.

Copy link
@Maxoudela

Maxoudela Oct 9, 2019

Author

I have put the since 14, because if merged, it will be available in OpenJFX 14 right? (It was 13 before)

This comment has been minimized.

Copy link
@kevinrushforth

This comment has been minimized.

Copy link
@nlisker

nlisker Oct 29, 2019

Contributor

The "The resulting column width for this implementation..." part might belong in an @implSpec section.

This comment has been minimized.

Copy link
@Maxoudela

Maxoudela Oct 30, 2019

Author

From https://openjdk.java.net/jeps/8068562

Implementation Specification. This is where the default implementation (or an overrideable implementation in a class) is specified. Interface implementors or class subclassers use the information here in order to decide whether it is sensible or necessary to override a particular method, and what behavior they can rely on if a method is called via super.

So maybe the whole part beginning from "The resulting column [..]width etc.)." should be in the @implSpec section.

This comment has been minimized.

Copy link
@nlisker

nlisker Oct 30, 2019

Contributor

Yes.

*/
protected void resizeColumnToFitContent(int maxRows) {
TableColumnBase<?, ?> tc = getTableColumn();
if (!tc.isResizable()) return;

Object control = this.getTableSkin().getSkinnable();
if (control instanceof TableView) {
resizeColumnToFitContent((TableView) control, (TableColumn) tc, this.getTableSkin(), maxRows);
} else if (control instanceof TreeTableView) {
resizeColumnToFitContent((TreeTableView) control, (TreeTableColumn) tc, this.getTableSkin(), maxRows);
}
}

private <T,S> void resizeColumnToFitContent(TableView<T> tv, TableColumn<T, S> tc, TableViewSkinBase tableSkin, int maxRows) {
List<?> items = tv.getItems();
if (items == null || items.isEmpty()) return;

Callback/*<TableColumn<T, ?>, TableCell<T,?>>*/ cellFactory = tc.getCellFactory();
if (cellFactory == null) return;

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(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();
}

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(tv);
cell.updateIndex(row);

if ((cell.getText() != null && !cell.getText().isEmpty()) || cell.getGraphic() != null) {
tableSkin.getChildren().add(cell);
cell.applyCss();
maxWidth = Math.max(maxWidth, cell.prefWidth(-1));
tableSkin.getChildren().remove(cell);
}
}

// dispose of the cell to prevent it retaining listeners (see RT-31015)
cell.updateIndex(-1);

// RT-36855 - take into account the column header text / graphic widths.
// Magic 10 is to allow for sort arrow to appear without text truncation.
TableColumnHeader header = tableSkin.getTableHeaderRow().getColumnHeaderFor(tc);
double headerTextWidth = Utils.computeTextWidth(header.label.getFont(), tc.getText(), -1);
Node graphic = header.label.getGraphic();
double headerGraphicWidth = graphic == null ? 0 : graphic.prefWidth(-1) + header.label.getGraphicTextGap();
double headerWidth = headerTextWidth + headerGraphicWidth + 10 + header.snappedLeftInset() + header.snappedRightInset();
maxWidth = Math.max(maxWidth, headerWidth);

// RT-23486
maxWidth += padding;
if (tv.getColumnResizePolicy() == TableView.CONSTRAINED_RESIZE_POLICY && tv.getWidth() > 0) {
if (maxWidth > tc.getMaxWidth()) {
maxWidth = tc.getMaxWidth();
}

int size = tc.getColumns().size();
if (size > 0) {
TableColumnHeader columnHeader = getTableHeaderRow().getColumnHeaderFor(tc.getColumns().get(size - 1));
if (columnHeader != null) {
columnHeader.resizeColumnToFitContent(maxRows);
}
return;
}

TableSkinUtils.resizeColumn(tableSkin, tc, Math.round(maxWidth - tc.getWidth()));
} else {
TableColumnBaseHelper.setWidth(tc, maxWidth);
}
}

private <T,S> void resizeColumnToFitContent(TreeTableView<T> ttv, TreeTableColumn<T, S> tc, TableViewSkinBase tableSkin, int maxRows) {
List<?> items = new TreeTableViewBackingList(ttv);
if (items == null || items.isEmpty()) return;

Callback cellFactory = tc.getCellFactory();
if (cellFactory == null) return;

TreeTableCell<T,S> cell = (TreeTableCell) 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(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<T> treeTableRow = new TreeTableRow<>();
treeTableRow.updateTreeTableView(ttv);

int rows = maxRows == -1 ? items.size() : Math.min(items.size(), maxRows);
double maxWidth = 0;
for (int row = 0; row < rows; row++) {
treeTableRow.updateIndex(row);
treeTableRow.updateTreeItem(ttv.getTreeItem(row));

cell.updateTreeTableColumn(tc);
cell.updateTreeTableView(ttv);
cell.updateTreeTableRow(treeTableRow);
cell.updateIndex(row);

if ((cell.getText() != null && !cell.getText().isEmpty()) || cell.getGraphic() != null) {
tableSkin.getChildren().add(cell);
cell.applyCss();

double w = cell.prefWidth(-1);

maxWidth = Math.max(maxWidth, w);
tableSkin.getChildren().remove(cell);
}
}

// dispose of the cell to prevent it retaining listeners (see RT-31015)
cell.updateIndex(-1);

// RT-36855 - take into account the column header text / graphic widths.
// Magic 10 is to allow for sort arrow to appear without text truncation.
TableColumnHeader header = tableSkin.getTableHeaderRow().getColumnHeaderFor(tc);
double headerTextWidth = Utils.computeTextWidth(header.label.getFont(), tc.getText(), -1);
Node graphic = header.label.getGraphic();
double headerGraphicWidth = graphic == null ? 0 : graphic.prefWidth(-1) + header.label.getGraphicTextGap();
double headerWidth = headerTextWidth + headerGraphicWidth + 10 + header.snappedLeftInset() + header.snappedRightInset();
maxWidth = Math.max(maxWidth, headerWidth);

// RT-23486
maxWidth += padding;
if (ttv.getColumnResizePolicy() == TreeTableView.CONSTRAINED_RESIZE_POLICY && ttv.getWidth() > 0) {

if (maxWidth > tc.getMaxWidth()) {
maxWidth = tc.getMaxWidth();
}

int size = tc.getColumns().size();
if (size > 0) {
TableColumnHeader columnHeader = getTableHeaderRow().getColumnHeaderFor(tc.getColumns().get(size - 1));
if (columnHeader != null) {
columnHeader.resizeColumnToFitContent(maxRows);
}
return;
}

TableSkinUtils.resizeColumn(tableSkin, tc, Math.round(maxWidth - tc.getWidth()));
} else {
TableColumnBaseHelper.setWidth(tc, maxWidth);
}
}

ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.