[TreeView] Slow operations are prohibited on EDT for TestSourcesFilter.isTestSources

Our plugin contains a custom TreeView that apply custom color scheme to test sources by calling `TestSourcesFilter.isTestSources` but that is not allowed on EDT. Could you please suggest the intended way of achieving that functionality without emitting the error?

We are getting the following error:
java.lang.Throwable: Slow operations are prohibited on EDT. See SlowOperations.assertSlowOperationsAreAllowed javadoc.
at com.intellij.openapi.diagnostic.Logger.error(Logger.java:375)
at com.intellij.util.SlowOperations.logError(SlowOperations.java:180)
at com.intellij.util.SlowOperations.assertSlowOperationsAreAllowed(SlowOperations.java:128)
at com.intellij.workspaceModel.core.fileIndex.impl.WorkspaceFileIndexDataImpl.ensureIsUpToDate(WorkspaceFileIndexDataImpl.kt:232)
at com.intellij.workspaceModel.core.fileIndex.impl.WorkspaceFileIndexDataImpl.getFileInfo(WorkspaceFileIndexDataImpl.kt:176)
at com.intellij.workspaceModel.core.fileIndex.impl.WorkspaceFileIndexImpl.getFileInfo(WorkspaceFileIndexImpl.kt:357)
at com.intellij.workspaceModel.core.fileIndex.impl.WorkspaceFileIndexImpl.findFileSetWithCustomData(WorkspaceFileIndexImpl.kt:317)
at com.intellij.openapi.roots.impl.ProjectFileIndexImpl.isInTestSourceContent(ProjectFileIndexImpl.java:283)
at com.intellij.openapi.roots.ProjectRootTestSourcesFilter.lambda$isTestSource$0(ProjectRootTestSourcesFilter.java:12)
at com.intellij.openapi.application.impl.AppImplKt$rethrowCheckedExceptions$2.invoke(appImpl.kt:126)
at com.intellij.platform.locking.impl.NestedLocksThreadingSupport.runReadAction(NestedLocksThreadingSupport.kt:856)
at com.intellij.openapi.application.impl.ApplicationImpl.runReadAction(ApplicationImpl.java:1068)
at com.intellij.openapi.application.ReadAction.compute(ReadAction.java:66)
at com.intellij.openapi.roots.ProjectRootTestSourcesFilter.isTestSource(ProjectRootTestSourcesFilter.java:12)
at com.intellij.openapi.roots.TestSourcesFilter.isTestSources(TestSourcesFilter.java:32)
at MyPluginWorkspaceTree.getBackgroundColor
at MyPluginWorkspaceTree.getFileColorFor
at com.intellij.ui.treeStructure.Tree.getFileColorForPath(Tree.java:455)
at com.intellij.ui.treeStructure.Tree.getFileColorForRow(Tree.java:445)
at com.intellij.ui.treeStructure.Tree.paintFileColorGutter(Tree.java:409)
at com.intellij.ui.treeStructure.Tree.paintComponent(Tree.java:391)

What is your tree model? The “true” way of handling such stuff is by using AsyncTreeModel wrapping some background model (often StructureTreeModel) and using PresentableNodeDescriptor-based user objects. There you can override computeBackgroundColor which will then be used when updating nodes in background, and then all your getFileColorFor override has to do is to retrieve it from the presentation data similarly to how our ProjectViewTree does.

Of course, you don’t have to use all that platform stuff if that’s inconvenient for some reason, but then you have to do something like that using some kind of service. But the idea stays the same: some background service computes colors, updates tree nodes and then fires “node changed” events so that the tree reacts.

Thanks a lot for the detailed explanation. The proposed solution works like a charm.