ability to create custom compound node decorator or tree structure provider

This commit is contained in:
Sergey Malenkov
2018-03-19 02:07:30 +03:00
parent bbf5dce5b7
commit fd1e8d9ac9
2 changed files with 60 additions and 51 deletions
@@ -4,51 +4,68 @@ package com.intellij.ide.projectView.impl;
import com.intellij.ide.projectView.PresentationData;
import com.intellij.ide.projectView.ProjectViewNode;
import com.intellij.ide.projectView.ProjectViewNodeDecorator;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.project.IndexNotReadyException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
import com.intellij.packageDependencies.ui.PackageDependenciesNode;
import com.intellij.ui.ColoredTreeCellRenderer;
import org.jetbrains.annotations.NotNull;
import java.util.function.Consumer;
/**
* This class is intended to combine all decorators for batch usages.
*
* @author Sergey Malenkov
*/
public final class CompoundProjectViewNodeDecorator implements ProjectViewNodeDecorator {
private static final ProjectViewNodeDecorator EMPTY = new CompoundProjectViewNodeDecorator();
private static final Key<ProjectViewNodeDecorator> KEY = Key.create("ProjectViewNodeDecorator");
private final Project project;
private static final Logger LOG = Logger.getInstance(CompoundProjectViewNodeDecorator.class);
private final ProjectViewNodeDecorator[] decorators;
/**
* @return a shared instance for the specified project
*/
@NotNull
public static ProjectViewNodeDecorator get(@NotNull Project project) {
if (project.isDisposed()) return EMPTY;
ProjectViewNodeDecorator provider = project.getUserData(KEY);
if (provider != null) return provider;
provider = new CompoundProjectViewNodeDecorator(project);
provider = new CompoundProjectViewNodeDecorator(EP_NAME.getExtensions(project));
project.putUserData(KEY, provider);
return provider;
}
private CompoundProjectViewNodeDecorator(@NotNull Project project) {
this.project = project;
public CompoundProjectViewNodeDecorator(@NotNull ProjectViewNodeDecorator... decorators) {
this.decorators = decorators;
}
@Override
public void decorate(ProjectViewNode node, PresentationData data) {
if (!project.isDisposed()) {
for (ProjectViewNodeDecorator decorator : EP_NAME.getExtensions(project)) {
decorator.decorate(node, data);
}
}
forEach(decorator -> decorator.decorate(node, data));
}
@Override
public void decorate(PackageDependenciesNode node, ColoredTreeCellRenderer cellRenderer) {
if (!project.isDisposed()) {
for (ProjectViewNodeDecorator decorator : EP_NAME.getExtensions(project)) {
decorator.decorate(node, cellRenderer);
forEach(decorator -> decorator.decorate(node, cellRenderer));
}
private void forEach(@NotNull Consumer<ProjectViewNodeDecorator> consumer) {
for (ProjectViewNodeDecorator decorator : decorators) {
try {
consumer.accept(decorator);
}
catch (IndexNotReadyException exception) {
throw new ProcessCanceledException(exception);
}
catch (ProcessCanceledException exception) {
throw exception;
}
catch (Exception exception) {
LOG.warn("unexpected error in " + decorator, exception);
}
}
}
@@ -6,7 +6,6 @@ import com.intellij.ide.projectView.ViewSettings;
import com.intellij.ide.util.treeView.AbstractTreeNode;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.IndexNotReadyException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
@@ -23,24 +22,26 @@ import java.util.Objects;
* @author Sergey Malenkov
*/
public final class CompoundTreeStructureProvider implements TreeStructureProvider {
private static final TreeStructureProvider EMPTY = new CompoundTreeStructureProvider();
private static final Key<TreeStructureProvider> KEY = Key.create("TreeStructureProvider");
private static final Logger LOG = Logger.getInstance(CompoundTreeStructureProvider.class);
private final Project project;
private final TreeStructureProvider[] providers;
/**
* @return a shared instance for the specified project
*/
@NotNull
public static TreeStructureProvider get(@NotNull Project project) {
if (project.isDisposed()) return EMPTY;
TreeStructureProvider provider = project.getUserData(KEY);
if (provider != null) return provider;
provider = new CompoundTreeStructureProvider(project);
provider = new CompoundTreeStructureProvider(EP_NAME.getExtensions(project));
project.putUserData(KEY, provider);
return provider;
}
private CompoundTreeStructureProvider(@NotNull Project project) {
this.project = project;
public CompoundTreeStructureProvider(@NotNull TreeStructureProvider... providers) {
this.providers = providers;
}
@NotNull
@@ -48,30 +49,25 @@ public final class CompoundTreeStructureProvider implements TreeStructureProvide
public Collection<AbstractTreeNode> modify(@NotNull AbstractTreeNode parent,
@NotNull Collection<AbstractTreeNode> children,
ViewSettings settings) {
if (!children.isEmpty()) {
TreeStructureProvider[] providers = getProviders();
if (providers != null && providers.length != 0) {
for (TreeStructureProvider provider : providers) {
try {
children = provider.modify(parent, children, settings);
if (children.stream().anyMatch(Objects::isNull)) {
LOG.warn("null child provided by " + provider);
children = StreamEx.of(children).nonNull().toImmutableList();
}
}
catch (IndexNotReadyException exception) {
throw new ProcessCanceledException(exception);
}
catch (ProcessCanceledException exception) {
throw exception;
}
catch (Exception exception) {
LOG.warn("unexpected error in " + provider, exception);
}
for (TreeStructureProvider provider : providers) {
try {
children = provider.modify(parent, children, settings);
if (children.stream().anyMatch(Objects::isNull)) {
LOG.warn("null child provided by " + provider);
children = StreamEx.of(children).nonNull().toImmutableList();
}
}
children.forEach(node -> node.setParent(parent));
catch (IndexNotReadyException exception) {
throw new ProcessCanceledException(exception);
}
catch (ProcessCanceledException exception) {
throw exception;
}
catch (Exception exception) {
LOG.warn("unexpected error in " + provider, exception);
}
}
children.forEach(node -> node.setParent(parent));
return children;
}
@@ -79,24 +75,20 @@ public final class CompoundTreeStructureProvider implements TreeStructureProvide
@Override
public Object getData(Collection<AbstractTreeNode> selection, String id) {
if (id != null && selection != null && !selection.isEmpty()) {
TreeStructureProvider[] providers = getProviders();
if (providers != null && providers.length != 0) {
for (TreeStructureProvider provider : providers) {
if (isDumbMode(provider)) continue;
for (TreeStructureProvider provider : providers) {
try {
Object data = provider.getData(selection, id);
if (data != null) return data;
}
catch (IndexNotReadyException ignore) {
}
catch (ProcessCanceledException ignore) {
}
catch (Exception exception) {
LOG.warn("unexpected error in " + provider, exception);
}
}
}
return null;
}
@Nullable
private TreeStructureProvider[] getProviders() {
return project.isDisposed() ? null : EP_NAME.getExtensions(project);
}
private boolean isDumbMode(TreeStructureProvider provider) {
return project.isDisposed() || DumbService.isDumb(project) && !DumbService.isDumbAware(provider);
}
}