more responsive find usages: group usages outside EDT

This commit is contained in:
peter
2012-05-31 17:44:31 +02:00
parent 8252e9dc72
commit f2765fe5ef
6 changed files with 46 additions and 26 deletions
@@ -22,6 +22,7 @@ import com.intellij.testFramework.LightPlatformTestCase;
import com.intellij.usages.*;
import com.intellij.usages.rules.UsageFilteringRule;
import com.intellij.usages.rules.UsageGroupingRule;
import com.intellij.util.Consumer;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
@@ -90,7 +91,12 @@ public class UsageNodeTreeBuilderTest extends LightPlatformTestCase {
model.setRoot(rootNode);
UsageNodeTreeBuilder usageNodeTreeBuilder = new UsageNodeTreeBuilder(UsageTarget.EMPTY_ARRAY, rules, UsageFilteringRule.EMPTY_ARRAY, rootNode);
for (Usage usage : usages) {
usageNodeTreeBuilder.appendUsage(usage);
usageNodeTreeBuilder.appendUsage(usage, new Consumer<Runnable>() {
@Override
public void consume(Runnable runnable) {
runnable.run();
}
});
UIUtil.dispatchAllInvocationEvents();
}
@@ -23,7 +23,7 @@ import com.intellij.usages.UsageGroup;
import com.intellij.usages.UsageView;
import com.intellij.usages.UsageViewSettings;
import com.intellij.usages.rules.MergeableUsage;
import com.intellij.util.ui.UIUtil;
import com.intellij.util.Consumer;
import gnu.trove.THashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -62,22 +62,22 @@ public class GroupNode extends Node implements Navigatable, Comparable<GroupNode
return children == null ? result : result + children.toString();
}
public GroupNode addGroup(@NotNull UsageGroup group, int ruleIndex) {
public GroupNode addGroup(@NotNull UsageGroup group, int ruleIndex, Consumer<Runnable> edtQueue) {
synchronized (lock) {
GroupNode node = mySubgroupNodes.get(group);
if (node == null) {
final GroupNode node1 = node = new GroupNode(group, ruleIndex, getBuilder());
mySubgroupNodes.put(group, node);
addNode(node1);
addNode(node1, edtQueue);
}
return node;
}
}
void addNode(@NotNull final DefaultMutableTreeNode node) {
void addNode(@NotNull final DefaultMutableTreeNode node, @NotNull Consumer<Runnable> edtQueue) {
if (!getBuilder().isDetachedMode()) {
UIUtil.invokeLaterIfNeeded(new Runnable() {
edtQueue.consume(new Runnable() {
@Override
public void run() {
myTreeModel.insertNodeInto(node, GroupNode.this, getNodeInsertionIndex(node));
@@ -102,7 +102,7 @@ public class GroupNode extends Node implements Navigatable, Comparable<GroupNode
myTreeModel.reload(this);
}
private UsageNode tryMerge(@NotNull Usage usage) {
@Nullable UsageNode tryMerge(@NotNull Usage usage) {
if (!(usage instanceof MergeableUsage)) return null;
MergeableUsage mergeableUsage = (MergeableUsage)usage;
for (UsageNode node : myUsageNodes) {
@@ -154,7 +154,7 @@ public class GroupNode extends Node implements Navigatable, Comparable<GroupNode
myTreeModel.nodeChanged(this);
}
public UsageNode addUsage(@NotNull Usage usage) {
public UsageNode addUsage(@NotNull Usage usage, Consumer<Runnable> edtQueue) {
final UsageNode node;
synchronized (lock) {
if (UsageViewSettings.getInstance().isFilterDuplicatedLine()) {
@@ -168,7 +168,7 @@ public class GroupNode extends Node implements Navigatable, Comparable<GroupNode
}
if (!getBuilder().isDetachedMode()) {
UIUtil.invokeLaterIfNeeded(new Runnable() {
edtQueue.consume(new Runnable() {
@Override
public void run() {
myTreeModel.insertNodeInto(node, GroupNode.this, getNodeIndex(node));
@@ -22,6 +22,7 @@ import com.intellij.usages.rules.UsageFilteringRule;
import com.intellij.usages.rules.UsageFilteringRuleEx;
import com.intellij.usages.rules.UsageGroupingRule;
import com.intellij.usages.rules.UsageGroupingRuleEx;
import com.intellij.util.Consumer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -69,7 +70,7 @@ class UsageNodeTreeBuilder {
}
@Nullable
UsageNode appendUsage(@NotNull Usage usage) {
UsageNode appendUsage(@NotNull Usage usage, Consumer<Runnable> edtQueue) {
if (!isVisible(usage)) return null;
GroupNode lastGroupNode = myRoot;
@@ -83,10 +84,10 @@ class UsageNodeTreeBuilder {
group = rule.groupUsage(usage);
}
if (group != null) {
lastGroupNode = lastGroupNode.addGroup(group, i);
lastGroupNode = lastGroupNode.addGroup(group, i, edtQueue);
}
}
return lastGroupNode.addUsage(usage);
return lastGroupNode.addUsage(usage, edtQueue);
}
}
@@ -34,7 +34,7 @@ import com.intellij.openapi.ui.SimpleToolWindowPanel;
import com.intellij.openapi.ui.Splitter;
import com.intellij.openapi.util.*;
import com.intellij.openapi.vfs.ReadonlyStatusHandler;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.pom.Navigatable;
import com.intellij.psi.PsiDocumentManager;
@@ -47,6 +47,7 @@ import com.intellij.usageView.UsageViewManager;
import com.intellij.usages.*;
import com.intellij.usages.rules.*;
import com.intellij.util.Alarm;
import com.intellij.util.Consumer;
import com.intellij.util.EditSourceOnDoubleClickHandler;
import com.intellij.util.Processor;
import com.intellij.util.containers.ContainerUtil;
@@ -237,10 +238,10 @@ public class UsageViewImpl implements UsageView, UsageModelTracker.UsageModelTra
}
});
}
myTransferToEDTQueue = new TransferToEDTQueue<Usage>("Insert usages", new Processor<Usage>() {
myTransferToEDTQueue = new TransferToEDTQueue<Runnable>("Insert usages", new Processor<Runnable>() {
@Override
public boolean process(Usage usage) {
appendUsage(usage);
public boolean process(Runnable runnable) {
runnable.run();
return true;
}
}, new Condition<Object>() {
@@ -672,7 +673,7 @@ public class UsageViewImpl implements UsageView, UsageModelTracker.UsageModelTra
if (usageCount > UsageLimitUtil.USAGES_LIMIT && tooManyUsages.get() == 0 && tooManyUsages.compareAndSet(0, 1)) {
((UsageViewManagerImpl)usageViewManager).showTooManyUsagesWarning(indicator, waitWhileUserClick, usageCountWithoutDefinition.get());
}
appendUsageLater(usage);
appendUsage(usage);
}
ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
return indicator == null || !indicator.isCanceled();
@@ -699,10 +700,7 @@ public class UsageViewImpl implements UsageView, UsageModelTracker.UsageModelTra
}
}
private final TransferToEDTQueue<Usage> myTransferToEDTQueue;
public void appendUsageLater(@NotNull Usage usage) {
myTransferToEDTQueue.offer(usage);
}
private final TransferToEDTQueue<Runnable> myTransferToEDTQueue;
public void drainQueuedUsageNodes() {
assert !ApplicationManager.getApplication().isDispatchThread() : Thread.currentThread();
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
@@ -718,6 +716,7 @@ public class UsageViewImpl implements UsageView, UsageModelTracker.UsageModelTra
doAppendUsage(usage);
}
@Nullable
public UsageNode doAppendUsage(@NotNull Usage usage) {
// invoke in ReadAction to be be sure that usages are not invalidated while the tree is being built
ApplicationManager.getApplication().assertReadAccessAllowed();
@@ -725,7 +724,12 @@ public class UsageViewImpl implements UsageView, UsageModelTracker.UsageModelTra
// because the view is built incrementally, the usage may be already invalid, so need to filter such cases
return null;
}
UsageNode node = myBuilder.appendUsage(usage);
UsageNode node = myBuilder.appendUsage(usage, new Consumer<Runnable>() {
@Override
public void consume(Runnable runnable) {
myTransferToEDTQueue.offer(runnable);
}
});
myUsageNodes.put(usage, node == null ? NULL_NODE : node);
return node;
}
@@ -934,7 +938,7 @@ public class UsageViewImpl implements UsageView, UsageModelTracker.UsageModelTra
final Set<VirtualFile> readOnlyUsages = getReadOnlyUsagesFiles();
return readOnlyUsages.isEmpty() ||
!ReadonlyStatusHandler.getInstance(myProject).ensureFilesWritable(VfsUtil.toVirtualFileArray(readOnlyUsages)).hasReadonlyFiles();
!ReadonlyStatusHandler.getInstance(myProject).ensureFilesWritable(VfsUtilCore.toVirtualFileArray(readOnlyUsages)).hasReadonlyFiles();
}
@NotNull
@@ -282,7 +282,7 @@ public class UsageViewManagerImpl extends UsageViewManager {
openView(usageView);
Usage firstUsage = myFirstUsage.get();
if (firstUsage != null) {
usageView.appendUsageLater(firstUsage);
usageView.appendUsage(firstUsage);
}
}
else {
@@ -308,8 +308,10 @@ public class UsageViewManagerImpl extends UsageViewManager {
@Override
public void run() {
//long start = System.currentTimeMillis();
searchUsages();
endSearchForUsages();
//System.out.println("Usage search took " + (System.currentTimeMillis() - start));
}
private void searchUsages() {
@@ -342,7 +344,7 @@ public class UsageViewManagerImpl extends UsageViewManager {
}
UsageViewImpl usageView = getUsageView();
if (usageView != null) {
usageView.appendUsageLater(usage);
usageView.appendUsage(usage);
}
}
return indicator == null || !indicator.isCanceled();
@@ -17,6 +17,8 @@ package com.intellij.usages.impl;
import com.intellij.usages.UsageTarget;
import com.intellij.usages.UsageViewPresentation;
import com.intellij.util.Consumer;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NonNls;
import javax.swing.tree.DefaultMutableTreeNode;
@@ -66,7 +68,12 @@ public class UsageViewTreeModelBuilder extends DefaultTreeModel {
myTargetsNode.add(targetNode);
myTargetNodes[i] = targetNode;
}
myRootNode.addNode(myTargetsNode);
myRootNode.addNode(myTargetsNode, new Consumer<Runnable>() {
@Override
public void consume(Runnable runnable) {
UIUtil.invokeLaterIfNeeded(runnable);
}
});
}
public UsageNode getFirstUsageNode() {