2 * Copyright 2000-2016 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package org.jetbrains.idea.devkit.inspections.quickfix;
19 import com.intellij.codeInspection.LocalQuickFix;
20 import com.intellij.codeInspection.ProblemDescriptor;
21 import com.intellij.icons.AllIcons;
22 import com.intellij.ide.fileTemplates.FileTemplate;
23 import com.intellij.ide.fileTemplates.FileTemplateManager;
24 import com.intellij.ide.fileTemplates.FileTemplateUtil;
25 import com.intellij.openapi.application.ApplicationManager;
26 import com.intellij.openapi.editor.Editor;
27 import com.intellij.openapi.fileEditor.FileEditorManager;
28 import com.intellij.openapi.module.Module;
29 import com.intellij.openapi.project.Project;
30 import com.intellij.openapi.roots.ModuleRootManager;
31 import com.intellij.openapi.ui.popup.JBPopup;
32 import com.intellij.openapi.ui.popup.JBPopupFactory;
33 import com.intellij.openapi.util.Iconable;
34 import com.intellij.openapi.vfs.VfsUtilCore;
35 import com.intellij.openapi.vfs.VirtualFile;
36 import com.intellij.psi.PsiDirectory;
37 import com.intellij.psi.PsiElement;
38 import com.intellij.psi.PsiFile;
39 import com.intellij.psi.PsiManager;
40 import com.intellij.ui.LayeredIcon;
41 import com.intellij.ui.components.JBList;
42 import com.intellij.util.ArrayUtil;
43 import one.util.streamex.StreamEx;
44 import org.jetbrains.annotations.NonNls;
45 import org.jetbrains.annotations.NotNull;
46 import org.jetbrains.idea.devkit.DevKitBundle;
47 import org.jetbrains.idea.devkit.inspections.DescriptionCheckerUtil;
48 import org.jetbrains.idea.devkit.inspections.DescriptionType;
49 import org.jetbrains.jps.model.java.JavaModuleSourceRootTypes;
50 import org.jetbrains.jps.model.java.JavaResourceRootType;
54 import java.util.Arrays;
55 import java.util.List;
58 * @author Konstantin Bulenkov
60 public class CreateHtmlDescriptionFix implements LocalQuickFix, Iconable {
63 private static final String TEMPLATE_NAME = "InspectionDescription.html";
65 private final String myFilename;
66 private final Module myModule;
67 private final DescriptionType myDescriptionType;
69 public CreateHtmlDescriptionFix(String filename, Module module, DescriptionType descriptionType) {
71 myDescriptionType = descriptionType;
72 myFilename = getNormalizedFileName(filename);
75 private boolean isFixedDescriptionFilename() {
76 return myDescriptionType.isFixedDescriptionFilename();
79 private static List<VirtualFile> getPotentialRoots(Module module, PsiDirectory[] dirs) {
80 if (dirs.length != 0) {
81 return StreamEx.of(dirs).map(PsiDirectory::getParentDirectory).nonNull().map(PsiDirectory::getVirtualFile).toList();
84 ModuleRootManager rootManager = ModuleRootManager.getInstance(module);
85 List<VirtualFile> resourceRoots = rootManager.getSourceRoots(JavaResourceRootType.RESOURCE);
86 if (!resourceRoots.isEmpty()) {
89 return rootManager.getSourceRoots(JavaModuleSourceRootTypes.SOURCES);
93 private String getNormalizedFileName(String filename) {
94 return myDescriptionType.isFixedDescriptionFilename() ? filename : filename + ".html";
98 public String getName() {
99 return DevKitBundle.message("create.description.file", getNewFileName());
103 public String getFamilyName() {
107 public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
108 final PsiDirectory[] dirs = getDirectories();
109 final List<VirtualFile> virtualFiles = getPotentialRoots(myModule, dirs);
110 final VirtualFile[] roots = prepare(VfsUtilCore.toVirtualFileArray(virtualFiles));
111 if (roots.length == 1) {
112 ApplicationManager.getApplication().runWriteAction(() -> createDescription(roots[0]));
115 List<String> options = StreamEx.of(roots).map(this::getPath).toList();
116 final JBList files = new JBList(ArrayUtil.toStringArray(options));
117 files.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
118 final JBPopup popup = JBPopupFactory.getInstance()
119 .createListPopupBuilder(files)
120 .setTitle(DevKitBundle.message("select.target.location.of.description", myFilename))
121 .setItemChoosenCallback(() -> {
122 final int index = files.getSelectedIndex();
123 if (0 <= index && index < roots.length) {
124 ApplicationManager.getApplication().runWriteAction(() -> createDescription(roots[index]));
127 final Editor editor = FileEditorManager.getInstance(myModule.getProject()).getSelectedTextEditor();
128 if (editor == null) return;
129 popup.showInBestPositionFor(editor);
133 private String getPath(VirtualFile file) {
134 String path = file.getPresentableUrl() + File.separator + getDescriptionFolderName() + File.separator + myFilename;
135 if (isFixedDescriptionFilename()) {
136 path += File.separator + "description.html";
141 private PsiDirectory[] getDirectories() {
142 return DescriptionCheckerUtil.getDescriptionsDirs(myModule, myDescriptionType);
145 private void createDescription(VirtualFile root) {
146 if (!root.isDirectory()) return;
147 final PsiManager psiManager = PsiManager.getInstance(myModule.getProject());
148 final PsiDirectory psiRoot = psiManager.findDirectory(root);
149 if (psiRoot == null) return;
150 PsiDirectory descrRoot =
151 StreamEx.of(psiRoot.getSubdirectories()).findFirst(dir -> getDescriptionFolderName().equals(dir.getName())).orElse(null);
154 descrRoot = descrRoot == null ? psiRoot.createSubdirectory(getDescriptionFolderName()) : descrRoot;
155 if (isFixedDescriptionFilename()) {
156 PsiDirectory dir = descrRoot.findSubdirectory(myFilename);
158 descrRoot = descrRoot.createSubdirectory(myFilename);
161 final FileTemplate descrTemplate = FileTemplateManager.getInstance(myModule.getProject()).getJ2eeTemplate(TEMPLATE_NAME);
162 final PsiElement template =
163 FileTemplateUtil.createFromTemplate(descrTemplate, getNewFileName(), null, descrRoot);
164 if (template instanceof PsiFile) {
165 final VirtualFile file = ((PsiFile)template).getVirtualFile();
167 FileEditorManager.getInstance(myModule.getProject()).openFile(file, true);
171 catch (Exception e) {//
175 private String getNewFileName() {
176 return isFixedDescriptionFilename() ? "description.html" : myFilename;
179 public Icon getIcon(int flags) {
180 return new LayeredIcon(AllIcons.FileTypes.Html, AllIcons.Actions.New);
183 private VirtualFile[] prepare(VirtualFile[] roots) {
184 VirtualFile[] found = Arrays.stream(roots).filter(this::containsDescriptionDir).toArray(VirtualFile[]::new);
185 return found.length > 0 ? found : roots;
188 private boolean containsDescriptionDir(VirtualFile root) {
189 if (!root.isDirectory()) return false;
190 return Arrays.stream(root.getChildren()).anyMatch(file -> file.isDirectory() && getDescriptionFolderName().equals(file.getName()));
193 private String getDescriptionFolderName() {
194 return myDescriptionType.getDescriptionFolder();