private boolean myPassthroughMode = false;
+ private Set<Object> myAutoExpandRoots = new HashSet<Object>();
+ private final RegistryValue myAutoExpandDepth = Registry.get("ide.tree.autoExpandMaxDepth");
+
protected void init(AbstractTreeBuilder builder,
JTree tree,
DefaultTreeModel treeModel,
autoExpand = getBuilder().isAutoExpandNode(descriptor);
}
+ Object element = getElementFromDescriptor(descriptor);
+ autoExpand = validateAutoExpand(autoExpand, element);
+
if (!autoExpand && !myTree.isRootVisible()) {
- Object element = getElementFromDescriptor(descriptor);
if (element != null && element.equals(getTreeStructure().getRootElement())) return true;
}
return autoExpand;
}
+ private boolean validateAutoExpand(boolean autoExpand, Object element) {
+ if (autoExpand) {
+ int distance = getDistanceToAutoExpandRoot(element);
+ if (distance < 0) {
+ myAutoExpandRoots.add(element);
+ } else {
+ if (distance >= myAutoExpandDepth.asInteger() - 1) {
+ autoExpand = false;
+ }
+ }
+ }
+ return autoExpand;
+ }
+
+ private int getDistanceToAutoExpandRoot(Object element) {
+ int distance = 0;
+
+ Object eachParent = element;
+ while (eachParent != null) {
+ if (myAutoExpandRoots.contains(eachParent)) break;
+ eachParent = getTreeStructure().getParentElement(eachParent);
+ distance++;
+ }
+
+ return eachParent != null ? distance : -1;
+ }
+
private boolean isAutoExpand(DefaultMutableTreeNode node) {
return isAutoExpand(getDescriptorFrom(node));
}
addSelectionPath(getPathFor(node), true, Condition.TRUE, null);
}
- doWithUpdaterState(new Runnable() {
+ processInnerChange(new Runnable() {
public void run() {
for (TreeNode each : children) {
removeNodeFromParent((MutableTreeNode)each, true);
private boolean canSmartExpand(DefaultMutableTreeNode node, boolean canSmartExpand) {
- return !myNotForSmartExpand.contains(node) && canSmartExpand;
+ if (!getBuilder().isSmartExpand()) return false;
+
+ boolean smartExpand = !myNotForSmartExpand.contains(node) && canSmartExpand;
+ return smartExpand ? validateAutoExpand(smartExpand, getElementFor(node)) : false;
}
- private void processSmartExpand(final DefaultMutableTreeNode node, final boolean canSmartExpand) {
- if (!getBuilder().isSmartExpand() || !canSmartExpand(node, canSmartExpand)) return;
+ private void processSmartExpand(final DefaultMutableTreeNode node, final boolean canSmartExpand, boolean forced) {
+ if (!getBuilder().isSmartExpand()) return;
+
+ boolean can = canSmartExpand(node, canSmartExpand);
+
+ if (!can && !forced) return;
- if (isNodeBeingBuilt(node)) {
+ if (isNodeBeingBuilt(node) && !forced) {
addNodeAction(getElementFor(node), new NodeAction() {
public void onReady(DefaultMutableTreeNode node) {
- processSmartExpand(node, canSmartExpand);
+ processSmartExpand(node, canSmartExpand, true);
}
}, true);
}
TreeNode child = getChildForSmartExpand(node);
if (child != null) {
final TreePath childPath = new TreePath(node.getPath()).pathByAddingChild(child);
- myTree.expandPath(childPath);
+ processInnerChange(new Runnable() {
+ public void run() {
+ myTree.expandPath(childPath);
+ }
+ });
}
}
}
}
private void addSelectionPath(final TreePath path, final boolean isAdjustedSelection, final Condition isExpiredAdjustement, @Nullable final Object adjustmentCause) {
- doWithUpdaterState(new Runnable() {
+ processInnerChange(new Runnable() {
public void run() {
TreePath toSelect = null;
private void removeNodeFromParent(final MutableTreeNode node, final boolean willAdjustSelection) {
- doWithUpdaterState(new Runnable() {
+ processInnerChange(new Runnable() {
public void run() {
if (willAdjustSelection) {
final TreePath path = getPathFor(node);
}
private void expandPath(final TreePath path, final boolean canSmartExpand) {
- doWithUpdaterState(new Runnable() {
+ processInnerChange(new Runnable() {
public void run() {
if (path.getLastPathComponent() instanceof DefaultMutableTreeNode) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode)path.getLastPathComponent();
try {
myRequestedExpand = path;
myTree.expandPath(path);
- processSmartExpand(node, canSmartExpand);
+ processSmartExpand(node, canSmartExpand, false);
}
finally {
myNotForSmartExpand.remove(node);
});
}
- private void doWithUpdaterState(Runnable runnable) {
- if (myUpdaterState != null) {
- myUpdaterState.process(runnable);
- }
- else {
- runnable.run();
+ private void processInnerChange(Runnable runnable) {
+ if (myUpdaterState == null) {
+ setUpdaterState(new UpdaterTreeState(this));
}
+
+ myUpdaterState.process(runnable);
+ }
+
+ private boolean isInnerChange() {
+ return myUpdaterState != null && myUpdaterState.isProcessingNow();
}
protected boolean doUpdateNodeDescriptor(final NodeDescriptor descriptor) {
sortChildren(parentNode, all, true, false);
if (!before.equals(all)) {
- doWithUpdaterState(new Runnable() {
+ processInnerChange(new Runnable() {
public void run() {
parentNode.removeAllChildren();
for (TreeNode each : all) {
if (descriptor == null) return;
final Object element = getElementFromDescriptor(descriptor);
removeMapping(element, node, null);
+ myAutoExpandRoots.remove(element);
node.setUserObject(null);
node.removeAllChildren();
}
}
private void dropUpdaterStateIfExternalChange() {
- if (myUpdaterState != null && !myUpdaterState.isProcessingNow()) {
- clearUpdaterState();
+ if (!isInnerChange()) {
+ clearUpdaterState();
+ myAutoExpandRoots.clear();
}
}
getBuilder().expandNodeChildren(node);
}
- processSmartExpand(node, canSmartExpand(node, true));
+ processSmartExpand(node, canSmartExpand(node, true), false);
processNodeActionsIfReady(node);
}