ScopeView: hide modules and content roots if ShowModules is false

This commit is contained in:
Sergey Malenkov
2018-06-14 22:50:33 +03:00
parent 079aef3562
commit 36b2a20e8d
3 changed files with 80 additions and 59 deletions
@@ -74,6 +74,7 @@ import java.util.function.BiFunction;
import java.util.stream.Collectors;
import static com.intellij.ide.projectView.impl.ProjectRootsUtil.findSourceFolder;
import static com.intellij.ide.projectView.impl.ShowModulesAction.hasModules;
import static com.intellij.openapi.roots.ui.configuration.SourceRootPresentation.getSourceRootIcon;
import static com.intellij.openapi.util.io.FileUtil.getLocationRelativeToUserHome;
import static com.intellij.openapi.vfs.VfsUtilCore.VFS_SEPARATOR_CHAR;
@@ -215,6 +216,7 @@ public final class ScopeViewTreeModel extends BaseTreeModel<AbstractTreeNode> im
model.onValidThread(() -> {
root.childrenValid = false;
LOG.debug("whole structure changed");
model.setShowModules(hasModules() && root.getSettings().isShowModules());
treeStructureChanged(null, null, null);
if (onDone != null) onDone.run();
});
@@ -534,13 +536,7 @@ public final class ScopeViewTreeModel extends BaseTreeModel<AbstractTreeNode> im
model.getChildren(model.getRoot()).forEach(child -> newRoots.put(child, mapper.apply(this, child)));
roots = newRoots;
if (newRoots.isEmpty()) return emptyList();
ModuleManager manager = getModuleManager(getProject());
if (manager == null) return emptyList();
boolean hidden = !getSettings().isShowModules();
if (!hidden && manager.getModules().length <= 1) hidden = true;
boolean flatten = hidden || getSettings().isFlattenModules();
if (!flatten && !manager.hasModuleGroups() && !Registry.is("project.qualified.module.names")) flatten = true;
return new Group(newRoots.values(), hidden, flatten).createChildren(this, old);
return new Group(newRoots.values(), getSettings().isFlattenModules() || !hasModuleGroups(getProject())).createChildren(this, old);
}
@NotNull
@@ -666,13 +662,21 @@ public final class ScopeViewTreeModel extends BaseTreeModel<AbstractTreeNode> im
@Override
protected void update(PresentationData presentation) {
VirtualFile file = getVirtualFile();
String title = getTitle();
presentation.setPresentableText(title != null ? title : toString());
SimpleTextAttributes attributes = SimpleTextAttributes.REGULAR_ATTRIBUTES;
if (node.getRootID() instanceof VirtualFile) {
ProjectFileIndex index = getProjectFileIndex(getProject());
if (index != null && file.equals(index.getContentRootForFile(file))) {
attributes = SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES;
}
}
presentation.addText(title != null ? title : toString(), attributes);
Icon icon = getIcon();
if (icon == null && getVirtualFile().isValid()) {
icon = getVirtualFile().isDirectory()
if (icon == null && file.isValid()) {
icon = file.isDirectory()
? getFolderIcon(node, null)
: getVirtualFile().getFileType().getIcon();
: file.getFileType().getIcon();
}
presentation.setIcon(icon);
decorate(presentation);
@@ -956,38 +960,33 @@ public final class ScopeViewTreeModel extends BaseTreeModel<AbstractTreeNode> im
id = module;
}
Group(@NotNull Collection<RootNode> nodes, boolean hidden, boolean flatten) {
Group(@NotNull Collection<RootNode> nodes, boolean flatten) {
id = null;
if (!nodes.isEmpty()) {
if (hidden) {
roots.addAll(nodes);
}
else {
HashMap<Module, Group> map = new HashMap<>();
nodes.forEach(node -> {
Object id = node.node.getRootID();
if (id instanceof Module) {
Module module = (Module)id;
Group group = map.get(module);
if (group == null) {
group = new Group(module);
map.put(module, group);
}
group.roots.add(node);
HashMap<Module, Group> map = new HashMap<>();
nodes.forEach(node -> {
Object id = node.node.getRootID();
if (id instanceof Module) {
Module module = (Module)id;
Group group = map.get(module);
if (group == null) {
group = new Group(module);
map.put(module, group);
}
else {
roots.add(node);
}
});
if (flatten) {
groups.putAll(map);
group.roots.add(node);
}
else {
map.forEach((module, group) -> {
List<String> path = getModuleNameAsList(module, Registry.is("project.qualified.module.names"));
group.roots.forEach(node -> add(node, path, 0));
});
roots.add(node);
}
});
if (flatten) {
groups.putAll(map);
}
else {
map.forEach((module, group) -> {
List<String> path = getModuleNameAsList(module, Registry.is("project.qualified.module.names"));
group.roots.forEach(node -> add(node, path, 0));
});
}
}
}
@@ -1149,6 +1148,7 @@ public final class ScopeViewTreeModel extends BaseTreeModel<AbstractTreeNode> im
return index == null ? null : index.getModuleForFile(file);
}
@Nullable
private static String getPackageName(@Nullable PsiElement element) {
if (element instanceof PsiDirectory && element.isValid()) {
PsiDirectoryFactory factory = PsiDirectoryFactory.getInstance(element.getProject());
@@ -1160,6 +1160,12 @@ public final class ScopeViewTreeModel extends BaseTreeModel<AbstractTreeNode> im
return null;
}
private static boolean hasModuleGroups(@Nullable Project project) {
if (Registry.is("project.qualified.module.names")) return true;
ModuleManager manager = getModuleManager(project);
return manager != null && manager.hasModuleGroups();
}
@NotNull
private static List<String> getModuleNameAsList(@NotNull Module module, boolean split) {
String name = module.getName();
@@ -125,10 +125,13 @@ public abstract class ProjectFileListener {
@Nullable
public static AreaInstance findArea(@NotNull VirtualFile file, @Nullable Project project) {
if (project == null || project.isDisposed()) return null;
Module module = ProjectFileIndex.getInstance(project).getModuleForFile(file);
Module module = ProjectFileIndex.getInstance(project).getModuleForFile(file, false);
if (module != null) return module.isDisposed() ? null : module;
VirtualFile ancestor = project.getBaseDir();
// file does not belong to any content root, but it is located under the project directory
return ancestor == null || !isAncestor(ancestor, file, false) ? null : project;
if (ancestor == null || !isAncestor(ancestor, file, false)) return null;
PsiManager manager = PsiManager.getInstance(project);
PsiElement element = file.isDirectory() ? manager.findDirectory(file) : manager.findFile(file);
return element == null ? null : project; // ensure that the corresponding file can be shown
}
}
@@ -6,12 +6,12 @@ import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.vfs.VFileProperty;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileFilter;
import com.intellij.ui.tree.BaseTreeModel;
import com.intellij.ui.tree.TreeCollector;
import com.intellij.util.SmartList;
import com.intellij.util.ThreeState;
import com.intellij.util.concurrency.Invoker;
@@ -30,6 +30,7 @@ import java.util.function.Predicate;
import static com.intellij.openapi.vfs.VfsUtilCore.isAncestor;
import static com.intellij.ui.tree.TreePathUtil.pathToCustomNode;
import static com.intellij.ui.tree.project.ProjectFileListener.findArea;
import static java.util.Collections.emptyList;
public final class ProjectFileTreeModel extends BaseTreeModel<ProjectFileNode> implements InvokerSupplier {
@@ -120,10 +121,6 @@ public final class ProjectFileTreeModel extends BaseTreeModel<ProjectFileNode> i
return visible;
}
private static boolean isExpectedModule(@Nullable Module module, @NotNull VirtualFile file, @NotNull Project project) {
return file.isValid() && !project.isDisposed() && module == ProjectFileIndex.getInstance(project).getModuleForFile(file);
}
@NotNull
private static Module[] getModules(@NotNull Project project) {
ModuleManager manager = ModuleManager.getInstance(project);
@@ -145,6 +142,15 @@ public final class ProjectFileTreeModel extends BaseTreeModel<ProjectFileNode> i
});
}
public void setShowModules(boolean showModules) {
onValidThread(() -> {
if (root.showModules == showModules) return;
root.showModules = showModules;
root.valid = false; // need to reload content roots
pathChanged(null);
});
}
private void pathChanged(@Nullable TreePath path) {
onValidThread(() -> treeStructureChanged(path, null, null));
}
@@ -211,6 +217,7 @@ public final class ProjectFileTreeModel extends BaseTreeModel<ProjectFileNode> i
private static class ProjectNode extends Node<RootNode> {
volatile VirtualFileFilter filter;
volatile boolean showModules;
final Project project;
ProjectNode(@NotNull Project project) {
@@ -227,15 +234,27 @@ public final class ProjectFileTreeModel extends BaseTreeModel<ProjectFileNode> i
List<RootNode> getChildren(@NotNull List<RootNode> oldList) {
List<RootNode> list = new SmartList<>();
Mapper<RootNode> mapper = new Mapper<>(oldList, RootNode::new);
TreeCollector<VirtualFile> collector = showModules ? null : TreeCollector.createFileRootsCollector();
VirtualFile ancestor = project.getBaseDir();
if (ancestor != null && isExpectedModule(null, ancestor, project)) {
list.add(mapper.apply(ancestor, project));
if (ancestor != null && project == findArea(ancestor, project)) {
if (collector != null) {
collector.add(ancestor);
}
else {
list.add(mapper.apply(ancestor, project));
}
}
for (Module module: getModules(project)) {
for (VirtualFile file: getContentRoots(module)) {
list.add(mapper.apply(file, module));
if (collector != null) {
collector.add(file);
}
else {
list.add(mapper.apply(file, module));
}
}
}
if (collector != null) collector.get().forEach(file -> list.add(mapper.apply(file, file)));
// invalidate all changed file nodes without notifications
list.forEach(node -> node.invalidateNow(null));
return list;
@@ -276,6 +295,9 @@ public final class ProjectFileTreeModel extends BaseTreeModel<ProjectFileNode> i
VirtualFile file = getVirtualFile();
if (!file.isValid()) return emptyList();
ProjectNode parent = findParent(ProjectNode.class);
if (parent == null) return emptyList();
visibility = ThreeState.UNSURE;
VirtualFile[] children = file.getChildren();
@@ -288,20 +310,10 @@ public final class ProjectFileTreeModel extends BaseTreeModel<ProjectFileNode> i
continue; // ignore invalid symlink
}
Object id = getRootID();
if (id instanceof VirtualFile) {
AreaInstance area = findArea(child, parent.project);
if (area != null && (id instanceof VirtualFile || area.equals(id))) {
list.add(mapper.apply(child, id));
}
else if (id instanceof Project) {
if (isExpectedModule(null, child, (Project)id)) {
list.add(mapper.apply(child, id));
}
}
else if (id instanceof Module) {
Module module = (Module)id;
if (!module.isDisposed() && isExpectedModule(module, child, module.getProject())) {
list.add(mapper.apply(child, id));
}
}
}
return list;
}