| /* |
| * 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.ide.util; |
| |
| import com.intellij.ide.IdeBundle; |
| import com.intellij.openapi.application.ApplicationManager; |
| import com.intellij.openapi.command.CommandProcessor; |
| import com.intellij.openapi.diagnostic.Logger; |
| import com.intellij.openapi.module.Module; |
| import com.intellij.openapi.module.ModuleUtil; |
| import com.intellij.openapi.project.Project; |
| import com.intellij.openapi.project.ProjectBundle; |
| import com.intellij.openapi.projectRoots.impl.ProjectRootUtil; |
| import com.intellij.openapi.roots.*; |
| import com.intellij.openapi.roots.ui.configuration.CommonContentEntriesEditor; |
| import com.intellij.openapi.roots.ui.configuration.ProjectSettingsService; |
| import com.intellij.openapi.ui.Messages; |
| import com.intellij.openapi.util.Computable; |
| import com.intellij.openapi.util.text.StringUtil; |
| import com.intellij.openapi.vfs.VirtualFile; |
| import com.intellij.psi.*; |
| import com.intellij.psi.search.GlobalSearchScope; |
| import com.intellij.util.ActionRunner; |
| import com.intellij.util.IncorrectOperationException; |
| import com.intellij.util.Query; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| import org.jetbrains.jps.model.java.JavaModuleSourceRootTypes; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| public class PackageUtil { |
| private static final Logger LOG = Logger.getInstance("com.intellij.ide.util.PackageUtil"); |
| |
| @Nullable |
| public static PsiDirectory findPossiblePackageDirectoryInModule(Module module, String packageName) { |
| return findPossiblePackageDirectoryInModule(module, packageName, true); |
| } |
| @Nullable |
| public static PsiDirectory findPossiblePackageDirectoryInModule(Module module, String packageName, boolean preferNonGeneratedRoots) { |
| final Project project = module.getProject(); |
| PsiDirectory psiDirectory = null; |
| if (!StringUtil.isEmptyOrSpaces(packageName)) { |
| PsiPackage rootPackage = findLongestExistingPackage(project, packageName); |
| if (rootPackage != null) { |
| final PsiDirectory[] psiDirectories = getPackageDirectoriesInModule(rootPackage, module); |
| if (psiDirectories.length > 0) { |
| psiDirectory = psiDirectories[0]; |
| |
| // If we prefer to find a non-generated PsiDirectory for the given package name, search through all |
| // the directories for the first dir not marked as generated and use that one instead |
| if (preferNonGeneratedRoots && psiDirectories.length > 1) { |
| for (PsiDirectory dir : psiDirectories) { |
| if (!GeneratedSourcesFilter.isGeneratedSourceByAnyFilter(dir.getVirtualFile(), project)) { |
| psiDirectory = dir; |
| break; |
| } |
| } |
| } |
| } |
| } |
| } |
| if (psiDirectory == null) { |
| if (checkSourceRootsConfigured(module)) { |
| final List<VirtualFile> sourceRoots = ModuleRootManager.getInstance(module).getSourceRoots(JavaModuleSourceRootTypes.SOURCES); |
| for (VirtualFile sourceRoot : sourceRoots) { |
| final PsiDirectory directory = PsiManager.getInstance(project).findDirectory(sourceRoot); |
| if (directory != null) { |
| psiDirectory = directory; |
| break; |
| } |
| } |
| } |
| } |
| return psiDirectory; |
| } |
| |
| /** |
| * @deprecated |
| */ |
| @Nullable |
| public static PsiDirectory findOrCreateDirectoryForPackage(Project project, |
| String packageName, |
| PsiDirectory baseDir, |
| boolean askUserToCreate) throws IncorrectOperationException { |
| return findOrCreateDirectoryForPackage(project, packageName, baseDir, askUserToCreate, false); |
| } |
| |
| /** |
| * @deprecated |
| */ |
| @Nullable |
| public static PsiDirectory findOrCreateDirectoryForPackage(Project project, |
| String packageName, |
| PsiDirectory baseDir, |
| boolean askUserToCreate, boolean filterSourceDirsForTestBaseDir) throws IncorrectOperationException { |
| |
| PsiDirectory psiDirectory = null; |
| |
| if (!"".equals(packageName)) { |
| PsiPackage rootPackage = findLongestExistingPackage(project, packageName); |
| if (rootPackage != null) { |
| int beginIndex = rootPackage.getQualifiedName().length() + 1; |
| packageName = beginIndex < packageName.length() ? packageName.substring(beginIndex) : ""; |
| String postfixToShow = packageName.replace('.', File.separatorChar); |
| if (packageName.length() > 0) { |
| postfixToShow = File.separatorChar + postfixToShow; |
| } |
| PsiDirectory[] directories = rootPackage.getDirectories(); |
| if (filterSourceDirsForTestBaseDir) { |
| directories = filterSourceDirectories(baseDir, project, directories); |
| } |
| psiDirectory = DirectoryChooserUtil.selectDirectory(project, directories, baseDir, postfixToShow); |
| if (psiDirectory == null) return null; |
| } |
| } |
| |
| if (psiDirectory == null) { |
| PsiDirectory[] sourceDirectories = ProjectRootUtil.getSourceRootDirectories(project); |
| psiDirectory = DirectoryChooserUtil.selectDirectory(project, sourceDirectories, baseDir, |
| File.separatorChar + packageName.replace('.', File.separatorChar)); |
| if (psiDirectory == null) return null; |
| } |
| |
| String restOfName = packageName; |
| boolean askedToCreate = false; |
| while (restOfName.length() > 0) { |
| final String name = getLeftPart(restOfName); |
| PsiDirectory foundExistingDirectory = psiDirectory.findSubdirectory(name); |
| if (foundExistingDirectory == null) { |
| if (!askedToCreate && askUserToCreate) { |
| int toCreate = Messages.showYesNoDialog(project, |
| IdeBundle.message("prompt.create.non.existing.package", packageName), |
| IdeBundle.message("title.package.not.found"), |
| Messages.getQuestionIcon()); |
| if (toCreate != Messages.YES) { |
| return null; |
| } |
| askedToCreate = true; |
| } |
| psiDirectory = createSubdirectory(psiDirectory, name, project); |
| } |
| else { |
| psiDirectory = foundExistingDirectory; |
| } |
| restOfName = cutLeftPart(restOfName); |
| } |
| return psiDirectory; |
| } |
| |
| private static PsiDirectory createSubdirectory(final PsiDirectory oldDirectory, |
| final String name, Project project) throws IncorrectOperationException { |
| final PsiDirectory[] psiDirectory = new PsiDirectory[1]; |
| final IncorrectOperationException[] exception = new IncorrectOperationException[1]; |
| |
| CommandProcessor.getInstance().executeCommand(project, new Runnable(){ |
| public void run() { |
| psiDirectory[0] = ApplicationManager.getApplication().runWriteAction(new Computable<PsiDirectory>() { |
| public PsiDirectory compute() { |
| try { |
| return oldDirectory.createSubdirectory(name); |
| } |
| catch (IncorrectOperationException e) { |
| exception[0] = e; |
| return null; |
| } |
| } |
| }); |
| } |
| }, IdeBundle.message("command.create.new.subdirectory"), null); |
| |
| if (exception[0] != null) throw exception[0]; |
| |
| return psiDirectory[0]; |
| } |
| |
| @Nullable |
| public static PsiDirectory findOrCreateDirectoryForPackage(@NotNull Module module, |
| String packageName, |
| @Nullable PsiDirectory baseDir, |
| boolean askUserToCreate) throws IncorrectOperationException { |
| return findOrCreateDirectoryForPackage(module, packageName, baseDir, askUserToCreate, false); |
| } |
| |
| @Nullable |
| public static PsiDirectory findOrCreateDirectoryForPackage(@NotNull Module module, |
| String packageName, |
| PsiDirectory baseDir, |
| boolean askUserToCreate, |
| boolean filterSourceDirsForBaseTestDirectory) throws IncorrectOperationException { |
| final Project project = module.getProject(); |
| PsiDirectory psiDirectory = null; |
| if (!packageName.isEmpty()) { |
| PsiPackage rootPackage = findLongestExistingPackage(module, packageName); |
| if (rootPackage != null) { |
| int beginIndex = rootPackage.getQualifiedName().length() + 1; |
| packageName = beginIndex < packageName.length() ? packageName.substring(beginIndex) : ""; |
| String postfixToShow = packageName.replace('.', File.separatorChar); |
| if (packageName.length() > 0) { |
| postfixToShow = File.separatorChar + postfixToShow; |
| } |
| PsiDirectory[] moduleDirectories = getPackageDirectoriesInModule(rootPackage, module); |
| if (filterSourceDirsForBaseTestDirectory) { |
| moduleDirectories = filterSourceDirectories(baseDir, project, moduleDirectories); |
| } |
| psiDirectory = DirectoryChooserUtil.selectDirectory(project, moduleDirectories, baseDir, postfixToShow); |
| if (psiDirectory == null) return null; |
| } |
| } |
| |
| if (psiDirectory == null) { |
| if (!checkSourceRootsConfigured(module, askUserToCreate)) return null; |
| final List<VirtualFile> sourceRoots = ModuleRootManager.getInstance(module).getSourceRoots(JavaModuleSourceRootTypes.SOURCES); |
| List<PsiDirectory> directoryList = new ArrayList<PsiDirectory>(); |
| for (VirtualFile sourceRoot : sourceRoots) { |
| final PsiDirectory directory = PsiManager.getInstance(project).findDirectory(sourceRoot); |
| if (directory != null) { |
| directoryList.add(directory); |
| } |
| } |
| PsiDirectory[] sourceDirectories = directoryList.toArray(new PsiDirectory[directoryList.size()]); |
| psiDirectory = DirectoryChooserUtil.selectDirectory(project, sourceDirectories, baseDir, |
| File.separatorChar + packageName.replace('.', File.separatorChar)); |
| if (psiDirectory == null) return null; |
| } |
| |
| String restOfName = packageName; |
| boolean askedToCreate = false; |
| while (restOfName.length() > 0) { |
| final String name = getLeftPart(restOfName); |
| PsiDirectory foundExistingDirectory = psiDirectory.findSubdirectory(name); |
| if (foundExistingDirectory == null) { |
| if (!askedToCreate && askUserToCreate) { |
| if (!ApplicationManager.getApplication().isUnitTestMode()) { |
| int toCreate = Messages.showYesNoDialog(project, |
| IdeBundle.message("prompt.create.non.existing.package", packageName), |
| IdeBundle.message("title.package.not.found"), |
| Messages.getQuestionIcon()); |
| if (toCreate != Messages.YES) { |
| return null; |
| } |
| } |
| askedToCreate = true; |
| } |
| |
| final PsiDirectory psiDirectory1 = psiDirectory; |
| try { |
| psiDirectory = ActionRunner.runInsideWriteAction(new ActionRunner.InterruptibleRunnableWithResult<PsiDirectory>() { |
| public PsiDirectory run() throws Exception { |
| return psiDirectory1.createSubdirectory(name); |
| } |
| }); |
| } |
| catch (IncorrectOperationException e) { |
| throw e; |
| } |
| catch (IOException e) { |
| throw new IncorrectOperationException(e); |
| } |
| catch (Exception e) { |
| LOG.error(e); |
| } |
| } |
| else { |
| psiDirectory = foundExistingDirectory; |
| } |
| restOfName = cutLeftPart(restOfName); |
| } |
| return psiDirectory; |
| } |
| |
| private static PsiDirectory[] filterSourceDirectories(PsiDirectory baseDir, Project project, PsiDirectory[] moduleDirectories) { |
| final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(project).getFileIndex(); |
| if (fileIndex.isInTestSourceContent(baseDir.getVirtualFile())) { |
| List<PsiDirectory> result = new ArrayList<PsiDirectory>(); |
| for (PsiDirectory moduleDirectory : moduleDirectories) { |
| if (fileIndex.isInTestSourceContent(moduleDirectory.getVirtualFile())) { |
| result.add(moduleDirectory); |
| } |
| } |
| moduleDirectories = result.toArray(new PsiDirectory[result.size()]); |
| } |
| return moduleDirectories; |
| } |
| |
| private static PsiDirectory[] getPackageDirectoriesInModule(PsiPackage rootPackage, Module module) { |
| return rootPackage.getDirectories(GlobalSearchScope.moduleScope(module)); |
| } |
| |
| private static PsiPackage findLongestExistingPackage(Project project, String packageName) { |
| PsiManager manager = PsiManager.getInstance(project); |
| String nameToMatch = packageName; |
| while (true) { |
| PsiPackage aPackage = JavaPsiFacade.getInstance(manager.getProject()).findPackage(nameToMatch); |
| if (aPackage != null && isWritablePackage(aPackage)) return aPackage; |
| int lastDotIndex = nameToMatch.lastIndexOf('.'); |
| if (lastDotIndex >= 0) { |
| nameToMatch = nameToMatch.substring(0, lastDotIndex); |
| } |
| else { |
| return null; |
| } |
| } |
| } |
| |
| private static boolean isWritablePackage(PsiPackage aPackage) { |
| PsiDirectory[] directories = aPackage.getDirectories(); |
| for (PsiDirectory directory : directories) { |
| if (directory.isValid() && directory.isWritable()) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| private static PsiDirectory getWritableModuleDirectory(@NotNull Query<VirtualFile> vFiles, @NotNull Module module, PsiManager manager) { |
| for (VirtualFile vFile : vFiles) { |
| if (ModuleUtil.findModuleForFile(vFile, module.getProject()) != module) continue; |
| PsiDirectory directory = manager.findDirectory(vFile); |
| if (directory != null && directory.isValid() && directory.isWritable()) { |
| return directory; |
| } |
| } |
| return null; |
| } |
| |
| private static PsiPackage findLongestExistingPackage(Module module, String packageName) { |
| final PsiManager manager = PsiManager.getInstance(module.getProject()); |
| |
| String nameToMatch = packageName; |
| while (true) { |
| Query<VirtualFile> vFiles = ModulePackageIndex.getInstance(module).getDirsByPackageName(nameToMatch, false); |
| PsiDirectory directory = getWritableModuleDirectory(vFiles, module, manager); |
| if (directory != null) return JavaDirectoryService.getInstance().getPackage(directory); |
| |
| int lastDotIndex = nameToMatch.lastIndexOf('.'); |
| if (lastDotIndex >= 0) { |
| nameToMatch = nameToMatch.substring(0, lastDotIndex); |
| } |
| else { |
| return null; |
| } |
| } |
| } |
| |
| private static String getLeftPart(String packageName) { |
| int index = packageName.indexOf('.'); |
| return index > -1 ? packageName.substring(0, index) : packageName; |
| } |
| |
| private static String cutLeftPart(String packageName) { |
| int index = packageName.indexOf('.'); |
| return index > -1 ? packageName.substring(index + 1) : ""; |
| } |
| |
| public static boolean checkSourceRootsConfigured(final Module module) { |
| return checkSourceRootsConfigured(module, true); |
| } |
| |
| public static boolean checkSourceRootsConfigured(final Module module, final boolean askUserToSetupSourceRoots) { |
| List<VirtualFile> sourceRoots = ModuleRootManager.getInstance(module).getSourceRoots(JavaModuleSourceRootTypes.SOURCES); |
| if (sourceRoots.isEmpty()) { |
| if (!askUserToSetupSourceRoots) { |
| return false; |
| } |
| |
| Project project = module.getProject(); |
| Messages.showErrorDialog(project, |
| ProjectBundle.message("module.source.roots.not.configured.error", module.getName()), |
| ProjectBundle.message("module.source.roots.not.configured.title")); |
| |
| ProjectSettingsService.getInstance(project).showModuleConfigurationDialog(module.getName(), CommonContentEntriesEditor.NAME); |
| |
| sourceRoots = ModuleRootManager.getInstance(module).getSourceRoots(JavaModuleSourceRootTypes.SOURCES); |
| if (sourceRoots.isEmpty()) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| @NotNull |
| public static PsiDirectory findOrCreateSubdirectory(@NotNull PsiDirectory directory, @NotNull String directoryName) { |
| PsiDirectory subDirectory = directory.findSubdirectory(directoryName); |
| if (subDirectory == null) { |
| subDirectory = directory.createSubdirectory(directoryName); |
| } |
| return subDirectory; |
| } |
| } |