diff --git a/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/AbstractTreeViewer.java b/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/AbstractTreeViewer.java
index 585bcc1b7f7..e50d51b3fdf 100644
--- a/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/AbstractTreeViewer.java
+++ b/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/AbstractTreeViewer.java
@@ -28,7 +28,6 @@
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
-import java.util.function.Function;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IStatus;
@@ -1833,23 +1832,22 @@ protected Widget internalGetWidgetToSelect(Object elementOrTreePath) {
}
/**
- * Recursively, conditionally expands the subtree rooted at the given widget to
- * the given level. Takes the {@code shouldChildrenExpand} predicate that
- * defines for a given widget if it shall be expanded.
+ * Recursively expands the subtree rooted at the given widget to the given level
+ * based on the {@code childExpansionFunction} function being executed for a
+ * child to be (potentially conditionally) expanded.
*
* Note that the default implementation of this method does not call
* {@code setRedraw}.
*
*
- * @param widget the widget
- * @param level non-negative level, or {@code ALL_LEVELS} to
- * expand all levels of the tree
- * @param shouldChildrenExpand predicate that defines for a given widget if it
- * should be expanded.
- * @since 3.32
+ * @param widget the widget
+ * @param level non-negative level, or {@code ALL_LEVELS} to
+ * expand all levels of the tree
+ * @param childrenExpansionFunction function to be called on a child to be
+ * expanded
*/
- private void internalConditionalExpandToLevel(Widget widget, int level,
- Function shouldChildrenExpand) {
+ private void internalCustomizedExpandToLevel(Widget widget, int level,
+ CustomChildrenExpansionFunction childrenExpansionFunction) {
if (level == ALL_LEVELS || level > 0) {
Object data = widget.getData();
if (widget instanceof Item it && data != null && !isExpandable(it, null, data)) {
@@ -1861,19 +1859,18 @@ private void internalConditionalExpandToLevel(Widget widget, int level,
setExpanded(it, true);
}
if (level == ALL_LEVELS || level > 1) {
- Item[] children = getChildren(widget);
- if (children != null && shouldChildrenExpand.apply(widget).booleanValue()) {
- int newLevel = (level == ALL_LEVELS ? ALL_LEVELS
- : level - 1);
- for (Item element : children) {
- internalConditionalExpandToLevel(element, newLevel, shouldChildrenExpand);
- }
- }
+ int newLevel = (level == ALL_LEVELS ? ALL_LEVELS : level - 1);
+ childrenExpansionFunction.expandChildren(widget, newLevel);
}
// XXX expanding here fails on linux
}
}
+ @FunctionalInterface
+ private interface CustomChildrenExpansionFunction {
+ void expandChildren(Widget parent, int previousLevel);
+ }
+
/**
* Recursively expands the subtree rooted at the given widget to the given
* level.
@@ -1887,7 +1884,14 @@ private void internalConditionalExpandToLevel(Widget widget, int level,
* levels of the tree
*/
protected void internalExpandToLevel(Widget widget, int level) {
- internalConditionalExpandToLevel(widget, level, w -> Boolean.TRUE);
+ internalCustomizedExpandToLevel(widget, level, (parent, newLevel) -> {
+ Item[] children = getChildren(parent);
+ if (children != null) {
+ for (Item child : children) {
+ internalExpandToLevel(child, newLevel);
+ }
+ }
+ });
}
/**
@@ -2532,14 +2536,22 @@ public void treeCollapsed(TreeExpansionEvent event) {
@Override
public void treeExpanded(TreeExpansionEvent e) {
Widget item = doFindItem(e.getElement());
-
- internalConditionalExpandToLevel(item, autoExpandOnSingleChildLevels,
- w -> Boolean.valueOf(doesWidgetHaveExactlyOneChild(w)));
+ internalCustomizedExpandToLevel(item, autoExpandOnSingleChildLevels, singleChildExpansionFunction);
}
};
addTreeListener(autoExpandOnSingleChildListener);
}
+ private CustomChildrenExpansionFunction singleChildExpansionFunction = (widget, newLevel) -> {
+ Item[] children = getChildren(widget);
+ boolean hasExactlyOneChild = children != null && children.length == 1;
+ if (hasExactlyOneChild) {
+ for (Item child : children) {
+ internalCustomizedExpandToLevel(child, newLevel, this.singleChildExpansionFunction);
+ }
+ }
+ };
+
private void removeAutoExpandOnSingleChildListener() {
if (autoExpandOnSingleChildListener != null) {
removeTreeListener(autoExpandOnSingleChildListener);
@@ -2702,8 +2714,7 @@ public void setExpandedStateWithAutoExpandOnSingleChild(Object elementOrTreePath
Widget item = internalGetWidgetToSelect(elementOrTreePath);
if (autoExpandOnSingleChildLevels != NO_EXPAND && expanded) {
- internalConditionalExpandToLevel(item, autoExpandOnSingleChildLevels,
- w -> Boolean.valueOf(doesWidgetHaveExactlyOneChild(w)));
+ internalCustomizedExpandToLevel(item, autoExpandOnSingleChildLevels, singleChildExpansionFunction);
}
}
@@ -3535,8 +3546,4 @@ ISelection getUpdatedSelection(ISelection selection) {
return selection;
}
- private boolean doesWidgetHaveExactlyOneChild(Widget w) {
- return getChildren(w).length == 1;
- }
-
}
diff --git a/tests/org.eclipse.jface.tests/src/org/eclipse/jface/tests/viewers/TreeViewerTest.java b/tests/org.eclipse.jface.tests/src/org/eclipse/jface/tests/viewers/TreeViewerTest.java
index 4d2a2ca0a52..4d325a0202e 100644
--- a/tests/org.eclipse.jface.tests/src/org/eclipse/jface/tests/viewers/TreeViewerTest.java
+++ b/tests/org.eclipse.jface.tests/src/org/eclipse/jface/tests/viewers/TreeViewerTest.java
@@ -16,6 +16,13 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Queue;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+import org.eclipse.jface.viewers.AbstractTreeViewer;
import org.eclipse.jface.viewers.StructuredViewer;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.swt.SWT;
@@ -23,6 +30,7 @@
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
+import org.eclipse.swt.widgets.Widget;
import org.junit.Test;
public class TreeViewerTest extends AbstractTreeViewerTest {
@@ -77,4 +85,33 @@ public void testAutoExpandOnSingleChildThroughEvent() {
fTreeViewer.getExpandedState(trivialPathRoot.getFirstChild().getFirstChild()));
}
+ @Test
+ public void testInternalExpandToLevelRecursive() {
+ // internalExpandToLevel is recursive by contract, so we track all processed
+ // elements in a subtype to validate contractual recursive execution
+ List