mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
execute node.update() in background because it could call smartPointer.isValid() which is ridiculously expensive in CLion
This commit is contained in:
+12
-2
@@ -21,6 +21,9 @@ import com.intellij.openapi.extensions.ExtensionPoint;
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.openapi.extensions.ExtensionsArea;
|
||||
import com.intellij.openapi.fileEditor.FileEditorLocation;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.progress.Task;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
@@ -112,13 +115,13 @@ public class UsageNodeTreeBuilderTest extends LightPlatformTestCase {
|
||||
UsageGroupingRuleProvider provider = new UsageGroupingRuleProvider() {
|
||||
@NotNull
|
||||
@Override
|
||||
public UsageGroupingRule[] getActiveRules(Project project) {
|
||||
public UsageGroupingRule[] getActiveRules(@NotNull Project project) {
|
||||
return rules;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public AnAction[] createGroupingActions(UsageView view) {
|
||||
public AnAction[] createGroupingActions(@NotNull UsageView view) {
|
||||
return AnAction.EMPTY_ARRAY;
|
||||
}
|
||||
};
|
||||
@@ -130,6 +133,13 @@ public class UsageNodeTreeBuilderTest extends LightPlatformTestCase {
|
||||
usageView.appendUsage(usage);
|
||||
}
|
||||
UIUtil.dispatchAllInvocationEvents();
|
||||
ProgressManager.getInstance().run(new Task.Modal(getProject(), "waiting", false) {
|
||||
@Override
|
||||
public void run(@NotNull ProgressIndicator indicator) {
|
||||
usageView.waitForUpdateRequestsCompletion();
|
||||
}
|
||||
});
|
||||
UIUtil.dispatchAllInvocationEvents();
|
||||
|
||||
return usageView.getRoot();
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ package com.intellij.usages.impl;
|
||||
import com.intellij.find.FindManager;
|
||||
import com.intellij.find.findUsages.FindUsagesHandler;
|
||||
import com.intellij.find.findUsages.FindUsagesManager;
|
||||
import com.intellij.find.findUsages.PsiElement2UsageTargetAdapter;
|
||||
import com.intellij.find.impl.FindManagerImpl;
|
||||
import com.intellij.ide.actions.exclusion.ExclusionHandler;
|
||||
import com.intellij.ide.impl.TypeSafeDataProviderAdapter;
|
||||
@@ -16,6 +15,9 @@ import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.command.WriteCommandAction;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.progress.Task;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.encoding.EncodingManager;
|
||||
@@ -31,6 +33,7 @@ import com.intellij.usageView.UsageInfo;
|
||||
import com.intellij.usages.*;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import com.intellij.util.ui.tree.TreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.tree.TreeNode;
|
||||
@@ -57,9 +60,7 @@ public class UsageViewTest extends LightPlatformCodeInsightFixtureTestCase {
|
||||
usages[i] = createUsage(psiFile,i);
|
||||
}
|
||||
|
||||
UsageView usageView = UsageViewManager.getInstance(getProject()).createUsageView(UsageTarget.EMPTY_ARRAY, usages, new UsageViewPresentation(), null);
|
||||
|
||||
Disposer.register(myFixture.getTestRootDisposable(), usageView);
|
||||
UsageView usageView = createUsageView(usages);
|
||||
|
||||
((EncodingManagerImpl)EncodingManager.getInstance()).clearDocumentQueue();
|
||||
FileDocumentManager.getInstance().saveAllDocuments();
|
||||
@@ -73,8 +74,7 @@ public class UsageViewTest extends LightPlatformCodeInsightFixtureTestCase {
|
||||
PsiFile psiFile = myFixture.addFileToProject("X.java", "public class X{ int xxx; } //comment");
|
||||
Usage usage = createUsage(psiFile, psiFile.getText().indexOf("xxx"));
|
||||
|
||||
UsageView usageView = UsageViewManager.getInstance(getProject()).createUsageView(UsageTarget.EMPTY_ARRAY, new Usage[]{usage}, new UsageViewPresentation(), null);
|
||||
Disposer.register(myFixture.getTestRootDisposable(), usageView);
|
||||
UsageView usageView = createUsageView(new Usage[]{usage});
|
||||
|
||||
PsiDocumentManager documentManager = PsiDocumentManager.getInstance(getProject());
|
||||
Document document = documentManager.getDocument(psiFile);
|
||||
@@ -87,8 +87,7 @@ public class UsageViewTest extends LightPlatformCodeInsightFixtureTestCase {
|
||||
PsiFile psiFile = myFixture.addFileToProject("X.java", "public class X{ int xxx; } //comment");
|
||||
Usage usage = new UsageInfo2UsageAdapter(new UsageInfo(psiFile, psiFile.getText().indexOf("xxx"), StringUtil.indexOfSubstringEnd(psiFile.getText(),"xxx")));
|
||||
|
||||
UsageView usageView = UsageViewManager.getInstance(getProject()).createUsageView(UsageTarget.EMPTY_ARRAY, new Usage[]{usage}, new UsageViewPresentation(), null);
|
||||
Disposer.register(myFixture.getTestRootDisposable(), usageView);
|
||||
UsageView usageView = createUsageView(new Usage[]{usage});
|
||||
|
||||
PsiDocumentManager documentManager = PsiDocumentManager.getInstance(getProject());
|
||||
Document document = documentManager.getDocument(psiFile);
|
||||
@@ -118,11 +117,17 @@ public class UsageViewTest extends LightPlatformCodeInsightFixtureTestCase {
|
||||
PsiNamedElement bar = (PsiNamedElement)members[members.length - 3];
|
||||
assertEquals("bar", bar.getName());
|
||||
|
||||
UsageTarget target = new PsiElement2UsageTargetAdapter(bar);
|
||||
FindUsagesManager usagesManager = ((FindManagerImpl)FindManager.getInstance(getProject())).getFindUsagesManager();
|
||||
FindUsagesHandler handler = usagesManager.getNewFindUsagesHandler(bar, false);
|
||||
UsageViewImpl usageView =
|
||||
(UsageViewImpl)usagesManager.doFindUsages(new PsiElement[]{bar}, PsiElement.EMPTY_ARRAY, handler, handler.getFindUsagesOptions(), false);
|
||||
ProgressManager.getInstance().run(new Task.Modal(getProject(), "waiting", false) {
|
||||
@Override
|
||||
public void run(@NotNull ProgressIndicator indicator) {
|
||||
usageView.waitForUpdateRequestsCompletion();
|
||||
usageView.drainQueuedUsageNodes();
|
||||
}
|
||||
});
|
||||
|
||||
Disposer.register(myFixture.getTestRootDisposable(), usageView);
|
||||
|
||||
@@ -156,9 +161,7 @@ public class UsageViewTest extends LightPlatformCodeInsightFixtureTestCase {
|
||||
PsiFile psiFile = myFixture.addFileToProject("X.java", "public class X{ int xxx; } //comment");
|
||||
Usage usage = new UsageInfo2UsageAdapter(new UsageInfo(psiFile, psiFile.getText().indexOf("xxx"), StringUtil.indexOfSubstringEnd(psiFile.getText(),"xxx")));
|
||||
|
||||
UsageViewImpl usageView =
|
||||
(UsageViewImpl)UsageViewManager.getInstance(getProject()).createUsageView(UsageTarget.EMPTY_ARRAY, new Usage[]{usage}, new UsageViewPresentation(), null);
|
||||
Disposer.register(myFixture.getTestRootDisposable(), usageView);
|
||||
UsageViewImpl usageView = createUsageView(new Usage[]{usage});
|
||||
|
||||
usageView.excludeUsages(new Usage[]{usage});
|
||||
UIUtil.dispatchAllInvocationEvents();
|
||||
@@ -204,14 +207,27 @@ public class UsageViewTest extends LightPlatformCodeInsightFixtureTestCase {
|
||||
" 1 public class X{ int xxx; } //comment\n", StringUtil.convertLineSeparators(text));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private UsageViewImpl createUsageView(@NotNull Usage[] usages) {
|
||||
UsageViewImpl usageView =
|
||||
(UsageViewImpl)UsageViewManager.getInstance(getProject()).createUsageView(UsageTarget.EMPTY_ARRAY, usages, new UsageViewPresentation(), null);
|
||||
Disposer.register(myFixture.getTestRootDisposable(), usageView);
|
||||
ProgressManager.getInstance().run(new Task.Modal(getProject(), "Waiting For Usages", false) {
|
||||
@Override
|
||||
public void run(@NotNull ProgressIndicator indicator) {
|
||||
usageView.drainQueuedUsageNodes();
|
||||
}
|
||||
});
|
||||
UIUtil.dispatchAllInvocationEvents();
|
||||
|
||||
return usageView;
|
||||
}
|
||||
|
||||
public void testExcludeNodeMustExcludeChildrenAndParents() {
|
||||
PsiFile psiFile = myFixture.addFileToProject("X.java", "public class X{ int xxx; } //comment");
|
||||
Usage usage = new UsageInfo2UsageAdapter(new UsageInfo(psiFile, psiFile.getText().indexOf("xxx"), StringUtil.indexOfSubstringEnd(psiFile.getText(),"xxx")));
|
||||
|
||||
UsageViewImpl usageView =
|
||||
(UsageViewImpl)UsageViewManager.getInstance(getProject()).createUsageView(UsageTarget.EMPTY_ARRAY, new Usage[]{usage}, new UsageViewPresentation(), null);
|
||||
Disposer.register(myFixture.getTestRootDisposable(), usageView);
|
||||
UIUtil.dispatchAllInvocationEvents();
|
||||
UsageViewImpl usageView = createUsageView(new Usage[]{usage});
|
||||
|
||||
Node[] usageNode = new Node[1];
|
||||
TreeUtil.traverse(usageView.getRoot(), node -> {
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.usages.impl;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.usages.UsageView;
|
||||
import com.intellij.util.BitUtil;
|
||||
import com.intellij.util.Consumer;
|
||||
@@ -30,7 +31,7 @@ import java.util.Vector;
|
||||
public abstract class Node extends DefaultMutableTreeNode {
|
||||
private int myCachedTextHash;
|
||||
|
||||
private byte myCachedFlags; // bit packed flags below:
|
||||
private byte myCachedFlags; // guarded by this; bit packed flags below:
|
||||
static final byte EXCLUDED_MASK = 1<<3;
|
||||
private static final byte UPDATED_MASK = 1<<4;
|
||||
|
||||
@@ -41,11 +42,11 @@ public abstract class Node extends DefaultMutableTreeNode {
|
||||
@MagicConstant(intValues = {CACHED_INVALID_MASK, CACHED_READ_ONLY_MASK, READ_ONLY_COMPUTED_MASK, EXCLUDED_MASK, UPDATED_MASK})
|
||||
private @interface FlagConstant {}
|
||||
|
||||
private boolean isFlagSet(@FlagConstant byte mask) {
|
||||
private synchronized boolean isFlagSet(@FlagConstant byte mask) {
|
||||
return BitUtil.isSet(myCachedFlags, mask);
|
||||
}
|
||||
|
||||
private void setFlag(@FlagConstant byte mask, boolean value) {
|
||||
private synchronized void setFlag(@FlagConstant byte mask, boolean value) {
|
||||
myCachedFlags = BitUtil.set(myCachedFlags, mask, value);
|
||||
}
|
||||
|
||||
@@ -92,6 +93,8 @@ public abstract class Node extends DefaultMutableTreeNode {
|
||||
}
|
||||
|
||||
final synchronized void update(@NotNull UsageView view, @NotNull Consumer<Node> edtNodeChangedQueue) {
|
||||
// performance: always update in background because smart pointer' isValid() can cause PSI chameleons expansion which is ridiculously expensive in cpp
|
||||
assert !ApplicationManager.getApplication().isDispatchThread();
|
||||
boolean isDataValid = isDataValid();
|
||||
boolean isReadOnly = isDataReadOnly();
|
||||
String text = getText(view);
|
||||
@@ -127,9 +130,11 @@ public abstract class Node extends DefaultMutableTreeNode {
|
||||
|
||||
// same as DefaultMutableTreeNode.insert() except it doesn't try to remove the newChild from its parent since we know it's new
|
||||
void insertNewNode(@NotNull Node newChild, int childIndex) {
|
||||
ApplicationManager.getApplication().assertIsDispatchThread();
|
||||
if (children == null) {
|
||||
children = new Vector();
|
||||
}
|
||||
//noinspection unchecked
|
||||
children.insertElementAt(newChild, childIndex);
|
||||
}
|
||||
|
||||
|
||||
@@ -498,8 +498,12 @@ class SearchForUsagesRunnable implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
UsageViewImpl usageView = myUsageViewRef.get();
|
||||
if (usageView != null) {
|
||||
usageView.waitForUpdateRequestsCompletion();
|
||||
}
|
||||
if (myListener != null) {
|
||||
myListener.findingUsagesFinished(myUsageViewRef.get());
|
||||
myListener.findingUsagesFinished(usageView);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import com.intellij.navigation.NavigationItem;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.actionSystem.*;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ReadAction;
|
||||
import com.intellij.openapi.command.CommandProcessor;
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
@@ -22,10 +23,7 @@ import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.ui.SimpleToolWindowPanel;
|
||||
import com.intellij.openapi.ui.Splitter;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.Factory;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.*;
|
||||
import com.intellij.openapi.vfs.ReadonlyStatusHandler;
|
||||
import com.intellij.openapi.vfs.VfsUtilCore;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
@@ -53,6 +51,7 @@ import com.intellij.util.concurrency.EdtExecutorService;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.LinkedMultiMap;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import com.intellij.util.containers.Queue;
|
||||
import com.intellij.util.enumeration.EmptyEnumeration;
|
||||
import com.intellij.util.messages.MessageBusConnection;
|
||||
import com.intellij.util.ui.DialogUtil;
|
||||
@@ -77,9 +76,7 @@ import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@@ -158,6 +155,7 @@ public class UsageViewImpl implements UsageView {
|
||||
private Usage myOriginUsage;
|
||||
@Nullable private Runnable myRerunActivity;
|
||||
private boolean myDisposeSmartPointersOnClose = true;
|
||||
private final Queue<Future<?>> updateRequests = new Queue<>(10); // guarded by insertionRequests
|
||||
|
||||
public UsageViewImpl(@NotNull final Project project,
|
||||
@NotNull UsageViewPresentation presentation,
|
||||
@@ -469,6 +467,7 @@ public class UsageViewImpl implements UsageView {
|
||||
Rectangle visibleRect = myTree.getVisibleRect();
|
||||
int rowForLocation = myTree.getClosestRowForLocation(0, visibleRect.y);
|
||||
int visibleRowCount = getVisibleRowCount();
|
||||
List<Node> toUpdate = new ArrayList<>();
|
||||
for (int i = rowForLocation + visibleRowCount + 1; i >= rowForLocation; i--) {
|
||||
final TreePath eachPath = myTree.getPathForRow(i);
|
||||
if (eachPath == null) continue;
|
||||
@@ -476,10 +475,14 @@ public class UsageViewImpl implements UsageView {
|
||||
treeState.invalidatePathBounds(eachPath);
|
||||
Object node = eachPath.getLastPathComponent();
|
||||
if (node instanceof UsageNode) {
|
||||
((UsageNode)node).update(this, edtNodeChangedQueue);
|
||||
toUpdate.add((Node)node);
|
||||
}
|
||||
}
|
||||
myTree.repaint(visibleRect);
|
||||
queueUpdateBulk(toUpdate, ()->{
|
||||
if (!isDisposed()) {
|
||||
myTree.repaint(visibleRect);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
myTree.setCellRenderer(myUsageViewTreeCellRenderer);
|
||||
@@ -637,7 +640,9 @@ public class UsageViewImpl implements UsageView {
|
||||
if (component instanceof Node) {
|
||||
Node node = (Node)component;
|
||||
if (!expandingAll && node.needsUpdate()) {
|
||||
checkNodeValidity(node, path);
|
||||
List<Node> toUpdate = new ArrayList<>();
|
||||
checkNodeValidity(node, path, toUpdate);
|
||||
queueUpdateBulk(toUpdate, EmptyRunnable.getInstance());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -886,17 +891,17 @@ public class UsageViewImpl implements UsageView {
|
||||
reset();
|
||||
myBuilder.setGroupingRules(getActiveGroupingRules(myProject, getUsageViewSettings()));
|
||||
myBuilder.setFilteringRules(getActiveFilteringRules(myProject));
|
||||
ApplicationManager.getApplication().runReadAction(() -> {
|
||||
for (Usage usage : allUsages) {
|
||||
if (!usage.isValid()) {
|
||||
continue;
|
||||
}
|
||||
if (usage instanceof MergeableUsage) {
|
||||
((MergeableUsage)usage).reset();
|
||||
}
|
||||
appendUsage(usage);
|
||||
for (int i = allUsages.size() - 1; i >= 0; i--) {
|
||||
Usage usage = allUsages.get(i);
|
||||
if (!usage.isValid()) {
|
||||
allUsages.remove(i);
|
||||
continue;
|
||||
}
|
||||
});
|
||||
if (usage instanceof MergeableUsage) {
|
||||
((MergeableUsage)usage).reset();
|
||||
}
|
||||
}
|
||||
appendUsagesInBulk(allUsages);
|
||||
if (myTree != null) {
|
||||
excludeUsages(excludedUsages.toArray(Usage.EMPTY_ARRAY));
|
||||
}
|
||||
@@ -1081,10 +1086,50 @@ public class UsageViewImpl implements UsageView {
|
||||
|
||||
@Override
|
||||
public void appendUsage(@NotNull Usage usage) {
|
||||
doAppendUsage(usage);
|
||||
if (ApplicationManager.getApplication().isDispatchThread()) {
|
||||
addUpdateRequest(ApplicationManager.getApplication().executeOnPooledThread(() -> ReadAction.run(() -> doAppendUsage(usage))));
|
||||
}
|
||||
else {
|
||||
doAppendUsage(usage);
|
||||
}
|
||||
}
|
||||
|
||||
private void addUpdateRequest(@NotNull Future<?> request) {
|
||||
synchronized (updateRequests) {
|
||||
while (!updateRequests.isEmpty() && updateRequests.peekFirst().isDone()) {
|
||||
updateRequests.pullFirst();
|
||||
}
|
||||
updateRequests.addLast(request);
|
||||
}
|
||||
}
|
||||
|
||||
void waitForUpdateRequestsCompletion() {
|
||||
assert !ApplicationManager.getApplication().isDispatchThread();
|
||||
while (true) {
|
||||
Future<?> request;
|
||||
synchronized (updateRequests) {
|
||||
request = updateRequests.isEmpty() ? null : updateRequests.pullFirst();
|
||||
}
|
||||
if (request == null) break;
|
||||
try {
|
||||
request.get();
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void appendUsagesInBulk(@NotNull Collection<Usage> usages) {
|
||||
addUpdateRequest(ApplicationManager.getApplication().executeOnPooledThread(() -> ReadAction.run(() -> {
|
||||
for (Usage usage : usages) {
|
||||
doAppendUsage(usage);
|
||||
}
|
||||
})));
|
||||
}
|
||||
|
||||
public UsageNode doAppendUsage(@NotNull Usage usage) {
|
||||
assert !ApplicationManager.getApplication().isDispatchThread();
|
||||
// invoke in ReadAction to be be sure that usages are not invalidated while the tree is being built
|
||||
ApplicationManager.getApplication().assertReadAccessAllowed();
|
||||
if (!usage.isValid()) {
|
||||
@@ -1175,28 +1220,46 @@ public class UsageViewImpl implements UsageView {
|
||||
ApplicationManager.getApplication().assertIsDispatchThread();
|
||||
if (myProject.isDisposed()) return;
|
||||
TreeNode root = (TreeNode)myTree.getModel().getRoot();
|
||||
checkNodeValidity(root, new TreePath(root));
|
||||
List<Node> toUpdate = new ArrayList<>();
|
||||
checkNodeValidity(root, new TreePath(root), toUpdate);
|
||||
queueUpdateBulk(toUpdate, EmptyRunnable.getInstance());
|
||||
updateOnSelectionChanged();
|
||||
}
|
||||
|
||||
private void queueUpdateBulk(@NotNull List<Node> toUpdate, @NotNull Runnable onCompletedInEdt) {
|
||||
if (toUpdate.isEmpty()) return;
|
||||
addUpdateRequest(ApplicationManager.getApplication().executeOnPooledThread(() -> {
|
||||
for (Node node : toUpdate) {
|
||||
try {
|
||||
if (isDisposed()) break;
|
||||
ReadAction.run(() -> node.update(this, edtNodeChangedQueue));
|
||||
}
|
||||
catch (IndexNotReadyException ignore) {
|
||||
}
|
||||
}
|
||||
ApplicationManager.getApplication().invokeLater(onCompletedInEdt);
|
||||
}));
|
||||
}
|
||||
|
||||
private void updateImmediatelyNodesUpToRoot(@NotNull Collection<Node> nodes) {
|
||||
ApplicationManager.getApplication().assertIsDispatchThread();
|
||||
if (myProject.isDisposed()) return;
|
||||
TreeNode root = (TreeNode)myTree.getModel().getRoot();
|
||||
Set<Node> updated = new HashSet<>();
|
||||
Set<Node> queued = new HashSet<>();
|
||||
List<Node> toUpdate = new ArrayList<>();
|
||||
while (true) {
|
||||
Set<Node> parents = new HashSet<>();
|
||||
for (Node node : nodes) {
|
||||
node.update(this, edtNodeChangedQueue);
|
||||
toUpdate.add(node);
|
||||
TreeNode parent = node.getParent();
|
||||
if (parent != root && parent instanceof Node && updated.add((Node)parent)) {
|
||||
if (parent != root && parent instanceof Node && queued.add((Node)parent)) {
|
||||
parents.add((Node)parent);
|
||||
}
|
||||
}
|
||||
if (parents.isEmpty()) break;
|
||||
nodes = parents;
|
||||
}
|
||||
|
||||
queueUpdateBulk(toUpdate, EmptyRunnable.getInstance());
|
||||
updateImmediately();
|
||||
}
|
||||
|
||||
@@ -1212,7 +1275,7 @@ public class UsageViewImpl implements UsageView {
|
||||
}
|
||||
}
|
||||
|
||||
private void checkNodeValidity(@NotNull TreeNode node, @NotNull TreePath path) {
|
||||
private void checkNodeValidity(@NotNull TreeNode node, @NotNull TreePath path, @NotNull List<Node> result) {
|
||||
ApplicationManager.getApplication().assertIsDispatchThread();
|
||||
boolean shouldCheckChildren = true;
|
||||
if (myTree.isCollapsed(path)) {
|
||||
@@ -1230,17 +1293,13 @@ public class UsageViewImpl implements UsageView {
|
||||
if (shouldCheckChildren && isVisible != UsageViewTreeCellRenderer.RowLocation.AFTER_VISIBLE_RECT) {
|
||||
for (int i=0; i < node.getChildCount(); i++) {
|
||||
TreeNode child = node.getChildAt(i);
|
||||
checkNodeValidity(child, path.pathByAddingChild(child));
|
||||
checkNodeValidity(child, path.pathByAddingChild(child), result);
|
||||
}
|
||||
}
|
||||
|
||||
// call update last, to let children a chance to update their cache first
|
||||
if (node instanceof Node && node != getModelRoot() && isVisible == UsageViewTreeCellRenderer.RowLocation.INSIDE_VISIBLE_RECT) {
|
||||
try {
|
||||
((Node)node).update(this, edtNodeChangedQueue);
|
||||
}
|
||||
catch (IndexNotReadyException ignore) {
|
||||
}
|
||||
result.add((Node)node);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ import com.intellij.util.ui.UIUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
@@ -67,8 +68,15 @@ public class UsageViewManagerImpl extends UsageViewManager {
|
||||
@NotNull UsageViewPresentation presentation,
|
||||
Factory<UsageSearcher> usageSearcherFactory) {
|
||||
UsageViewImpl usageView = new UsageViewImpl(myProject, presentation, targets, usageSearcherFactory);
|
||||
appendUsages(usages, usageView);
|
||||
usageView.appendUsagesInBulk(Arrays.asList(usages));
|
||||
ProgressManager.getInstance().run(new Task.Modal(myProject, "Waiting For Usages", false) {
|
||||
@Override
|
||||
public void run(@NotNull ProgressIndicator indicator) {
|
||||
usageView.waitForUpdateRequestsCompletion();
|
||||
}
|
||||
});
|
||||
usageView.setSearchInProgress(false);
|
||||
|
||||
return usageView;
|
||||
}
|
||||
|
||||
@@ -205,14 +213,6 @@ public class UsageViewManagerImpl extends UsageViewManager {
|
||||
}
|
||||
}
|
||||
|
||||
protected static void appendUsages(@NotNull final Usage[] foundUsages, @NotNull final UsageViewImpl usageView) {
|
||||
ApplicationManager.getApplication().runReadAction(() -> {
|
||||
for (Usage foundUsage : foundUsages) {
|
||||
usageView.appendUsage(foundUsage);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public static void showTooManyUsagesWarningLater(@NotNull final Project project,
|
||||
@NotNull final TooManyUsagesStatus tooManyUsagesStatus,
|
||||
|
||||
Reference in New Issue
Block a user