Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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.
* <p>
* Note that the default implementation of this method does not call
* {@code setRedraw}.
* </p>
*
* @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<Widget, Boolean> 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)) {
Expand All @@ -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.
Expand All @@ -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);
}
}
});
}

/**
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
}
}

Expand Down Expand Up @@ -3535,8 +3546,4 @@ ISelection getUpdatedSelection(ISelection selection) {
return selection;
}

private boolean doesWidgetHaveExactlyOneChild(Widget w) {
return getChildren(w).length == 1;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,21 @@
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;
import org.eclipse.swt.widgets.Composite;
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 {
Expand Down Expand Up @@ -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<Object> recursiveExpandedElements = new ArrayList<>();
TreeViewer viewer = new TreeViewer(fShell) {
@Override
protected void internalExpandToLevel(Widget widget, int level) {
if (widget != this.getTree()) {
recursiveExpandedElements.add(widget.getData());
}
super.internalExpandToLevel(widget, level);
}
};
TestElement rootElement = TestElement.createModel(2, 5);
viewer.setContentProvider(new TestModelContentProvider());
viewer.setInput(rootElement);

viewer.expandToLevel(AbstractTreeViewer.ALL_LEVELS);

Queue<TestElement> elements = new ConcurrentLinkedQueue<>(Arrays.asList(rootElement.getChildren()));
while (!elements.isEmpty()) {
TestElement currentElement = elements.poll();
assertTrue("expansion for child was not processed: " + currentElement,
recursiveExpandedElements.contains(currentElement));
elements.addAll(Arrays.asList(currentElement.getChildren()));
}
}

}
Loading