/* * Copyright 2000-2006 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 jetbrains.communicator.idea; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.Document; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.roots.ProjectFileIndex; import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; import jetbrains.communicator.core.vfs.VFile; import java.util.HashSet; import java.util.Set; /** * @author Kir * */ public class VFSUtil { private static Project[] ourProjects; private VFSUtil() { } public static VirtualFile getVirtualFile(final VFile file) { final VirtualFile [] result = new VirtualFile[1]; ApplicationManager.getApplication().runReadAction(() -> { result[0] = _getVirtualFile(file); }); return result[0]; } public static VFile createFileFrom(final VirtualFile file, final Project project) { final VFile []result = new VFile[1]; ApplicationManager.getApplication().runReadAction(() -> { result[0] = _createFileFrom(project, file); }); return result[0]; } private static VFile _createFileFrom(Project project, VirtualFile file) { VFile result = null; Document document = FileDocumentManager.getInstance().getDocument(file); Project[] openProjects = getOpenProjects(); for (int i = 0; i < openProjects.length && result == null; i++) { Project openProject = openProjects[i]; if (!openProject.isInitialized() && !ApplicationManager.getApplication().isUnitTestMode()) continue; if (document != null) { PsiFile psiFile = PsiDocumentManager.getInstance(openProject).getPsiFile(document); if (isJavaFile(psiFile)) { PsiJavaFile psiJavaFile = (PsiJavaFile) psiFile; assert psiJavaFile != null; final PsiClass[] classes = psiJavaFile.getClasses(); if (classes.length > 0) { result = createResultIfNeeded(result, file); result.setFQName(classes[0].getQualifiedName()); } } } ProjectFileIndex projectFileIndex = ProjectRootManager.getInstance(openProject).getFileIndex(); if (projectFileIndex.isInSource(file)) { VirtualFile sourceRoot = projectFileIndex.getSourceRootForFile(file); result = createResultIfNeeded(result, file); result.setSourcePath(getRelativePath(file, sourceRoot)); } if (projectFileIndex.isInContent(file)) { VirtualFile contentRoot = projectFileIndex.getContentRootForFile(file); result = createResultIfNeeded(result, file); result.setContentPath(getRelativePath(file, contentRoot)); } } if (result == null) { result = VFile.create(file.getPath(), null, file.isWritable()); } if (project != null) { result.setProjectName(project.getName()); } return result; } private static boolean isJavaFile(PsiFile psiFile) { if (psiFile instanceof PsiJavaFile) { PsiJavaFile file = (PsiJavaFile) psiFile; String name = file.getName(); return name != null && name.endsWith(".java"); } return false; } private static VFile createResultIfNeeded(VFile result, VirtualFile file) { if (result == null) { result = VFile.create(file.getPath(), file.isWritable()); } return result; } private static String getRelativePath(VirtualFile file, VirtualFile rootForFile) { if (file == null || rootForFile == null) return null; return file.getPath().substring(rootForFile.getPath().length()); } private static VirtualFile _getVirtualFile(VFile file) { VirtualFile resultFile = null; Project fileProject = getProjectByName(file.getProjectName()); if (fileProject != null) { resultFile = _getVirtualFile(fileProject, file); } if (resultFile == null) { resultFile = findFileInAllOpenProjects(fileProject, file); } return resultFile; } private static VirtualFile findFileInAllOpenProjects(Project fileProject, VFile file) { for (Project openProject : getOpenProjects()) { if (fileProject != openProject) { VirtualFile virtualFile = _getVirtualFile(openProject, file); if (virtualFile != null) { return virtualFile; } } } return null; } private static VirtualFile _getVirtualFile(Project project, VFile file) { VirtualFile result = findFileByFQName(file, project); if (result == null) { final Set<VirtualFile> candidates = new HashSet<>(); Module[] modules = ModuleManager.getInstance(project).getModules(); for (Module module : modules) { findFileInModule(candidates, module, file); } int currWeight = 0; for (VirtualFile candidate : candidates) { final int newWeight = weight(candidate, file); if (result == null || newWeight > currWeight) { currWeight = newWeight; result = candidate; } } } return result; } private static int weight(final VirtualFile candidate, final VFile file) { final String pattern = file.getFullPath().replace('\\', '/'); final String candidatePath = candidate.getPath(); int weight = 0; while( weight < pattern.length() && weight < candidatePath.length() && pattern.charAt(pattern.length() - weight - 1) == candidatePath.charAt(candidatePath.length() - weight - 1) ) weight ++; return weight; } private static VirtualFile findFileByFQName(VFile file, Project project) { VirtualFile result = null; if (file.getFQName() != null) { PsiClass aClass = JavaPsiFacade.getInstance(project).findClass(file.getFQName(), GlobalSearchScope.allScope(project)); if (aClass != null && isJavaFile(aClass.getNavigationElement().getContainingFile())) { result = aClass.getNavigationElement().getContainingFile().getVirtualFile(); } } return result; } private static void findFileInModule(final Set<VirtualFile> found, Module module, VFile file) { ModuleRootManager rootManager = ModuleRootManager.getInstance(module); findInRoots(found, rootManager.getSourceRoots(), file.getSourcePath()); findInRoots(found, rootManager.getContentRoots(), file.getContentPath()); } private static void findInRoots(final Set<VirtualFile> found, VirtualFile[] roots, String relativePath) { if (relativePath == null) return; for (VirtualFile root : roots) { String probeName; if (isArchive(root)) { probeName = root.getPath() + '!' + relativePath; } else { probeName = root.getPath() + relativePath; } VirtualFile virtualFile = root.getFileSystem().findFileByPath(probeName); if (virtualFile != null) { found.add(virtualFile); } } } public static boolean isArchive(VirtualFile sourceRoot) { return sourceRoot.getFileType() == getArchiveFileType(); } private static FileType getArchiveFileType() { FileType fileType = FileTypeManager.getInstance().getFileTypeByExtension(".zip"); if (fileType == FileTypeManager.getInstance().getFileTypeByExtension(".kokoko")) { fileType = FileTypeManager.getInstance().getFileTypeByExtension("zip"); } return fileType; } private static Project getProjectByName(String projectName) { if (projectName == null) return null; for (Project openProject : getOpenProjects()) { if (openProject.getName().equals(projectName)) { return openProject; } } return null; } private static Project[] getOpenProjects() { Project[] openProjects = ourProjects; if (openProjects == null) { openProjects = ProjectManager.getInstance().getOpenProjects(); } return openProjects; } public static void _setProject(Project project) { ourProjects = new Project[] {project}; } }