mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
javafx: add single imports for unresolved tags
This commit is contained in:
+2
-2
@@ -32,9 +32,9 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ImportClassFix extends ImportClassFixBase<PsiJavaCodeReferenceElement> {
|
||||
public class ImportClassFix extends ImportClassFixBase<PsiJavaCodeReferenceElement, PsiJavaCodeReferenceElement> {
|
||||
public ImportClassFix(@NotNull PsiJavaCodeReferenceElement element) {
|
||||
super(element);
|
||||
super(element, element);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+34
-24
@@ -57,20 +57,22 @@ import java.util.regex.PatternSyntaxException;
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
public abstract class ImportClassFixBase<T extends PsiElement & PsiReference> implements HintAction, HighPriorityAction {
|
||||
private final T myRef;
|
||||
public abstract class ImportClassFixBase<T extends PsiElement, R extends PsiReference> implements HintAction, HighPriorityAction {
|
||||
private final T myElement;
|
||||
private final R myRef;
|
||||
|
||||
protected ImportClassFixBase(@NotNull T ref) {
|
||||
protected ImportClassFixBase(@NotNull T elem, R ref) {
|
||||
myElement = elem;
|
||||
myRef = ref;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiFile file) {
|
||||
if (!myRef.isValid()) {
|
||||
if (!myElement.isValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PsiElement parent = myRef.getParent();
|
||||
PsiElement parent = myElement.getParent();
|
||||
if (parent instanceof PsiNewExpression && ((PsiNewExpression)parent).getQualifier() != null) {
|
||||
return false;
|
||||
}
|
||||
@@ -80,15 +82,15 @@ public abstract class ImportClassFixBase<T extends PsiElement & PsiReference> im
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected abstract String getReferenceName(@NotNull T reference);
|
||||
protected abstract PsiElement getReferenceNameElement(@NotNull T reference);
|
||||
protected abstract boolean hasTypeParameters(@NotNull T reference);
|
||||
protected abstract String getReferenceName(@NotNull R reference);
|
||||
protected abstract PsiElement getReferenceNameElement(@NotNull R reference);
|
||||
protected abstract boolean hasTypeParameters(@NotNull R reference);
|
||||
|
||||
@NotNull
|
||||
public List<PsiClass> getClassesToImport() {
|
||||
PsiShortNamesCache cache = PsiShortNamesCache.getInstance(myRef.getProject());
|
||||
PsiShortNamesCache cache = PsiShortNamesCache.getInstance(myElement.getProject());
|
||||
String name = getReferenceName(myRef);
|
||||
GlobalSearchScope scope = myRef.getResolveScope();
|
||||
GlobalSearchScope scope = myElement.getResolveScope();
|
||||
if (name == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
@@ -96,7 +98,7 @@ public abstract class ImportClassFixBase<T extends PsiElement & PsiReference> im
|
||||
PsiClass[] classes = cache.getClassesByName(name, scope);
|
||||
if (classes.length == 0) return Collections.emptyList();
|
||||
List<PsiClass> classList = new ArrayList<PsiClass>(classes.length);
|
||||
boolean isAnnotationReference = myRef.getParent() instanceof PsiAnnotation;
|
||||
boolean isAnnotationReference = myElement.getParent() instanceof PsiAnnotation;
|
||||
for (PsiClass aClass : classes) {
|
||||
if (isAnnotationReference && !aClass.isAnnotationType()) continue;
|
||||
if (JavaCompletionUtil.isInExcludedPackage(aClass, false)) continue;
|
||||
@@ -105,26 +107,26 @@ public abstract class ImportClassFixBase<T extends PsiElement & PsiReference> im
|
||||
if (qName != null) { //filter local classes
|
||||
if (qName.indexOf('.') == -1) continue; //do not show classes from default package)
|
||||
if (qName.endsWith(name)) {
|
||||
if (isAccessible(aClass, myRef)) {
|
||||
if (isAccessible(aClass, myElement)) {
|
||||
classList.add(aClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final String memberName = getRequiredMemberName(myRef);
|
||||
final String memberName = getRequiredMemberName(myElement);
|
||||
if (memberName != null) {
|
||||
List<PsiClass> filtered = ContainerUtil.findAll(classList, new Condition<PsiClass>() {
|
||||
@Override
|
||||
public boolean value(PsiClass psiClass) {
|
||||
PsiField field = psiClass.findFieldByName(memberName, true);
|
||||
if (field != null && field.hasModifierProperty(PsiModifier.STATIC) && isAccessible(field, myRef)) return true;
|
||||
if (field != null && field.hasModifierProperty(PsiModifier.STATIC) && isAccessible(field, myElement)) return true;
|
||||
|
||||
PsiClass inner = psiClass.findInnerClassByName(memberName, true);
|
||||
if (inner != null && isAccessible(inner, myRef)) return true;
|
||||
if (inner != null && isAccessible(inner, myElement)) return true;
|
||||
|
||||
for (PsiMethod method : psiClass.findMethodsByName(memberName, true)) {
|
||||
if (method.hasModifierProperty(PsiModifier.STATIC) && isAccessible(method, myRef)) return true;
|
||||
if (method.hasModifierProperty(PsiModifier.STATIC) && isAccessible(method, myElement)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -134,7 +136,7 @@ public abstract class ImportClassFixBase<T extends PsiElement & PsiReference> im
|
||||
}
|
||||
}
|
||||
|
||||
List<PsiClass> filtered = filterByContext(classList, myRef);
|
||||
List<PsiClass> filtered = filterByContext(classList, myElement);
|
||||
if (!filtered.isEmpty()) {
|
||||
classList = filtered;
|
||||
}
|
||||
@@ -179,7 +181,7 @@ public abstract class ImportClassFixBase<T extends PsiElement & PsiReference> im
|
||||
if (classesToImport.isEmpty()) return Result.POPUP_NOT_SHOWN;
|
||||
|
||||
try {
|
||||
String name = getQualifiedName(myRef);
|
||||
String name = getQualifiedName(myElement);
|
||||
if (name != null) {
|
||||
Pattern pattern = Pattern.compile(DaemonCodeAnalyzerSettings.getInstance().NO_AUTO_IMPORT_PATTERN);
|
||||
Matcher matcher = pattern.matcher(name);
|
||||
@@ -191,12 +193,12 @@ public abstract class ImportClassFixBase<T extends PsiElement & PsiReference> im
|
||||
catch (PatternSyntaxException e) {
|
||||
//ignore
|
||||
}
|
||||
final PsiFile psiFile = myRef.getContainingFile();
|
||||
final PsiFile psiFile = myElement.getContainingFile();
|
||||
if (classesToImport.size() > 1) {
|
||||
reduceSuggestedClassesBasedOnDependencyRuleViolation(psiFile, classesToImport);
|
||||
}
|
||||
PsiClass[] classes = classesToImport.toArray(new PsiClass[classesToImport.size()]);
|
||||
final Project project = myRef.getProject();
|
||||
final Project project = myElement.getProject();
|
||||
CodeInsightUtil.sortIdenticalShortNameClasses(classes, myRef);
|
||||
|
||||
final QuestionAction action = createAddImportAction(classes, project, editor);
|
||||
@@ -226,14 +228,22 @@ public abstract class ImportClassFixBase<T extends PsiElement & PsiReference> im
|
||||
if (allowPopup && canImportHere) {
|
||||
String hintText = ShowAutoImportPass.getMessage(classes.length > 1, classes[0].getQualifiedName());
|
||||
if (!ApplicationManager.getApplication().isUnitTestMode() && !HintManager.getInstance().hasShownHintsThatWillHideByOtherHint(true)) {
|
||||
HintManager.getInstance().showQuestionHint(editor, hintText, myRef.getTextOffset(),
|
||||
myRef.getTextRange().getEndOffset(), action);
|
||||
HintManager.getInstance().showQuestionHint(editor, hintText, getStartOffset(myElement, myRef),
|
||||
getEndOffset(myElement, myRef), action);
|
||||
}
|
||||
return Result.POPUP_SHOWN;
|
||||
}
|
||||
return Result.POPUP_NOT_SHOWN;
|
||||
}
|
||||
|
||||
protected int getStartOffset(T element, R ref) {
|
||||
return element.getTextOffset();
|
||||
}
|
||||
|
||||
protected int getEndOffset(T element, R ref) {
|
||||
return element.getTextRange().getEndOffset();
|
||||
}
|
||||
|
||||
private static boolean autoImportWillInsertUnexpectedCharacters(PsiClass aClass) {
|
||||
PsiClass containingClass = aClass.getContainingClass();
|
||||
// when importing inner class, the reference might be qualified with outer class name and it can be confusing
|
||||
@@ -245,7 +255,7 @@ public abstract class ImportClassFixBase<T extends PsiElement & PsiReference> im
|
||||
!hasUnresolvedImportWhichCanImport(psiFile, exampleClassName);
|
||||
}
|
||||
|
||||
protected abstract boolean isQualified(T reference);
|
||||
protected abstract boolean isQualified(R reference);
|
||||
|
||||
@Override
|
||||
public boolean showHint(final Editor editor) {
|
||||
@@ -290,7 +300,7 @@ public abstract class ImportClassFixBase<T extends PsiElement & PsiReference> im
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isCaretNearRef(@NotNull Editor editor, @NotNull T ref) {
|
||||
private boolean isCaretNearRef(@NotNull Editor editor, @NotNull R ref) {
|
||||
PsiElement nameElement = getReferenceNameElement(ref);
|
||||
if (nameElement == null) return false;
|
||||
TextRange range = nameElement.getTextRange();
|
||||
|
||||
+2
-2
@@ -33,9 +33,9 @@ import java.util.List;
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
public class GroovyAddImportAction extends ImportClassFixBase<GrReferenceElement> {
|
||||
public class GroovyAddImportAction extends ImportClassFixBase<GrReferenceElement, GrReferenceElement> {
|
||||
public GroovyAddImportAction(GrReferenceElement ref) {
|
||||
super(ref);
|
||||
super(ref, ref);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -12,5 +12,6 @@
|
||||
<xml.schemaProvider implementation="org.jetbrains.plugins.javaFX.fxml.JavaFXSchemaHandler"/>
|
||||
<psi.referenceContributor implementation="org.jetbrains.plugins.javaFX.fxml.FxmlReferencesContributor"/>
|
||||
<codeInsight.unresolvedReferenceQuickFixProvider implementation="org.jetbrains.plugins.javaFX.fxml.JavaFxEventHandlerReference$JavaFxUnresolvedReferenceHandlerQuickfixProvider"/>
|
||||
<codeInsight.unresolvedReferenceQuickFixProvider implementation="org.jetbrains.plugins.javaFX.fxml.JavaFxTagNameReference$JavaFxUnresolvedTagRefsProvider"/>
|
||||
</extensions>
|
||||
</idea-plugin>
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright 2000-2013 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 org.jetbrains.plugins.javaFX.fxml;
|
||||
|
||||
import com.intellij.codeInsight.daemon.impl.quickfix.ImportClassFixBase;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiMember;
|
||||
import com.intellij.psi.xml.XmlTag;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* User: anna
|
||||
*/
|
||||
abstract class JavaFxImportClassFix extends ImportClassFixBase<XmlTag, JavaFxTagNameReference> {
|
||||
|
||||
public JavaFxImportClassFix(JavaFxTagNameReference ref, XmlTag element) {
|
||||
super(element, ref);
|
||||
}
|
||||
|
||||
protected abstract XmlTag getTagElement(JavaFxTagNameReference ref);
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected String getReferenceName(@NotNull JavaFxTagNameReference reference) {
|
||||
return getTagElement(reference).getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PsiElement getReferenceNameElement(@NotNull JavaFxTagNameReference reference) {
|
||||
return getTagElement(reference).getNavigationElement();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean hasTypeParameters(@NotNull JavaFxTagNameReference reference) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isAccessible(PsiMember member, XmlTag reference) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getQualifiedName(XmlTag tag) {
|
||||
return tag.getDescriptor().getQualifiedName();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isQualified(JavaFxTagNameReference reference) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean hasUnresolvedImportWhichCanImport(PsiFile psiFile, String name) {
|
||||
return false; //todo
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getStartOffset(XmlTag element, JavaFxTagNameReference ref) {
|
||||
return element.getTextOffset() + ref.getRangeInElement().getStartOffset();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getEndOffset(XmlTag element, JavaFxTagNameReference ref) {
|
||||
return element.getTextOffset() + ref.getRangeInElement().getEndOffset();
|
||||
}
|
||||
}
|
||||
@@ -2,14 +2,19 @@ package org.jetbrains.plugins.javaFX.fxml;
|
||||
|
||||
import com.intellij.codeInsight.completion.InsertionContext;
|
||||
import com.intellij.codeInsight.completion.XmlTagInsertHandler;
|
||||
import com.intellij.codeInsight.daemon.QuickFixActionRegistrar;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.codeInsight.lookup.LookupElementBuilder;
|
||||
import com.intellij.codeInsight.quickfix.UnresolvedReferenceQuickFixProvider;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.impl.source.PostprocessReformattingAspect;
|
||||
import com.intellij.psi.impl.source.xml.TagNameReference;
|
||||
import com.intellij.psi.xml.*;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.xml.XmlElementDescriptor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -21,11 +26,23 @@ import java.util.List;
|
||||
* User: anna
|
||||
* Date: 1/8/13
|
||||
*/
|
||||
public class JavaFxTagNameReference extends TagNameReference {
|
||||
public class JavaFxTagNameReference extends TagNameReference{
|
||||
public JavaFxTagNameReference(ASTNode element, boolean startTagFlag) {
|
||||
super(element, startTagFlag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiElement bindToElement(@NotNull PsiElement element) throws IncorrectOperationException {
|
||||
if (element instanceof PsiClass) {
|
||||
final String qualifiedName = ((PsiClass)element).getQualifiedName();
|
||||
if (qualifiedName != null) {
|
||||
insertImportWhenNeeded((XmlFile)getElement().getContainingFile(), StringUtil.getShortName(qualifiedName), qualifiedName);
|
||||
return getElement();
|
||||
}
|
||||
}
|
||||
return super.bindToElement(element);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public LookupElement[] getVariants() {
|
||||
@@ -45,6 +62,42 @@ public class JavaFxTagNameReference extends TagNameReference {
|
||||
return elements.toArray(new LookupElement[elements.size()]);
|
||||
}
|
||||
|
||||
private static void insertImportWhenNeeded(XmlFile xmlFile,
|
||||
String shortName,
|
||||
String qualifiedName) {
|
||||
if (shortName != null && JavaFxClassBackedElementDescriptor.findPsiClass(shortName, xmlFile.getRootTag()) == null) {
|
||||
final XmlDocument document = xmlFile.getDocument();
|
||||
if (document != null) {
|
||||
final XmlProcessingInstruction processingInstruction = JavaFxPsiUtil.createSingleImportInstruction(qualifiedName, xmlFile.getProject());
|
||||
final XmlProlog prolog = document.getProlog();
|
||||
if (prolog != null) {
|
||||
prolog.add(processingInstruction);
|
||||
} else {
|
||||
document.addBefore(processingInstruction, document.getRootTag());
|
||||
}
|
||||
PostprocessReformattingAspect.getInstance(xmlFile.getProject()).doPostponedFormatting(xmlFile.getViewProvider());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class JavaFxUnresolvedTagRefsProvider extends UnresolvedReferenceQuickFixProvider<JavaFxTagNameReference> {
|
||||
@Override
|
||||
public void registerFixes(JavaFxTagNameReference ref, QuickFixActionRegistrar registrar) {
|
||||
registrar.register(new JavaFxImportClassFix(ref, ref.getTagElement()) {
|
||||
@Override
|
||||
protected XmlTag getTagElement(JavaFxTagNameReference ref) {
|
||||
return ref.getTagElement();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Class<JavaFxTagNameReference> getReferenceClass() {
|
||||
return JavaFxTagNameReference.class;
|
||||
}
|
||||
}
|
||||
|
||||
private static class JavaFxTagInsertHandler extends XmlTagInsertHandler {
|
||||
public static final JavaFxTagInsertHandler INSTANCE = new JavaFxTagInsertHandler();
|
||||
|
||||
@@ -55,21 +108,8 @@ public class JavaFxTagNameReference extends TagNameReference {
|
||||
if (object instanceof JavaFxClassBackedElementDescriptor) {
|
||||
final XmlFile xmlFile = (XmlFile)context.getFile();
|
||||
final String shortName = ((JavaFxClassBackedElementDescriptor)object).getName();
|
||||
if (shortName != null && JavaFxClassBackedElementDescriptor.findPsiClass(shortName, xmlFile.getRootTag()) == null) {
|
||||
final XmlProcessingInstruction processingInstruction = JavaFxPsiUtil
|
||||
.createSingleImportInstruction(((JavaFxClassBackedElementDescriptor)object).getQualifiedName(), context.getProject());
|
||||
final XmlDocument document = xmlFile.getDocument();
|
||||
if (document != null) {
|
||||
final XmlProlog prolog = document.getProlog();
|
||||
if (prolog != null) {
|
||||
prolog.add(processingInstruction);
|
||||
} else {
|
||||
document.addBefore(processingInstruction, document.getRootTag());
|
||||
}
|
||||
context.commitDocument();
|
||||
PostprocessReformattingAspect.getInstance(context.getProject()).doPostponedFormatting(context.getFile().getViewProvider());
|
||||
}
|
||||
}
|
||||
insertImportWhenNeeded(xmlFile, shortName, ((JavaFxClassBackedElementDescriptor)object).getQualifiedName());
|
||||
context.commitDocument();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.scene.layout.*?>
|
||||
<GridPane xmlns:fx="http://javafx.com/fxml">
|
||||
<children>
|
||||
<But<caret>ton/>
|
||||
</children>
|
||||
</GridPane>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.scene.layout.*?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<GridPane xmlns:fx="http://javafx.com/fxml">
|
||||
<children>
|
||||
<Button/>
|
||||
</children>
|
||||
</GridPane>
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2000-2013 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 org.jetbrains.plugins.javaFX.fxml;
|
||||
|
||||
import com.intellij.codeInsight.daemon.DaemonAnalyzerTestCase;
|
||||
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
|
||||
import com.intellij.openapi.application.PluginPathManager;
|
||||
import com.intellij.testFramework.ExpectedHighlightingData;
|
||||
import com.intellij.testFramework.PsiTestUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class JavaFXImportTest extends DaemonAnalyzerTestCase {
|
||||
@Override
|
||||
protected void setUpModule() {
|
||||
super.setUpModule();
|
||||
PsiTestUtil.addLibrary(getModule(), "javafx", PluginPathManager.getPluginHomePath("javaFX") + "/testData", "jfxrt.jar");
|
||||
}
|
||||
|
||||
public void testSimpleImport() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
|
||||
private void doTest() throws Exception {
|
||||
configureByFiles(null, getTestName(true) + ".fxml");
|
||||
final List<HighlightInfo> infos = doHighlighting();
|
||||
findAndInvokeIntentionAction(infos, "Import Class", getEditor(), getFile());
|
||||
checkResultByFile(getTestName(true) + "_after.fxml");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected String getTestDataPath() {
|
||||
return PluginPathManager.getPluginHomePath("javaFX") + "/testData/importing/";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user