diff --git a/modules/javafx.controls/src/main/java/javafx/scene/control/skin/VirtualFlow.java b/modules/javafx.controls/src/main/java/javafx/scene/control/skin/VirtualFlow.java index 02f4a3b723a..a1829b840a5 100644 --- a/modules/javafx.controls/src/main/java/javafx/scene/control/skin/VirtualFlow.java +++ b/modules/javafx.controls/src/main/java/javafx/scene/control/skin/VirtualFlow.java @@ -3069,45 +3069,51 @@ private void recalculateEstimatedSize() { recalculateAndImproveEstimatedSize(DEFAULT_IMPROVEMENT); } + private boolean recalculating = false; + private void recalculateAndImproveEstimatedSize(int improve) { - int itemCount = getCellCount(); - int cacheCount = itemSizeCache.size(); - boolean keepRatio = ((cacheCount > 0) && !Double.isInfinite(this.absoluteOffset)); - double estSize = estimatedSize / itemCount; - - int oldIndex = computeCurrentIndex(); - double oldOffset = computeViewportOffset(getPosition()); - int added = 0; - while ((itemCount > itemSizeCache.size()) && (added < improve)) { - getOrCreateCellSize(itemSizeCache.size()); - added++; - } - cacheCount = itemSizeCache.size(); - int cnt = 0; - double tot = 0d; - for (int i = 0; (i < itemCount && i < cacheCount); i++) { - Double il = itemSizeCache.get(i); - if (il != null) { - tot = tot + il; - cnt++; - } - } - this.estimatedSize = cnt == 0 ? 1d : tot * itemCount / cnt; - estSize = estimatedSize / itemCount; - - if (keepRatio) { - double newOffset = 0; - for (int i = 0; i < oldIndex; i++) { - double h = getCellSize(i); - if (h < 0) { - h = estSize; + if (recalculating) return; + recalculating = true; + try { + int itemCount = getCellCount(); + int cacheCount = itemSizeCache.size(); + boolean keepRatio = ((cacheCount > 0) && !Double.isInfinite(this.absoluteOffset)); + + int oldIndex = computeCurrentIndex(); + double oldOffset = computeViewportOffset(getPosition()); + int added = 0; + while ((itemCount > itemSizeCache.size()) && (added < improve)) { + getOrCreateCellSize(itemSizeCache.size()); + added++; + } + cacheCount = itemSizeCache.size(); + int cnt = 0; + double tot = 0d; + for (int i = 0; (i < itemCount && i < cacheCount); i++) { + Double il = itemSizeCache.get(i); + if (il != null) { + tot = tot + il; + cnt++; } - newOffset += h; } - this.absoluteOffset = newOffset + oldOffset; - adjustPosition(); - } + this.estimatedSize = cnt == 0 ? 1d : tot * itemCount / cnt; + double estSize = estimatedSize / itemCount; + if (keepRatio) { + double newOffset = 0; + for (int i = 0; i < oldIndex; i++) { + double h = getCellSize(i); + if (h < 0) { + h = estSize; + } + newOffset += h; + } + this.absoluteOffset = newOffset + oldOffset; + adjustPosition(); + } + } finally { + recalculating = false; + } } private void resetSizeEstimates() { diff --git a/modules/javafx.controls/src/test/java/test/javafx/scene/control/TreeViewTest.java b/modules/javafx.controls/src/test/java/test/javafx/scene/control/TreeViewTest.java index ffc00ae9208..057c96a2eaf 100644 --- a/modules/javafx.controls/src/test/java/test/javafx/scene/control/TreeViewTest.java +++ b/modules/javafx.controls/src/test/java/test/javafx/scene/control/TreeViewTest.java @@ -3907,6 +3907,35 @@ public void testRemoveTreeItemFromCollapsedAncestorKeepsSelectedItem() { assertEquals("Node 0", table.getFocusModel().getFocusedItem().getValue()); } + private List> generateChildren(int lvl) { + List> children = new ArrayList<>(); + for (int idx = 0; idx < 10; idx++) { + TreeItem child = new TreeItem<>("Child lvl. " + lvl + " idx. " + idx); + child.setExpanded(true); + if (lvl <= 2) { + child.getChildren().addAll(generateChildren(lvl + 1)); + } + children.add(child); + } + return children; + } + + // JDK-8290348 + @Test + public void testCheckPositionAfterCollapsed() { + TreeItem rootNode = new TreeItem<>("Root"); + rootNode.setExpanded(true); + rootNode.getChildren().addAll(generateChildren(1)); + TreeView treeView = new TreeView<>(rootNode); + treeView.scrollTo(100); + IndexedCell expandedCell = VirtualFlowTestUtils.getCell(treeView, 100); + Toolkit.getToolkit().firePulse(); + rootNode.getChildren().get(1).setExpanded(false); + Toolkit.getToolkit().firePulse(); + IndexedCell scrolledCell = VirtualFlowTestUtils.getCell(treeView, 100); + assertTrue(scrolledCell.isVisible()); + } + public static class MisbehavingOnCancelTreeCell extends TreeCell { @Override