IJPL-158493 Reduce dependency on AsyncTreeModel

Before migrating the Project View to the new models,
we need to take care of existing code that relies on the exact
implementation class.

For "Can this thing calculate nodes on a BGT?" instanceof checks,
introduce a new marker interface, BgtAwareTreeModel.
We may add methods such as isProcessing() there later.
Replace existing usages with the new interface.

For "Can this thing accept a visitor on a BGT?" instanceof checks,
introduce TreeVisitor.LoadingAwareAcceptor with the second
accept() overload that controls node loading. Replace existing
usages.

GitOrigin-RevId: 67905cc6873aab2f917ee2028d0a167f60fa85f7
This commit is contained in:
Sergei Tachenov
2024-09-13 15:05:12 +03:00
committed by intellij-monorepo-bot
parent b211b4adeb
commit 1f3bbf9580
13 changed files with 51 additions and 14 deletions

View File

@@ -123,7 +123,7 @@ public abstract class ChooseLibrariesDialogBase extends DialogWrapper {
protected void queueUpdateAndSelect(@NotNull final Library library) {
myModel.invalidateAsync().thenRun(() -> {
((AsyncTreeModel)myTree.getModel()).accept(path -> {
((TreeVisitor.Acceptor)myTree.getModel()).accept(path -> {
return TreeVisitor.Action.CONTINUE; // traverse to update myParentsMap
}).onProcessed(path -> {
myModel.select(library, myTree, p -> {});

View File

@@ -3028,6 +3028,10 @@ c:com.intellij.ui.tree.TreeVisitor$ByTreePath
- visit(javax.swing.tree.TreePath):com.intellij.ui.tree.TreeVisitor$Action
- p:visit(javax.swing.tree.TreePath,java.lang.Object):com.intellij.ui.tree.TreeVisitor$Action
- p:visit(javax.swing.tree.TreePath,java.lang.Object,I):com.intellij.ui.tree.TreeVisitor$Action
com.intellij.ui.tree.TreeVisitor$LoadingAwareAcceptor
- com.intellij.ui.tree.TreeVisitor$Acceptor
- accept(com.intellij.ui.tree.TreeVisitor):org.jetbrains.concurrency.Promise
- a:accept(com.intellij.ui.tree.TreeVisitor,Z):org.jetbrains.concurrency.Promise
*e:com.intellij.ui.tree.TreeVisitor$VisitThread
- java.lang.Enum
- sf:BGT:com.intellij.ui.tree.TreeVisitor$VisitThread

View File

@@ -71,6 +71,23 @@ public interface TreeVisitor {
Promise<TreePath> accept(@NotNull TreeVisitor visitor);
}
/**
* Represents a tree model that accepts a tree visitor and promises a result, optionally allowing to skip not loaded nodes.
*/
interface LoadingAwareAcceptor extends Acceptor {
@Override
default @NotNull Promise<TreePath> accept(@NotNull TreeVisitor visitor) {
return accept(visitor, true);
}
/**
* @param visitor an object that controls visiting a tree structure
* @param allowLoading a flag that determines whether the nodes that weren't loaded yet will be loaded and visited or skipped
* @return a promise that will be resolved when visiting is finished
*/
@NotNull
Promise<TreePath> accept(@NotNull TreeVisitor visitor, boolean allowLoading);
}
abstract class ByComponent<C, T> implements TreeVisitor {
private final Function<TreePath, T> converter;

View File

@@ -21,7 +21,6 @@ com/intellij/ide/actions/searcheverywhere/SearchEverywhereSpellingCorrector
com/intellij/ide/actions/searcheverywhere/SearchListModel
com/intellij/ide/plugins/ContainerDescriptor
com/intellij/ide/plugins/IdeaPluginDescriptorImpl
com/intellij/ide/projectView/impl/AsyncProjectViewSupport
com/intellij/ide/todo/FileTree
com/intellij/ide/todo/TodoNodeVisitor
com/intellij/ide/todo/TodoTreeBuilderCoroutineHelper

View File

@@ -6,8 +6,8 @@ import com.intellij.ide.bookmark.FileBookmark
import com.intellij.ide.bookmark.ui.BookmarksView
import com.intellij.openapi.vfs.VfsUtilCore.isAncestor
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.ui.tree.AsyncTreeModel
import com.intellij.ui.tree.TreeCollector
import com.intellij.ui.tree.TreeVisitor
import com.intellij.ui.tree.project.ProjectFileNodeUpdater
import javax.swing.tree.TreePath
@@ -42,7 +42,7 @@ internal class FolderNodeUpdater(val view: BookmarksView) : ProjectFileNodeUpdat
}
private fun forEachTreePath(file: VirtualFile, action: (TreePath) -> Unit) {
val model = view.tree.model as? AsyncTreeModel ?: return
val model = view.tree.model as? TreeVisitor.LoadingAwareAcceptor ?: return
val paths = mutableListOf<TreePath>()
model.accept(VirtualFileVisitor(file, paths), false).onSuccess { paths.forEach(action) }
}

View File

@@ -38,6 +38,7 @@ import com.intellij.ui.tree.AsyncTreeModel;
import com.intellij.ui.tree.TreePathUtil;
import com.intellij.ui.tree.TreeVisitor;
import com.intellij.ui.tree.project.ProjectFileNode;
import com.intellij.ui.treeStructure.BgtAwareTreeModel;
import com.intellij.ui.treeStructure.TreeStateListener;
import com.intellij.util.ArrayUtil;
import com.intellij.util.ArrayUtilRt;
@@ -637,7 +638,7 @@ public abstract class AbstractProjectViewPane implements UiCompatibleDataProvide
private boolean isExpandAllAllowed() {
JTree tree = getTree();
TreeModel model = tree == null ? null : tree.getModel();
return model == null || model instanceof AsyncTreeModel || model instanceof InvokerSupplier;
return model == null || model instanceof BgtAwareTreeModel || model instanceof InvokerSupplier;
}
@Override

View File

@@ -143,7 +143,7 @@ public abstract class TodoPanel extends SimpleToolWindowPanel implements Occuren
TodoView todoView = this.myProject.getService(TodoView.class);
todoView.setSelectedContent(this);
AsyncTreeModel model = (AsyncTreeModel)myTree.getModel();
var model = (TreeVisitor.Acceptor)myTree.getModel();
model.accept(new TreeVisitor() {
@Override
public @NotNull Action visit(@NotNull TreePath path) {

View File

@@ -10908,6 +10908,8 @@ c:com.intellij.ui.treeStructure.AutoExpandSimpleNodeListener
- com.intellij.util.ui.tree.TreeModelAdapter
- <init>(javax.swing.JTree):V
- treeNodesInserted(javax.swing.event.TreeModelEvent):V
com.intellij.ui.treeStructure.BgtAwareTreeModel
- javax.swing.tree.TreeModel
a:com.intellij.ui.treeStructure.CachingSimpleNode
- com.intellij.ui.treeStructure.SimpleNode
- p:<init>(com.intellij.openapi.project.Project,com.intellij.ide.util.treeView.NodeDescriptor):V

View File

@@ -0,0 +1,9 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.ui.treeStructure;
import javax.swing.tree.TreeModel;
/**
* Marker interface to indicate that the model can load nodes in the background without freezing the EDT
*/
public interface BgtAwareTreeModel extends TreeModel { }

View File

@@ -25514,7 +25514,8 @@ a:com.intellij.ui.tree.AbstractTreeWalker
- start(javax.swing.tree.TreePath,java.lang.Object):V
f:com.intellij.ui.tree.AsyncTreeModel
- com.intellij.ui.tree.Searchable
- com.intellij.ui.tree.TreeVisitor$Acceptor
- com.intellij.ui.tree.TreeVisitor$LoadingAwareAcceptor
- com.intellij.ui.treeStructure.BgtAwareTreeModel
- com.intellij.util.ui.tree.AbstractTreeModel
- <init>(javax.swing.tree.TreeModel,com.intellij.openapi.Disposable):V
- <init>(javax.swing.tree.TreeModel,Z,com.intellij.openapi.Disposable):V

View File

@@ -11,6 +11,7 @@ import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.util.Disposer;
import com.intellij.ui.LoadingNode;
import com.intellij.ui.treeStructure.BgtAwareTreeModel;
import com.intellij.ui.treeStructure.CachingTreePath;
import com.intellij.util.concurrency.Invoker;
import com.intellij.util.concurrency.InvokerSupplier;
@@ -40,7 +41,9 @@ import static java.util.Collections.emptyList;
import static org.jetbrains.concurrency.Promises.rejectedPromise;
import static org.jetbrains.concurrency.Promises.resolvedPromise;
public final class AsyncTreeModel extends AbstractTreeModel implements Searchable, TreeVisitor.Acceptor, CachedTreePresentationSupport {
public final class AsyncTreeModel extends AbstractTreeModel
implements Searchable, TreeVisitor.LoadingAwareAcceptor, CachedTreePresentationSupport, BgtAwareTreeModel
{
private static final Logger LOG = Logger.getInstance(AsyncTreeModel.class);
private final Invoker foreground;
private final Invoker background;
@@ -236,6 +239,7 @@ public final class AsyncTreeModel extends AbstractTreeModel implements Searchabl
* @param allowLoading load all needed children if {@code true}
* @return a promise that will be resolved when visiting is finished
*/
@Override
public @NotNull Promise<TreePath> accept(@NotNull TreeVisitor visitor, boolean allowLoading) {
var walker = createWalker(visitor, allowLoading);
if (allowLoading) {

View File

@@ -11,8 +11,8 @@ import com.intellij.ui.*;
import com.intellij.ui.hover.TreeHoverListener;
import com.intellij.ui.render.RenderingHelper;
import com.intellij.ui.render.RenderingUtil;
import com.intellij.ui.tree.AsyncTreeModel;
import com.intellij.ui.tree.TreePathBackgroundSupplier;
import com.intellij.ui.treeStructure.BgtAwareTreeModel;
import com.intellij.ui.treeStructure.Tree;
import com.intellij.ui.treeStructure.TreeUiBulkExpandCollapseSupport;
import com.intellij.util.ObjectUtils;
@@ -602,7 +602,7 @@ public class DefaultTreeUI extends BasicTreeUI implements TreeUiBulkExpandCollap
@Override
protected void setRootVisible(boolean newValue) {
if (treeModel instanceof AsyncTreeModel) {
if (treeModel instanceof BgtAwareTreeModel) {
// this method must be called on EDT to be consistent with ATM,
// because it modifies a list of visible nodes in the layout cache
EdtInvocationManager.invokeLaterIfNeeded(() -> super.setRootVisible(newValue));
@@ -720,7 +720,7 @@ public class DefaultTreeUI extends BasicTreeUI implements TreeUiBulkExpandCollap
JTree tree = getTree();
if (!shouldAutoExpand(tree, path)) return;
TreeModel model = tree.getModel();
if (model instanceof AsyncTreeModel && 1 == model.getChildCount(path.getLastPathComponent())) {
if (model instanceof BgtAwareTreeModel && 1 == model.getChildCount(path.getLastPathComponent())) {
int pathCount = 1 + path.getPathCount();
for (int i = 0; i <= oldRowCount; i++) {
TreePath row = getPathForRow(i);
@@ -799,10 +799,10 @@ public class DefaultTreeUI extends BasicTreeUI implements TreeUiBulkExpandCollap
if (!shouldAutoExpand(tree, row.getParentPath())) {
return;
}
if (tree.getModel() instanceof AsyncTreeModel asyncTreeModel) {
if (tree.getModel() instanceof BgtAwareTreeModel) {
Object node = row.getLastPathComponent();
if (isAutoExpandAllowed(tree, node)) {
asyncTreeModel.onValidThread(() -> tree.expandPath(row));
EdtInvocationManager.invokeLaterIfNeeded(() -> tree.expandPath(row));
}
}
}

View File

@@ -236,7 +236,7 @@ public class MavenProjectsStructure extends SimpleTreeStructure {
}
public void accept(@NotNull TreeVisitor visitor) {
((AsyncTreeModel)myTree.getModel()).accept(visitor);
((TreeVisitor.Acceptor)myTree.getModel()).accept(visitor);
}
public void updateGoals() {