blob: 1a45483ed2d20ec18471af7cf7805899087744f5 [file]
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.plugins.gradle.projectView;
import com.intellij.ide.projectView.PresentationData;
import com.intellij.ide.projectView.TreeStructureProvider;
import com.intellij.ide.projectView.ViewSettings;
import com.intellij.ide.projectView.impl.ProjectRootsUtil;
import com.intellij.ide.projectView.impl.nodes.*;
import com.intellij.ide.util.treeView.AbstractTreeNode;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleGrouper;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDirectory;
import com.intellij.util.SmartList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.gradle.service.project.GradleProjectResolverUtil;
import org.jetbrains.plugins.gradle.util.GradleConstants;
import java.util.Collection;
import java.util.List;
import static com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil.*;
import static com.intellij.ui.SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES;
import static com.intellij.ui.SimpleTextAttributes.merge;
/**
* @author Vladislav.Soroka
*/
public class GradleTreeStructureProvider implements TreeStructureProvider, DumbAware {
@NotNull
@Override
public Collection<AbstractTreeNode<?>> modify(@NotNull AbstractTreeNode<?> parent,
@NotNull Collection<AbstractTreeNode<?>> children,
ViewSettings settings) {
Project project = parent.getProject();
if (project == null) return children;
if (parent instanceof ProjectViewProjectNode) {
return getProjectNodeChildren(project, children);
}
if (parent instanceof ProjectViewModuleGroupNode) {
Collection<AbstractTreeNode<?>> modifiedChildren = new SmartList<>();
for (AbstractTreeNode child : children) {
if (child instanceof ProjectViewModuleNode) {
Module module = ((ProjectViewModuleNode)child).getValue();
if (!showUnderModuleGroup(module)) continue;
GradleProjectViewModuleNode sourceSetNode = getGradleModuleNode(project, (ProjectViewModuleNode)child, settings);
child = sourceSetNode != null ? sourceSetNode : child;
}
else if (child instanceof PsiDirectoryNode) {
GradleModuleDirectoryNode sourceSetNode = getGradleModuleNode(project, (PsiDirectoryNode)child, settings);
if (sourceSetNode != null && !showUnderModuleGroup(sourceSetNode.myModule)) continue;
child = sourceSetNode != null ? sourceSetNode : child;
}
modifiedChildren.add(child);
}
return modifiedChildren;
}
if (parent instanceof GradleProjectViewModuleNode) {
Module module = ((GradleProjectViewModuleNode)parent).getValue();
String projectPath = getExternalProjectPath(module);
Collection<AbstractTreeNode<?>> modifiedChildren = new SmartList<>();
for (AbstractTreeNode child : children) {
if (child instanceof PsiDirectoryNode) {
PsiDirectory psiDirectory = ((PsiDirectoryNode)child).getValue();
if (psiDirectory != null) {
final VirtualFile virtualFile = psiDirectory.getVirtualFile();
if (projectPath != null && FileUtil.isAncestor(projectPath, virtualFile.getPath(), false)) {
continue;
}
}
}
modifiedChildren.add(child);
}
return modifiedChildren;
}
if (parent instanceof PsiDirectoryNode) {
Collection<AbstractTreeNode<?>> modifiedChildren = new SmartList<>();
for (AbstractTreeNode child : children) {
if (child instanceof PsiDirectoryNode) {
GradleModuleDirectoryNode sourceSetNode = getGradleModuleNode(project, (PsiDirectoryNode)child, settings);
child = sourceSetNode != null ? sourceSetNode : child;
}
modifiedChildren.add(child);
}
return modifiedChildren;
}
return children;
}
private static boolean showUnderModuleGroup(Module module) {
if (isExternalSystemAwareModule(GradleConstants.SYSTEM_ID, module)) {
String projectPath = getExternalProjectPath(module);
for (VirtualFile root : ModuleRootManager.getInstance(module).getContentRoots()) {
if (projectPath != null && !FileUtil.isAncestor(projectPath, root.getPath(), true)) {
return true;
}
}
return false;
}
return true;
}
@NotNull
private static Collection<AbstractTreeNode<?>> getProjectNodeChildren(@NotNull Project project,
@NotNull Collection<AbstractTreeNode<?>> children) {
Collection<AbstractTreeNode<?>> modifiedChildren = new SmartList<>();
ProjectFileIndex fileIndex = ProjectRootManager.getInstance(project).getFileIndex();
for (AbstractTreeNode child : children) {
Pair<VirtualFile, PsiDirectoryNode> parentNodePair = null;
if (child instanceof ProjectViewModuleGroupNode) {
final ProjectViewModuleGroupNode groupNode = (ProjectViewModuleGroupNode)child;
final Collection<AbstractTreeNode<?>> groupNodeChildren = groupNode.getChildren();
for (final AbstractTreeNode node : groupNodeChildren) {
if (node instanceof PsiDirectoryNode) {
final PsiDirectoryNode psiDirectoryNode = (PsiDirectoryNode)node;
final PsiDirectory psiDirectory = psiDirectoryNode.getValue();
if (psiDirectory == null) {
parentNodePair = null;
break;
}
final VirtualFile virtualFile = psiDirectory.getVirtualFile();
final Module module = fileIndex.getModuleForFile(virtualFile);
if (!isExternalSystemAwareModule(GradleConstants.SYSTEM_ID, module)) {
parentNodePair = null;
break;
}
if (parentNodePair == null || VfsUtilCore.isAncestor(virtualFile, parentNodePair.first, false)) {
parentNodePair = Pair.pair(virtualFile, psiDirectoryNode);
}
else if (!VfsUtilCore.isAncestor(parentNodePair.first, virtualFile, false)) {
parentNodePair = null;
break;
}
}
else {
parentNodePair = null;
break;
}
}
}
else if (child instanceof PsiDirectoryNode && child.getParent() == null) {
PsiDirectory psiDirectory = ((PsiDirectoryNode)child).getValue();
if (psiDirectory != null) {
VirtualFile directoryFile = psiDirectory.getVirtualFile();
GradleModuleDirectoryNode gradleModuleNode = getGradleModuleNode(project, (PsiDirectoryNode)child,
((PsiDirectoryNode)child).getSettings());
if (gradleModuleNode != null) {
parentNodePair = Pair.pair(directoryFile, gradleModuleNode);
}
}
}
modifiedChildren.add(parentNodePair != null ? parentNodePair.second : child);
}
return modifiedChildren;
}
@Nullable
private static GradleProjectViewModuleNode getGradleModuleNode(@NotNull Project project,
@NotNull ProjectViewModuleNode moduleNode,
ViewSettings settings) {
Module module = moduleNode.getValue();
final String moduleShortName = getGradleModuleShortName(module);
if (moduleShortName == null) return null;
return new GradleProjectViewModuleNode(project, module, settings, moduleShortName);
}
@Nullable
private static GradleModuleDirectoryNode getGradleModuleNode(@NotNull Project project,
@NotNull PsiDirectoryNode directoryNode,
ViewSettings settings) {
PsiDirectory psiDirectory = directoryNode.getValue();
if (psiDirectory == null) return null;
final VirtualFile virtualFile = psiDirectory.getVirtualFile();
if (!ProjectRootsUtil.isModuleContentRoot(virtualFile, project)) return null;
ProjectFileIndex fileIndex = ProjectRootManager.getInstance(project).getFileIndex();
final Module module = fileIndex.getModuleForFile(virtualFile);
final String moduleShortName = getGradleModuleShortName(module);
if (moduleShortName == null) return null;
return new GradleModuleDirectoryNode(project, psiDirectory, settings, module, moduleShortName, directoryNode.getFilter());
}
@Nullable
private static String getGradleModuleShortName(Module module) {
if (!isExternalSystemAwareModule(GradleConstants.SYSTEM_ID, module)) return null;
String moduleShortName;
if (isSourceSetModule(module)) {
return GradleProjectResolverUtil.getSourceSetName(module);
}
else {
moduleShortName = getExternalProjectId(module);
}
boolean isRootModule = StringUtil.equals(getExternalProjectPath(module), getExternalRootProjectPath(module));
if (isRootModule || moduleShortName == null) return moduleShortName;
moduleShortName = ModuleGrouper.instanceFor(module.getProject()).getShortenedNameByFullModuleName(moduleShortName);
return StringUtil.getShortName(moduleShortName, ':');
}
private static boolean isSourceSetModule(Module module) {
return GradleConstants.GRADLE_SOURCE_SET_MODULE_TYPE_KEY.equals(getExternalModuleType(module));
}
private static class GradleModuleDirectoryNode extends PsiDirectoryNode {
private final String myModuleShortName;
private final Module myModule;
private final boolean appendModuleName;
private final boolean isSourceSetModule;
GradleModuleDirectoryNode(Project project,
@NotNull PsiDirectory psiDirectory,
ViewSettings settings,
Module module,
String moduleShortName,
PsiFileSystemItemFilter filter) {
super(project, psiDirectory, settings, filter);
myModuleShortName = moduleShortName;
myModule = module;
VirtualFile directoryFile = psiDirectory.getVirtualFile();
appendModuleName = StringUtil.isNotEmpty(myModuleShortName) &&
!StringUtil.equalsIgnoreCase(myModuleShortName.replace("-", ""), directoryFile.getName().replace("-", ""));
isSourceSetModule = isSourceSetModule(myModule);
}
@Override
protected boolean shouldShowModuleName() {
return !(appendModuleName || isSourceSetModule);
}
@Override
protected void updateImpl(@NotNull PresentationData data) {
super.updateImpl(data);
if (appendModuleName) {
data.addText("[" + myModuleShortName + "]", REGULAR_BOLD_ATTRIBUTES);
}
else if (isSourceSetModule) {
List<ColoredFragment> fragments = data.getColoredText();
if (fragments.size() == 1) {
ColoredFragment fragment = fragments.iterator().next();
data.clearText();
data.addText(fragment.getText().trim(), merge(fragment.getAttributes(), REGULAR_BOLD_ATTRIBUTES));
}
}
}
}
private static class GradleProjectViewModuleNode extends ProjectViewModuleNode {
@NotNull
private final String myModuleShortName;
GradleProjectViewModuleNode(Project project, Module value, ViewSettings viewSettings, @NotNull String moduleShortName) {
super(project, value, viewSettings);
myModuleShortName = moduleShortName;
}
@Override
public void update(@NotNull PresentationData presentation) {
super.update(presentation);
presentation.setPresentableText(myModuleShortName);
presentation.addText(myModuleShortName, REGULAR_BOLD_ATTRIBUTES);
}
@Override
protected boolean showModuleNameInBold() {
return false;
}
}
}