diff --git a/modules/javafx.controls/src/main/java/javafx/scene/control/skin/NestedTableColumnHeader.java b/modules/javafx.controls/src/main/java/javafx/scene/control/skin/NestedTableColumnHeader.java
index 20e06fae49e..c34524be811 100644
--- a/modules/javafx.controls/src/main/java/javafx/scene/control/skin/NestedTableColumnHeader.java
+++ b/modules/javafx.controls/src/main/java/javafx/scene/control/skin/NestedTableColumnHeader.java
@@ -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;
+
/**
*
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.
diff --git a/modules/javafx.controls/src/main/java/javafx/scene/control/skin/TableColumnHeader.java b/modules/javafx.controls/src/main/java/javafx/scene/control/skin/TableColumnHeader.java
index daee836443e..c3eefee5b3f 100644
--- a/modules/javafx.controls/src/main/java/javafx/scene/control/skin/TableColumnHeader.java
+++ b/modules/javafx.controls/src/main/java/javafx/scene/control/skin/TableColumnHeader.java
@@ -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.
+ *
+ * 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
+ */
+ 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 void resizeColumnToFitContent(TableView tv, TableColumn tc, TableViewSkinBase tableSkin, int maxRows) {
+ List> items = tv.getItems();
+ if (items == null || items.isEmpty()) return;
+
+ Callback/*, TableCell>*/ cellFactory = tc.getCellFactory();
+ if (cellFactory == null) return;
+
+ TableCell cell = (TableCell) 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 void resizeColumnToFitContent(TreeTableView ttv, TreeTableColumn 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 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 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);
}
}
diff --git a/modules/javafx.controls/src/main/java/javafx/scene/control/skin/TableSkinUtils.java b/modules/javafx.controls/src/main/java/javafx/scene/control/skin/TableSkinUtils.java
index f1e0419346b..2914e7368f5 100644
--- a/modules/javafx.controls/src/main/java/javafx/scene/control/skin/TableSkinUtils.java
+++ b/modules/javafx.controls/src/main/java/javafx/scene/control/skin/TableSkinUtils.java
@@ -71,179 +71,6 @@ public static boolean resizeColumn(TableViewSkinBase,?,?,?,?> tableSkin, Table
return false;
}
- /*
- * 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.
- */
- /** {@inheritDoc} */
- public static void resizeColumnToFitContent(TableViewSkinBase,?,?,?,?> tableSkin, TableColumnBase,?> tc, int maxRows) {
- if (!tc.isResizable()) return;
-
- Object control = tableSkin.getSkinnable();
- if (control instanceof TableView) {
- resizeColumnToFitContent((TableView)control, (TableColumn)tc, tableSkin, maxRows);
- } else if (control instanceof TreeTableView) {
- resizeColumnToFitContent((TreeTableView)control, (TreeTableColumn)tc, tableSkin, maxRows);
- }
- }
-
- private static void resizeColumnToFitContent(TableView tv, TableColumn tc, TableViewSkinBase tableSkin, int maxRows) {
- List> items = tv.getItems();
- if (items == null || items.isEmpty()) return;
-
- Callback/*, TableCell>*/ cellFactory = tc.getCellFactory();
- if (cellFactory == null) return;
-
- TableCell cell = (TableCell) 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) {
- resizeColumnToFitContent(tableSkin, tc.getColumns().get(size - 1), maxRows);
- return;
- }
-
- resizeColumn(tableSkin, tc, Math.round(maxWidth - tc.getWidth()));
- } else {
- TableColumnBaseHelper.setWidth(tc, maxWidth);
- }
- }
-
-
- /*
- * 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.
- */
- private static void resizeColumnToFitContent(TreeTableView ttv, TreeTableColumn 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 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 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) {
- resizeColumnToFitContent(tableSkin, tc.getColumns().get(size - 1), maxRows);
- return;
- }
-
- resizeColumn(tableSkin, tc, Math.round(maxWidth - tc.getWidth()));
- } else {
- TableColumnBaseHelper.setWidth(tc, maxWidth);
- }
- }
-
public static ObjectProperty> columnResizePolicyProperty(TableViewSkinBase,?,?,?,?> tableSkin) {
Object control = tableSkin.getSkinnable();
if (control instanceof TableView) {
diff --git a/modules/javafx.controls/src/shims/java/javafx/scene/control/skin/TableColumnHeaderShim.java b/modules/javafx.controls/src/shims/java/javafx/scene/control/skin/TableColumnHeaderShim.java
index 2cc4351363b..c1ee3b57d64 100644
--- a/modules/javafx.controls/src/shims/java/javafx/scene/control/skin/TableColumnHeaderShim.java
+++ b/modules/javafx.controls/src/shims/java/javafx/scene/control/skin/TableColumnHeaderShim.java
@@ -56,4 +56,8 @@ public static void columnReordering(TableColumnHeader header, double sceneX, dou
public static void columnReorderingComplete(TableColumnHeader header) {
header.columnReorderingComplete();
}
+
+ public static void resizeColumnToFitContent(TableColumnHeader header, int nbRows) {
+ header.resizeColumnToFitContent(nbRows);
+ }
}
diff --git a/modules/javafx.controls/src/test/java/test/javafx/scene/control/skin/TableColumnHeaderTest.java b/modules/javafx.controls/src/test/java/test/javafx/scene/control/skin/TableColumnHeaderTest.java
new file mode 100644
index 00000000000..6c043ab4d55
--- /dev/null
+++ b/modules/javafx.controls/src/test/java/test/javafx/scene/control/skin/TableColumnHeaderTest.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2018, 2019, 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
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * 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 test.javafx.scene.control.skin;
+
+import com.sun.javafx.tk.Toolkit;
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import javafx.scene.control.TableColumn;
+import javafx.scene.control.TableView;
+import javafx.scene.control.cell.PropertyValueFactory;
+import javafx.scene.control.skin.TableColumnHeader;
+import org.junit.Before;
+import org.junit.After;
+import org.junit.Test;
+import test.com.sun.javafx.scene.control.infrastructure.StageLoader;
+import test.com.sun.javafx.scene.control.infrastructure.VirtualFlowTestUtils;
+import test.com.sun.javafx.scene.control.test.Person;
+import javafx.scene.control.skin.TableColumnHeaderShim;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class TableColumnHeaderTest {
+
+ private TableColumnHeader firstColumnHeader;
+ private TableView tableView;
+ private StageLoader sl;
+ private static String NAME0 = "Humphrey McPhee";
+ private static String NAME1 = "Justice Caldwell";
+ private static String NAME2 = "Orrin Davies";
+ private static String NAME3 = "Emma Wilson";
+
+ @Before
+ public void before() {
+ ObservableList model = FXCollections.observableArrayList(
+ new Person(NAME0, 76),
+ new Person(NAME1, 30),
+ new Person(NAME2, 30),
+ new Person(NAME3, 8)
+ );
+ TableColumn column = new TableColumn<>("Col ");
+ column.setCellValueFactory(new PropertyValueFactory("firstName"));
+
+ tableView = new TableView<>(model);
+
+ tableView.getColumns().add(column);
+
+ sl = new StageLoader(tableView);
+ Toolkit tk = Toolkit.getToolkit();
+
+ tk.firePulse();
+ //Force the column to have default font, otherwise font Amble is applied and mess with header width size
+ column.setStyle("-fx-font: System;");
+ firstColumnHeader = VirtualFlowTestUtils.getTableColumnHeader(tableView, column);
+ }
+
+ @After
+ public void after() {
+ sl.dispose();
+ }
+
+ /**
+ * @test
+ * @bug 8207957
+ * Resize the column header without modifications
+ */
+ @Test
+ public void test_resizeColumnToFitContent() {
+ TableColumn column = tableView.getColumns().get(0);
+ double width = column.getWidth();
+ TableColumnHeaderShim.resizeColumnToFitContent(firstColumnHeader, -1);
+
+ assertEquals("Width must be the same",
+ width, column.getWidth(), 0.001);
+ }
+
+ /**
+ * @test
+ * @bug 8207957
+ * Resize the column header with first column increase
+ */
+ @Test
+ public void test_resizeColumnToFitContentIncrease() {
+ TableColumn column = tableView.getColumns().get(0);
+ double width = column.getWidth();
+
+ tableView.getItems().get(0).setFirstName("This is a big text inside that column");
+
+ assertEquals("Width must be the same",
+ width, column.getWidth(), 0.001);
+
+ TableColumnHeaderShim.resizeColumnToFitContent(firstColumnHeader, -1);
+ assertTrue("Column width must be greater",
+ width < column.getWidth());
+
+ //Back to initial value
+ tableView.getItems().get(0).setFirstName(NAME0);
+
+ TableColumnHeaderShim.resizeColumnToFitContent(firstColumnHeader, -1);
+ assertEquals("Width must be equal to initial value",
+ width, column.getWidth(), 0.001);
+ }
+
+ /**
+ * @test
+ * @bug 8207957
+ * Resize the column header with first column decrease
+ */
+ @Test
+ public void test_resizeColumnToFitContentDecrease() {
+ TableColumn column = tableView.getColumns().get(0);
+ double width = column.getWidth();
+
+ tableView.getItems().get(0).setFirstName("small");
+ tableView.getItems().get(1).setFirstName("small");
+ tableView.getItems().get(2).setFirstName("small");
+ tableView.getItems().get(3).setFirstName("small");
+
+ assertEquals("Width must be the same",
+ width, column.getWidth(), 0.001);
+
+ TableColumnHeaderShim.resizeColumnToFitContent(firstColumnHeader, -1);
+ assertTrue("Column width must be smaller",
+ width > column.getWidth());
+
+ //Back to initial value
+ tableView.getItems().get(0).setFirstName(NAME0);
+ tableView.getItems().get(1).setFirstName(NAME1);
+ tableView.getItems().get(2).setFirstName(NAME2);
+ tableView.getItems().get(3).setFirstName(NAME3);
+
+ TableColumnHeaderShim.resizeColumnToFitContent(firstColumnHeader, -1);
+ assertEquals("Width must be equal to initial value",
+ width, column.getWidth(), 0.001);
+ }
+
+ /**
+ * @test
+ * @bug 8207957
+ * Resize the column header itself
+ */
+ @Test
+ public void test_resizeColumnToFitContentHeader() {
+ TableColumn column = tableView.getColumns().get(0);
+ double width = column.getWidth();
+
+ column.setText("This is a big text inside that column");
+
+ assertEquals("Width must be the same",
+ width, column.getWidth(), 0.001);
+
+ TableColumnHeaderShim.resizeColumnToFitContent(firstColumnHeader, -1);
+ assertTrue("Column width must be greater",
+ width < column.getWidth());
+
+ //Back to initial value
+ column.setText("Col");
+ TableColumnHeaderShim.resizeColumnToFitContent(firstColumnHeader, 3);
+ assertEquals("Width must be equal to initial value",
+ width, column.getWidth(), 0.001);
+ }
+
+ /**
+ * @test
+ * @bug 8207957
+ * Resize the column header with only 3 first rows
+ */
+ @Test
+ public void test_resizeColumnToFitContentMaxRow() {
+ TableColumn column = tableView.getColumns().get(0);
+ double width = column.getWidth();
+
+ tableView.getItems().get(3).setFirstName("This is a big text inside that column");
+
+
+ TableColumnHeaderShim.resizeColumnToFitContent(firstColumnHeader, 3);
+ assertEquals("Width must be the same",
+ width, column.getWidth(), 0.001);
+
+
+ //Back to initial value
+ tableView.getItems().get(3).setFirstName(NAME3);
+
+
+ TableColumnHeaderShim.resizeColumnToFitContent(firstColumnHeader, 3);
+ assertEquals("Width must be equal to initial value",
+ width, column.getWidth(), 0.001);
+ }
+}