From: Kirill Kalishev Date: Tue, 27 Jul 2010 09:21:30 +0000 (+0400) Subject: Merge branch 'master' of git@git.labs.intellij.net:idea/community X-Git-Tag: rubymine/96.788~4 X-Git-Url: https://git.jetbrains.org/?p=idea%2Fcommunity.git;a=commitdiff_plain;h=e98c87b8e93545a6c3dfbc1a587333c50ff44220;hp=dee36a2c64f40e8bbea972010511d4fa36f56767 Merge branch 'master' of git@git.labs.intellij.net:idea/community --- diff --git a/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeBuilder.java b/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeBuilder.java index b0ab02fd1bfb..8bc11f45c984 100644 --- a/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeBuilder.java +++ b/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeBuilder.java @@ -82,31 +82,31 @@ public class AbstractTreeBuilder implements Disposable { } public final void select(final Object element, @Nullable final Runnable onDone) { - getUi().userSelect(new Object[] {element}, onDone, false, true); + getUi().userSelect(new Object[] {element}, new UserRunnable(onDone), false, true); } public final void select(final Object element, @Nullable final Runnable onDone, boolean addToSelection) { - getUi().userSelect(new Object[] {element}, onDone, addToSelection, true); + getUi().userSelect(new Object[] {element}, new UserRunnable(onDone), addToSelection, true); } public final void select(final Object[] elements, @Nullable final Runnable onDone) { - getUi().userSelect(elements, onDone, false, true); + getUi().userSelect(elements, new UserRunnable(onDone), false, true); } public final void select(final Object[] elements, @Nullable final Runnable onDone, boolean addToSelection) { - getUi().userSelect(elements, onDone, addToSelection, true); + getUi().userSelect(elements, new UserRunnable(onDone), addToSelection, true); } public final void expand(Object element, @Nullable Runnable onDone) { - getUi().expand(element, onDone); + getUi().expand(element, new UserRunnable(onDone)); } public final void expand(Object[] element, @Nullable Runnable onDone) { - getUi().expand(element, onDone); + getUi().expand(element, new UserRunnable(onDone)); } public final void collapseChildren(Object element, @Nullable Runnable onDone) { - getUi().collapseChildren(element, onDone); + getUi().collapseChildren(element, new UserRunnable(onDone)); } @@ -501,4 +501,25 @@ public class AbstractTreeBuilder implements Disposable { return builder != null && builder.getUi() != null ? builder.getUi().isToPaintSelection() : true; } + class UserRunnable implements Runnable { + + private Runnable myRunnable; + + public UserRunnable(Runnable runnable) { + myRunnable = runnable; + } + + @Override + public void run() { + if (myRunnable != null) { + AbstractTreeUi ui = getUi(); + if (ui != null) { + ui.executeUserRunnable(myRunnable); + } else { + myRunnable.run(); + } + } + } + } + } diff --git a/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java b/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java index c8893ea0b46c..49b8366e9683 100644 --- a/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java +++ b/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java @@ -178,6 +178,8 @@ public class AbstractTreeUi { private Set myRevalidatedObjects = new HashSet(); + private Set myUserRunnables = new HashSet(); + private Alarm myMaybeReady = new Alarm(); private Runnable myMaybeReadyRunnable = new Runnable() { @Override @@ -1054,6 +1056,7 @@ public class AbstractTreeUi { final NodeDescriptor descriptor = getDescriptorFrom(node); if (descriptor == null) { + removeFromUnbuilt(node); removeLoading(node, true); return; } @@ -1145,6 +1148,7 @@ public class AbstractTreeUi { if (desc == null) return false; if (getTreeStructure().isAlwaysLeaf(element)) { + removeFromUnbuilt(node); removeLoading(node, true); if (node.getChildCount() > 0) { @@ -1212,6 +1216,8 @@ public class AbstractTreeUi { final boolean canSmartExpand = canSmartExpand(node, toSmartExpand); + removeFromUnbuilt(node); + processExistingNodes(node, elementToIndexMap, pass, canSmartExpand(node, toSmartExpand), forceUpdate, wasExpanded, preloadedChildren) .doWhenDone(new Runnable() { public void run() { @@ -1236,7 +1242,7 @@ public class AbstractTreeUi { public void run(ArrayList nodesToInsert) { insertNodesInto(nodesToInsert, node); updateNodesToInsert(nodesToInsert, pass, canSmartExpand, isChildNodeForceUpdate(node, forceUpdate, expanded)); - removeLoading(node, true); + removeLoading(node, false); removeFromUpdating(node); if (node.getChildCount() > 0) { @@ -1371,6 +1377,7 @@ public class AbstractTreeUi { boolean processed; if (children.getElements().size() == 0) { + removeFromUnbuilt(node); removeLoading(node, true); processed = true; } @@ -1746,6 +1753,7 @@ public class AbstractTreeUi { } } else { + removeFromUnbuilt(node); removeLoading(node, true); } } @@ -2313,6 +2321,16 @@ public class AbstractTreeUi { return myReleaseRequested; } + public void executeUserRunnable(Runnable runnable) { + try { + myUserRunnables.add(runnable); + runnable.run(); + } + finally { + myUserRunnables.remove(runnable); + } + } + static class ElementNode extends DefaultMutableTreeNode { Set myElements = new HashSet(); @@ -2412,6 +2430,8 @@ public class AbstractTreeUi { myTreeModel.insertNodeInto(loadingNode, node, node.getChildCount()); } + removeFromUnbuilt(node); + final Ref children = new Ref(); final Ref elementFromDescriptor = new Ref(); @@ -2423,7 +2443,7 @@ public class AbstractTreeUi { public void run() { if (isReleased()) return; - removeLoading(node, true); + removeLoading(node, false); removeFromLoadedInBackground(elementFromDescriptor.get()); removeFromLoadedInBackground(oldElementFromDescriptor); @@ -2520,7 +2540,7 @@ public class AbstractTreeUi { Object element = elementFromDescriptor.get(); if (element != null) { - removeLoading(node, true); + removeLoading(node, false); nodeToProcessActions[0] = node; } } @@ -2538,7 +2558,11 @@ public class AbstractTreeUi { return isExpanded || myTree.isExpanded(getPathFor(node)); } - private void removeLoading(DefaultMutableTreeNode parent, boolean removeFromUnbuilt) { + private void removeLoading(DefaultMutableTreeNode parent, boolean forced) { + if (!forced && myUnbuiltNodes.contains(parent) && !myCancelledBuild.containsKey(parent)) { + return; + } + for (int i = 0; i < parent.getChildCount(); i++) { TreeNode child = parent.getChildAt(i); if (removeIfLoading(child)) { @@ -2546,10 +2570,6 @@ public class AbstractTreeUi { } } - if (removeFromUnbuilt) { - removeFromUnbuilt(parent); - } - if (parent == getRootNode() && !myTree.isRootVisible() && parent.getChildCount() == 0) { insertLoadingNode(parent, false); } @@ -3021,7 +3041,7 @@ public class AbstractTreeUi { } private boolean isInnerChange() { - return myUpdaterState != null && myUpdaterState.isProcessingNow(); + return (myUpdaterState != null && myUpdaterState.isProcessingNow()) && myUserRunnables.size() == 0; } protected boolean doUpdateNodeDescriptor(final NodeDescriptor descriptor) { @@ -3407,6 +3427,7 @@ public class AbstractTreeUi { public boolean addSubtreeToUpdate(final DefaultMutableTreeNode root, final Runnable runAfterUpdate) { Object element = getElementFor(root); if (getTreeStructure().isAlwaysLeaf(element)) { + removeFromUnbuilt(root); removeLoading(root, true); if (runAfterUpdate != null) { @@ -4108,7 +4129,9 @@ public class AbstractTreeUi { if (isLoadingParent(node)) return (DefaultMutableTreeNode)node; - final boolean childrenAreNoLoadedYet = myUnbuiltNodes.contains(node); + DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode)node; + + final boolean childrenAreNoLoadedYet = myUnbuiltNodes.contains(treeNode) || isUpdatingNow(treeNode); if (childrenAreNoLoadedYet) { if (node instanceof DefaultMutableTreeNode) { final TreePath nodePath = new TreePath(((DefaultMutableTreeNode)node).getPath()); diff --git a/platform/platform-impl/testSrc/com/intellij/ide/util/treeView/TreeUiTest.java b/platform/platform-impl/testSrc/com/intellij/ide/util/treeView/TreeUiTest.java index 86e504e99279..84c338e6cc5f 100644 --- a/platform/platform-impl/testSrc/com/intellij/ide/util/treeView/TreeUiTest.java +++ b/platform/platform-impl/testSrc/com/intellij/ide/util/treeView/TreeUiTest.java @@ -803,6 +803,45 @@ public class TreeUiTest extends AbstractTreeBuilderTest { " +xunit\n"); } + public void testCollapsedPathOnExpandedCallback() throws Exception { + Node com = myRoot.addChild("com"); + + activate(); + assertTree("+/\n"); + + expand(getPath("/")); + assertTree("-/\n" + + " com\n"); + + com.addChild("intellij"); + + collapsePath(getPath("/")); + + final Ref done = new Ref(); + invokeLaterIfNeeded(new Runnable() { + @Override + public void run() { + getBuilder().expand(new NodeElement("com"), new Runnable() { + @Override + public void run() { + getBuilder().getTree().collapsePath(getPath("com")); + done.set(Boolean.TRUE); + } + }); + } + }); + + waitBuilderToCome(new Condition() { + @Override + public boolean value(Object o) { + return (done.get() != null) && done.get().booleanValue(); + } + }); + + assertTree("-/\n" + + " +com\n"); + } + public void testSelectionGoesToParentWhenOnlyChildMoved() throws Exception { buildStructure(myRoot); buildNode("openapi", true);