blob: 55f2f41f57c7ca3c973f16179d1650eb416c75f4 [file] [log] [blame]
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.xml.config;
import com.intellij.ide.presentation.VirtualFilePresentation;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleType;
import com.intellij.openapi.vfs.JarFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.intellij.ui.ColoredTreeCellRenderer;
import com.intellij.ui.SimpleTextAttributes;
import com.intellij.ui.TreeSpeedSearch;
import com.intellij.util.containers.Convertor;
import com.intellij.util.containers.MultiMap;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import java.util.*;
public class ConfigFilesTreeBuilder {
private final JTree myTree;
public ConfigFilesTreeBuilder(JTree tree) {
myTree = tree;
installSearch(tree);
}
public Set<PsiFile> buildTree(DefaultMutableTreeNode root, ConfigFileSearcher... searchers) {
final Set<PsiFile> psiFiles = new com.intellij.util.containers.HashSet<PsiFile>();
final MultiMap<Module, PsiFile> files = new MultiMap<Module, PsiFile>();
final MultiMap<VirtualFile, PsiFile> jars = new MultiMap<VirtualFile, PsiFile>();
final MultiMap<VirtualFile, PsiFile> virtualFiles = new MultiMap<VirtualFile, PsiFile>();
for (ConfigFileSearcher searcher : searchers) {
files.putAllValues(searcher.getFilesByModules());
jars.putAllValues(searcher.getJars());
virtualFiles.putAllValues(searcher.getVirtualFiles());
}
psiFiles.addAll(buildModuleNodes(files, jars, root));
for (Map.Entry<VirtualFile, Collection<PsiFile>> entry : virtualFiles.entrySet()) {
DefaultMutableTreeNode node = createFileNode(entry.getKey());
List<PsiFile> list = new ArrayList<PsiFile>(entry.getValue());
Collections.sort(list, FILE_COMPARATOR);
for (PsiFile file : list) {
node.add(createFileNode(file));
}
root.add(node);
}
return psiFiles;
}
public DefaultMutableTreeNode addFile(VirtualFile file) {
final DefaultMutableTreeNode root = (DefaultMutableTreeNode)myTree.getModel().getRoot();
final DefaultMutableTreeNode treeNode = createFileNode(file);
root.add(treeNode);
DefaultTreeModel model = (DefaultTreeModel)myTree.getModel();
model.nodeStructureChanged(root);
return treeNode;
}
public Set<PsiFile> buildModuleNodes(final MultiMap<Module, PsiFile> files,
final MultiMap<VirtualFile, PsiFile> jars,
DefaultMutableTreeNode root) {
final HashSet<PsiFile> psiFiles = new HashSet<PsiFile>();
final List<Module> modules = new ArrayList<Module>(files.keySet());
Collections.sort(modules, new Comparator<Module>() {
@Override
public int compare(final Module o1, final Module o2) {
return o1.getName().compareTo(o2.getName());
}
});
for (Module module : modules) {
DefaultMutableTreeNode moduleNode = createFileNode(module);
root.add(moduleNode);
if (files.containsKey(module)) {
List<PsiFile> moduleFiles = new ArrayList<PsiFile>(files.get(module));
MultiMap<FileType, PsiFile> filesByType = new MultiMap<FileType, PsiFile>();
for (PsiFile file : moduleFiles) {
filesByType.putValue(file.getFileType(), file);
}
if (hasNonEmptyGroups(filesByType)) {
for (Map.Entry<FileType, Collection<PsiFile>> entry : filesByType.entrySet()) {
DefaultMutableTreeNode fileTypeNode = createFileNode(entry.getKey());
moduleNode.add(fileTypeNode);
addChildrenFiles(psiFiles, fileTypeNode, new ArrayList<PsiFile>(entry.getValue()));
}
} else {
addChildrenFiles(psiFiles, moduleNode, moduleFiles);
}
}
}
for (VirtualFile file : jars.keySet()) {
final List<PsiFile> list = new ArrayList<PsiFile>(jars.get(file));
final PsiFile jar = list.get(0).getManager().findFile(file);
if (jar != null) {
final DefaultMutableTreeNode jarNode = createFileNode(jar);
root.add(jarNode);
Collections.sort(list, FILE_COMPARATOR);
for (PsiFile psiFile : list) {
jarNode.add(createFileNode(psiFile));
psiFiles.add(psiFile);
}
}
}
return psiFiles;
}
private static String getFileTypeNodeName(FileType fileType) {
return fileType.getName() + " context files" ;
}
private boolean hasNonEmptyGroups(MultiMap<FileType, PsiFile> filesByType) {
byte nonEmptyGroups = 0;
for (Map.Entry<FileType, Collection<PsiFile>> entry : filesByType.entrySet()) {
Collection<PsiFile> files = entry.getValue();
if (files != null && files.size() > 0) nonEmptyGroups++;
}
return nonEmptyGroups > 1;
}
private void addChildrenFiles(@NotNull Set<PsiFile> psiFiles, DefaultMutableTreeNode parentNode, @NotNull List<PsiFile> moduleFiles) {
Collections.sort(moduleFiles, FILE_COMPARATOR);
for (PsiFile file : moduleFiles) {
final DefaultMutableTreeNode fileNode = createFileNode(file);
parentNode.add(fileNode);
psiFiles.add(file);
}
}
protected DefaultMutableTreeNode createFileNode(Object file) {
return new DefaultMutableTreeNode(file);
}
private static final Comparator<PsiFile> FILE_COMPARATOR = new Comparator<PsiFile>() {
@Override
public int compare(final PsiFile o1, final PsiFile o2) {
return o1.getName().compareTo(o2.getName());
}
};
public static void renderNode(Object value, boolean expanded, ColoredTreeCellRenderer renderer) {
if (!(value instanceof DefaultMutableTreeNode)) return;
final Object object = ((DefaultMutableTreeNode)value).getUserObject();
if (object instanceof FileType) {
final FileType fileType = (FileType)object;
final Icon icon = fileType.getIcon();
renderer.setIcon(icon);
renderer.append(getFileTypeNodeName(fileType), SimpleTextAttributes.REGULAR_ATTRIBUTES);
}
else if (object instanceof Module) {
final Module module = (Module)object;
final Icon icon = ModuleType.get(module).getIcon();
renderer.setIcon(icon);
final String moduleName = module.getName();
renderer.append(moduleName, SimpleTextAttributes.REGULAR_ATTRIBUTES);
}
else if (object instanceof PsiFile) {
final PsiFile psiFile = (PsiFile)object;
final Icon icon = psiFile.getIcon(0);
renderer.setIcon(icon);
final String fileName = psiFile.getName();
renderer.append(fileName, SimpleTextAttributes.REGULAR_ATTRIBUTES);
final VirtualFile virtualFile = psiFile.getVirtualFile();
if (virtualFile != null) {
String path = virtualFile.getPath();
final int i = path.indexOf(JarFileSystem.JAR_SEPARATOR);
if (i >= 0) {
path = path.substring(i + JarFileSystem.JAR_SEPARATOR.length());
}
renderer.append(" (" + path + ")", SimpleTextAttributes.GRAYED_ATTRIBUTES);
}
}
else if (object instanceof VirtualFile) {
VirtualFile file = (VirtualFile)object;
renderer.setIcon(VirtualFilePresentation.getIcon(file));
renderer.append(file.getName(), SimpleTextAttributes.REGULAR_ATTRIBUTES);
String path = file.getPath();
final int i = path.indexOf(JarFileSystem.JAR_SEPARATOR);
if (i >= 0) {
path = path.substring(i + JarFileSystem.JAR_SEPARATOR.length());
}
renderer.append(" (" + path + ")", SimpleTextAttributes.GRAYED_ATTRIBUTES);
}
}
public static void installSearch(JTree tree) {
new TreeSpeedSearch(tree, new Convertor<TreePath, String>() {
@Override
public String convert(final TreePath treePath) {
final Object object = ((DefaultMutableTreeNode)treePath.getLastPathComponent()).getUserObject();
if (object instanceof Module) {
return ((Module)object).getName();
}
else if (object instanceof PsiFile) {
return ((PsiFile)object).getName();
}
else if (object instanceof VirtualFile) {
return ((VirtualFile)object).getName();
}
else {
return "";
}
}
});
}
}