From 13d8b77b14ecf4b1f001f2cb19761be0370c0ded Mon Sep 17 00:00:00 2001 From: Ziad El Midaoui Date: Wed, 12 Nov 2025 15:04:39 +0100 Subject: [PATCH 1/4] Added new treeStructureDirty --- .../javafx/scene/control/skin/TreeTableViewSkin.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/modules/javafx.controls/src/main/java/javafx/scene/control/skin/TreeTableViewSkin.java b/modules/javafx.controls/src/main/java/javafx/scene/control/skin/TreeTableViewSkin.java index e8a80754813..e9be88f15a9 100644 --- a/modules/javafx.controls/src/main/java/javafx/scene/control/skin/TreeTableViewSkin.java +++ b/modules/javafx.controls/src/main/java/javafx/scene/control/skin/TreeTableViewSkin.java @@ -69,7 +69,7 @@ public class TreeTableViewSkin extends TableViewSkinBase, Tree ObjectProperty>> tableBackingListProperty; private final TreeTableViewBehavior behavior; private final EventHandler> rootListener; - + private boolean treeStructureDirty; /* ************************************************************************* @@ -147,6 +147,12 @@ public TreeTableViewSkin(final TreeTableView control) { control.requestLayout(); break; } + else if (eventType.equals(TreeItem.childrenModificationEvent())) { + markItemCountDirty(); + treeStructureDirty = true; + control.requestLayout(); + break; + } eventType = eventType.getSuperType(); } } @@ -347,6 +353,10 @@ private TreeTableRow createCell() { // A unit test exists in TreeTableViewTest to ensure that // the performance issue covered in JDK-8147483 doesn't regress. // requestRebuildCells(); + treeStructureDirty = false; + } else if (treeStructureDirty) { + requestRebuildCells(); + treeStructureDirty = false; } else { needCellsReconfigured = true; } From 4a07d87eb632f73fd733178522a80f7edb81d0bd Mon Sep 17 00:00:00 2001 From: Ziad El Midaoui Date: Thu, 13 Nov 2025 19:45:22 +0100 Subject: [PATCH 2/4] Add test --- .../scene/control/TreeTableViewTest.java | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/modules/javafx.controls/src/test/java/test/javafx/scene/control/TreeTableViewTest.java b/modules/javafx.controls/src/test/java/test/javafx/scene/control/TreeTableViewTest.java index d5946742da3..7d969e85c73 100644 --- a/modules/javafx.controls/src/test/java/test/javafx/scene/control/TreeTableViewTest.java +++ b/modules/javafx.controls/src/test/java/test/javafx/scene/control/TreeTableViewTest.java @@ -6439,6 +6439,70 @@ private void test_rt_40319(boolean toRight, boolean toBottom, boolean useMouse) sl.dispose(); } + @Test + void test_jdk_8356770_reparentingItem() { + TreeItem itemA1 = new TreeItem<>("item A1"); + TreeItem itemA2 = new TreeItem<>("item A2"); + TreeItem itemA = new TreeItem<>("item A"); + itemA.getChildren().addAll(itemA1, itemA2); + itemA.setExpanded(true); + + TreeItem itemB1 = new TreeItem<>("item B1"); + TreeItem itemB2 = new TreeItem<>("item B2"); + TreeItem itemB = new TreeItem<>("item B"); + itemB.getChildren().addAll(itemB1, itemB2); + itemB.setExpanded(true); + + TreeItem root = new TreeItem<>("Root"); + root.getChildren().addAll(itemA, itemB); + root.setExpanded(true); + + TreeTableView table = new TreeTableView<>(); + TreeTableColumn col = new TreeTableColumn<>("Name"); + col.setCellValueFactory(cd -> new SimpleStringProperty(cd.getValue().getValue())); + table.getColumns().add(col); + table.setRoot(root); + table.setShowRoot(true); + + stageLoader = new StageLoader(table); + Toolkit.getToolkit().firePulse(); + + // Find "item B" row and record its disclosure node indent + TreeTableRow rowBefore = findRow(table, "item B"); + assertNotNull(rowBefore, "item B row should not be null"); + double xBefore = disclosureX(rowBefore); + + // Reparenting "item B" under "item A" + root.getChildren().remove(itemB); + itemA.getChildren().add(itemB); + Toolkit.getToolkit().firePulse(); + + TreeTableRow rowAfter = findRow(table, "item B"); + assertNotNull(rowAfter, "item B row should not be null"); + double xAfter = disclosureX(rowAfter); + + assertTrue(xAfter > xBefore, + "Indentation of item B must increase after reparenting"); + } + + private static TreeTableRow findRow(TreeTableView table, String value) { + for (Node n : table.lookupAll(".tree-table-row-cell")) { + if (n instanceof TreeTableRow) { + TreeTableRow row = (TreeTableRow) n; + TreeItem ti = row.getTreeItem(); + if (ti != null && value.equals(ti.getValue())) { + return row; + } + } + } + return null; + } + + private static double disclosureX(TreeTableRow row) { + Node disclosureNode = row.lookup(".tree-disclosure-node"); + return disclosureNode == null ? 0.0 : (disclosureNode.getLayoutX() + disclosureNode.getTranslateX()); + } + @Test public void test_jdk_8144681_removeColumn() { TreeTableView table = new TreeTableView<>(); From 58f9f4e7483a1f60e0ae4a24bc18d0766050f62a Mon Sep 17 00:00:00 2001 From: Ziad El Midaoui Date: Fri, 14 Nov 2025 16:44:55 +0100 Subject: [PATCH 3/4] Minor test changes --- .../scene/control/skin/TreeTableViewSkin.java | 3 +- .../scene/control/TreeTableViewTest.java | 33 ++++++------------- 2 files changed, 11 insertions(+), 25 deletions(-) diff --git a/modules/javafx.controls/src/main/java/javafx/scene/control/skin/TreeTableViewSkin.java b/modules/javafx.controls/src/main/java/javafx/scene/control/skin/TreeTableViewSkin.java index e9be88f15a9..f9a660de45d 100644 --- a/modules/javafx.controls/src/main/java/javafx/scene/control/skin/TreeTableViewSkin.java +++ b/modules/javafx.controls/src/main/java/javafx/scene/control/skin/TreeTableViewSkin.java @@ -146,8 +146,7 @@ public TreeTableViewSkin(final TreeTableView control) { markItemCountDirty(); control.requestLayout(); break; - } - else if (eventType.equals(TreeItem.childrenModificationEvent())) { + } else if (eventType.equals(TreeItem.childrenModificationEvent())) { markItemCountDirty(); treeStructureDirty = true; control.requestLayout(); diff --git a/modules/javafx.controls/src/test/java/test/javafx/scene/control/TreeTableViewTest.java b/modules/javafx.controls/src/test/java/test/javafx/scene/control/TreeTableViewTest.java index 7d969e85c73..660cdb5aabc 100644 --- a/modules/javafx.controls/src/test/java/test/javafx/scene/control/TreeTableViewTest.java +++ b/modules/javafx.controls/src/test/java/test/javafx/scene/control/TreeTableViewTest.java @@ -6439,8 +6439,12 @@ private void test_rt_40319(boolean toRight, boolean toBottom, boolean useMouse) sl.dispose(); } + /** + * Reparenting a TreeItem must update its indentation in the TreeTableView. + * See also: JDK-8356770 + */ @Test - void test_jdk_8356770_reparentingItem() { + void testIndentationUpdateAfterReparenting() { TreeItem itemA1 = new TreeItem<>("item A1"); TreeItem itemA2 = new TreeItem<>("item A2"); TreeItem itemA = new TreeItem<>("item A"); @@ -6465,41 +6469,24 @@ void test_jdk_8356770_reparentingItem() { table.setShowRoot(true); stageLoader = new StageLoader(table); - Toolkit.getToolkit().firePulse(); // Find "item B" row and record its disclosure node indent - TreeTableRow rowBefore = findRow(table, "item B"); - assertNotNull(rowBefore, "item B row should not be null"); - double xBefore = disclosureX(rowBefore); + double xBefore = disclosureIndent(table,4); // Reparenting "item B" under "item A" root.getChildren().remove(itemB); itemA.getChildren().add(itemB); Toolkit.getToolkit().firePulse(); - TreeTableRow rowAfter = findRow(table, "item B"); - assertNotNull(rowAfter, "item B row should not be null"); - double xAfter = disclosureX(rowAfter); + double xAfter = disclosureIndent(table,4); assertTrue(xAfter > xBefore, "Indentation of item B must increase after reparenting"); } - private static TreeTableRow findRow(TreeTableView table, String value) { - for (Node n : table.lookupAll(".tree-table-row-cell")) { - if (n instanceof TreeTableRow) { - TreeTableRow row = (TreeTableRow) n; - TreeItem ti = row.getTreeItem(); - if (ti != null && value.equals(ti.getValue())) { - return row; - } - } - } - return null; - } - - private static double disclosureX(TreeTableRow row) { - Node disclosureNode = row.lookup(".tree-disclosure-node"); + private double disclosureIndent(TreeTableView table, int index) { + TreeTableRow row = (TreeTableRow) VirtualFlowTestUtils.getVirtualFlow(table).getVisibleCell(index); + Node disclosureNode = row.getDisclosureNode(); return disclosureNode == null ? 0.0 : (disclosureNode.getLayoutX() + disclosureNode.getTranslateX()); } From e160a15ae085e41605392570316dde1ed1bd5774 Mon Sep 17 00:00:00 2001 From: Ziad El Midaoui Date: Sat, 15 Nov 2025 03:32:59 +0100 Subject: [PATCH 4/4] minor change --- .../java/test/javafx/scene/control/TreeTableViewTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/javafx.controls/src/test/java/test/javafx/scene/control/TreeTableViewTest.java b/modules/javafx.controls/src/test/java/test/javafx/scene/control/TreeTableViewTest.java index 660cdb5aabc..d6900c20e3e 100644 --- a/modules/javafx.controls/src/test/java/test/javafx/scene/control/TreeTableViewTest.java +++ b/modules/javafx.controls/src/test/java/test/javafx/scene/control/TreeTableViewTest.java @@ -6471,14 +6471,14 @@ void testIndentationUpdateAfterReparenting() { stageLoader = new StageLoader(table); // Find "item B" row and record its disclosure node indent - double xBefore = disclosureIndent(table,4); + double xBefore = disclosureIndent(table, 4); // Reparenting "item B" under "item A" root.getChildren().remove(itemB); itemA.getChildren().add(itemB); Toolkit.getToolkit().firePulse(); - double xAfter = disclosureIndent(table,4); + double xAfter = disclosureIndent(table, 4); assertTrue(xAfter > xBefore, "Indentation of item B must increase after reparenting");