don't search for custom engine if junit 5 is not on classpath
[idea/community.git] / plugins / devkit / src / inspections / quickfix / RegisterExtensionFix.java
1 /*
2  * Copyright 2000-2016 JetBrains s.r.o.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 package org.jetbrains.idea.devkit.inspections.quickfix;
17
18 import com.intellij.codeInsight.intention.IntentionAction;
19 import com.intellij.lang.LanguageExtensionPoint;
20 import com.intellij.openapi.application.Result;
21 import com.intellij.openapi.command.WriteCommandAction;
22 import com.intellij.openapi.editor.Editor;
23 import com.intellij.openapi.extensions.KeyedFactoryEPBean;
24 import com.intellij.openapi.fileTypes.FileTypeExtensionPoint;
25 import com.intellij.openapi.project.DumbService;
26 import com.intellij.openapi.project.Project;
27 import com.intellij.openapi.ui.popup.JBPopupFactory;
28 import com.intellij.openapi.ui.popup.PopupStep;
29 import com.intellij.openapi.ui.popup.util.BaseListPopupStep;
30 import com.intellij.openapi.util.ClassExtensionPoint;
31 import com.intellij.psi.PsiClass;
32 import com.intellij.psi.PsiElement;
33 import com.intellij.psi.PsiFile;
34 import com.intellij.psi.xml.XmlAttribute;
35 import com.intellij.psi.xml.XmlTag;
36 import com.intellij.util.Consumer;
37 import com.intellij.util.IncorrectOperationException;
38 import com.intellij.util.KeyedLazyInstanceEP;
39 import com.intellij.util.PsiNavigateUtil;
40 import com.intellij.util.containers.ContainerUtil;
41 import com.intellij.util.xml.DomFileElement;
42 import org.jetbrains.annotations.NotNull;
43 import org.jetbrains.idea.devkit.dom.Extension;
44 import org.jetbrains.idea.devkit.dom.Extensions;
45 import org.jetbrains.idea.devkit.dom.IdeaPlugin;
46 import org.jetbrains.idea.devkit.util.ExtensionPointCandidate;
47
48 import java.util.List;
49 import java.util.Map;
50
51 /**
52  * @author yole
53  */
54 public class RegisterExtensionFix implements IntentionAction {
55   private final PsiClass myExtensionClass;
56   private final List<ExtensionPointCandidate> myEPCandidates;
57
58   public RegisterExtensionFix(PsiClass extensionClass, List<ExtensionPointCandidate> epCandidates) {
59     myExtensionClass = extensionClass;
60     myEPCandidates = epCandidates;
61   }
62
63   @NotNull
64   @Override
65   public String getText() {
66     return "Register extension";
67   }
68
69   @NotNull
70   @Override
71   public String getFamilyName() {
72     return getText();
73   }
74
75   @Override
76   public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
77     return !DumbService.isDumb(project);
78   }
79
80   @Override
81   public void invoke(@NotNull Project project, final Editor editor, PsiFile file) throws IncorrectOperationException {
82     PluginDescriptorChooser.show(project, editor, file, element -> doFix(editor, element));
83   }
84
85   private void doFix(Editor editor, final DomFileElement<IdeaPlugin> element) {
86     if (myEPCandidates.size() == 1) {
87       registerExtension(element, myEPCandidates.get(0));
88     }
89     else {
90       final BaseListPopupStep<ExtensionPointCandidate> popupStep =
91         new BaseListPopupStep<ExtensionPointCandidate>("Choose Extension Point", myEPCandidates) {
92           @Override
93           public PopupStep onChosen(ExtensionPointCandidate selectedValue, boolean finalChoice) {
94             registerExtension(element, selectedValue);
95             return FINAL_CHOICE;
96           }
97         };
98       JBPopupFactory.getInstance().createListPopup(popupStep).showInBestPositionFor(editor);
99     }
100   }
101
102   private void registerExtension(final DomFileElement<IdeaPlugin> selectedValue, final ExtensionPointCandidate candidate) {
103     PsiElement navTarget = new WriteCommandAction<PsiElement>(selectedValue.getFile().getProject(), selectedValue.getFile()) {
104       @Override
105       protected void run(@NotNull Result<PsiElement> result) throws Throwable {
106         Extensions extensions = PluginDescriptorChooser.findOrCreateExtensionsForEP(selectedValue, candidate.epName);
107         Extension extension = extensions.addExtension(candidate.epName);
108         XmlTag tag = extension.getXmlTag();
109         PsiElement navTarget = null;
110         String keyAttrName = KEY_MAP.get(candidate.beanClassName);
111         if (keyAttrName != null) {
112           XmlAttribute attr = tag.setAttribute(keyAttrName, "");
113           navTarget = attr.getValueElement();
114         }
115         if (candidate.attributeName != null) {
116           tag.setAttribute(candidate.attributeName, myExtensionClass.getQualifiedName());
117         }
118         else {
119           XmlTag subTag = tag.createChildTag(candidate.tagName, null, myExtensionClass.getQualifiedName(), false);
120           tag.addSubTag(subTag, false);
121         }
122         result.setResult(navTarget != null ? navTarget : extension.getXmlTag());
123       }
124     }.execute().throwException().getResultObject();
125     PsiNavigateUtil.navigate(navTarget);
126   }
127
128   private static final Map<String, String> KEY_MAP = ContainerUtil.<String, String>immutableMapBuilder()
129     .put(KeyedFactoryEPBean.class.getName(), "key")
130     .put(KeyedLazyInstanceEP.class.getName(), "key")
131     .put(FileTypeExtensionPoint.class.getName(), "filetype")
132     .put(LanguageExtensionPoint.class.getName(), "language")
133     .put(ClassExtensionPoint.class.getName(), "forClass")
134     .build();
135
136
137   @Override
138   public boolean startInWriteAction() {
139     return false;
140   }
141 }