void (JTree tree, TreePath path, Rectangle bounds, int offset, long expected, Runnable done, AbstractTreeBuilder builder, int attempt) { Runnable scroll = () -> { Rectangle pathBounds = attempt <= 0 ? null : tree.getPathBounds(path); if (pathBounds != null) { Object property = tree.getClientProperty(TREE_UTIL_SCROLL_TIME_STAMP); long stamp = property instanceof Long ? (Long)property : Long.MAX_VALUE; if (LOG.isTraceEnabled()) LOG.debug("tree scroll ", attempt, stamp == expected ? ": try again: " : ": ignore: ", path); if (stamp == expected) { bounds.y = pathBounds.y - offset; // restore bounds according to the current row Rectangle visible = tree.getVisibleRect(); if (bounds.y < visible.y || bounds.y > visible.y + Math.max(0, visible.height - bounds.height)) { tree.scrollRectToVisible(bounds); scrollToVisible(tree, path, bounds, offset, expected, done, builder, attempt - 1); return; // try to scroll again } } } done.run(); }; SwingUtilities.invokeLater(builder == null ? scroll : () -> builder.getReady(TreeUtil.class).doWhenDone(scroll)); }