mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Javafx: Rename nested controller field along with the corresponding fx:id attribute or field (IDEA-153810)
This commit is contained in:
+13
@@ -190,6 +190,19 @@ public class JavaFXRenameTest extends AbstractJavaFXRenameTest {
|
||||
assertMethodExists(psiClass, "getNewName");
|
||||
}
|
||||
|
||||
public void testNestedControllerIdFromFxml() throws Exception {
|
||||
doTestHandler("newName", getTestName(false) + "Internal");
|
||||
myFixture.checkResultByFile(getTestName(false) + ".java", getTestName(false) + "_after.java", false);
|
||||
}
|
||||
|
||||
public void testNestedControllerIdFromJava() throws Exception {
|
||||
myFixture.configureByFiles(getTestName(false) + ".java", getTestName(false) + "Internal.java", getTestName(true) + ".fxml");
|
||||
final PsiElement elementAtCaret = myFixture.getElementAtCaret();
|
||||
new RenameProcessor(getProject(), elementAtCaret, "newName", false, false).run();
|
||||
myFixture.checkResultByFile(getTestName(true) + ".fxml", getTestName(true) + "_after.fxml", false);
|
||||
myFixture.checkResultByFile(getTestName(false) + ".java", getTestName(false) + "_after.java", false);
|
||||
}
|
||||
|
||||
public void testControllerStringProperty() throws Exception {
|
||||
doTestProperty("newName", false);
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
<codeInsight.lineMarkerProvider language="JAVA" implementationClass="org.jetbrains.plugins.javaFX.fxml.codeInsight.JavaFxRelatedItemLineMarkerProvider"/>
|
||||
<codeInsight.lineMarkerProvider language="Groovy" implementationClass="org.jetbrains.plugins.javaFX.fxml.codeInsight.JavaFxRelatedItemLineMarkerProvider"/>
|
||||
<useScopeEnlarger implementation="org.jetbrains.plugins.javaFX.fxml.refs.JavaFxScopeEnlarger"/>
|
||||
<renamePsiElementProcessor implementation="org.jetbrains.plugins.javaFX.refactoring.JavaFxRenameFxIdFieldProcessor" order="first"/>
|
||||
|
||||
<localInspection language="XML" shortName="JavaFxDefaultTag" displayName="Unnecessary default tag" groupName="JavaFX"
|
||||
enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.plugins.javaFX.fxml.codeInsight.inspections.JavaFxDefaultTagInspection"/>
|
||||
|
||||
+54
-7
@@ -6,14 +6,14 @@ import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.resolve.reference.impl.PsiMultiReference;
|
||||
import com.intellij.psi.util.PropertyUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.xml.XmlAttributeValue;
|
||||
import com.intellij.psi.xml.XmlFile;
|
||||
import com.intellij.psi.xml.XmlTag;
|
||||
import com.intellij.refactoring.RenameRefactoring;
|
||||
import com.intellij.refactoring.openapi.impl.JavaRenameRefactoringImpl;
|
||||
import com.intellij.refactoring.rename.PsiElementRenameHandler;
|
||||
@@ -25,8 +25,10 @@ import gnu.trove.THashMap;
|
||||
import gnu.trove.THashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.javaFX.fxml.FxmlConstants;
|
||||
import org.jetbrains.plugins.javaFX.fxml.JavaFxCommonNames;
|
||||
import org.jetbrains.plugins.javaFX.fxml.JavaFxFileTypeFactory;
|
||||
import org.jetbrains.plugins.javaFX.fxml.JavaFxPsiUtil;
|
||||
import org.jetbrains.plugins.javaFX.fxml.refs.JavaFxComponentIdReferenceProvider;
|
||||
import org.jetbrains.plugins.javaFX.fxml.refs.JavaFxFieldIdReferenceProvider;
|
||||
import org.jetbrains.plugins.javaFX.fxml.refs.JavaFxPropertyReference;
|
||||
@@ -87,23 +89,26 @@ public class JavaFxPropertyRenameHandler implements RenameHandler {
|
||||
}
|
||||
}
|
||||
if (reference instanceof JavaFxFieldIdReferenceProvider.JavaFxControllerFieldRef) {
|
||||
final XmlAttributeValue fxIdValueElement =
|
||||
((JavaFxFieldIdReferenceProvider.JavaFxControllerFieldRef)reference).getXmlAttributeValue();
|
||||
final Set<PsiElement> elementsToRename = new THashSet<>();
|
||||
JavaFxRenameAttributeProcessor.visitReferencedElements(references, psiElement -> {
|
||||
if (psiElement != null) {
|
||||
elementsToRename.add(psiElement);
|
||||
}
|
||||
});
|
||||
ContainerUtil.addIfNotNull(elementsToRename, getNestedControllerField(fxIdValueElement));
|
||||
|
||||
if (!canRename(project, editor, elementsToRename)) {
|
||||
return;
|
||||
}
|
||||
final XmlAttributeValue fxIdElement = ((JavaFxFieldIdReferenceProvider.JavaFxControllerFieldRef)reference).getXmlAttributeValue();
|
||||
if (ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
final String newName = PsiElementRenameHandler.DEFAULT_NAME.getData(dataContext);
|
||||
assert newName != null : "Rename property";
|
||||
new RenameDialog(project, fxIdElement, null, editor).performRename(newName);
|
||||
doRenameFxId(fxIdValueElement, newName, false, false);
|
||||
}
|
||||
else {
|
||||
new RenameDialog(project, fxIdElement, null, editor).show();
|
||||
new RenameFxIdDialog(fxIdValueElement, editor).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -180,6 +185,33 @@ public class JavaFxPropertyRenameHandler implements RenameHandler {
|
||||
if (key != null) map.put(key, value);
|
||||
}
|
||||
|
||||
public static void doRenameFxId(XmlAttributeValue fxIdValueElement, String newName, boolean searchInComments, boolean previewUsages) {
|
||||
final RenameRefactoring rename =
|
||||
new JavaRenameRefactoringImpl(fxIdValueElement.getProject(), fxIdValueElement, newName, searchInComments, false);
|
||||
rename.setPreviewUsages(previewUsages);
|
||||
|
||||
final PsiField nestedControllerField = getNestedControllerField(fxIdValueElement);
|
||||
if (nestedControllerField != null) {
|
||||
rename.addElement(nestedControllerField, newName + FxmlConstants.CONTROLLER_SUFFIX);
|
||||
}
|
||||
rename.run();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiField getNestedControllerField(@NotNull XmlAttributeValue fxIdValueElement) {
|
||||
final String fxId = fxIdValueElement.getValue();
|
||||
if (!StringUtil.isEmpty(fxId)) {
|
||||
final XmlTag tag = PsiTreeUtil.getParentOfType(fxIdValueElement, XmlTag.class);
|
||||
if (tag != null && FxmlConstants.FX_INCLUDE.equals(tag.getName())) {
|
||||
final PsiClass controllerClass = JavaFxPsiUtil.getControllerClass(tag.getContainingFile());
|
||||
if (controllerClass != null) {
|
||||
return controllerClass.findFieldByName(fxId + FxmlConstants.CONTROLLER_SUFFIX, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static class PropertyRenameDialog extends RenameDialog {
|
||||
|
||||
private final JavaFxPropertyReference myPropertyReference;
|
||||
@@ -199,4 +231,19 @@ public class JavaFxPropertyRenameHandler implements RenameHandler {
|
||||
close(DialogWrapper.OK_EXIT_CODE);
|
||||
}
|
||||
}
|
||||
|
||||
private static class RenameFxIdDialog extends RenameDialog {
|
||||
public RenameFxIdDialog(@NotNull XmlAttributeValue fxIdValueElement, Editor editor) {
|
||||
super(fxIdValueElement.getProject(), fxIdValueElement, null, editor);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doAction() {
|
||||
final String newName = getNewName();
|
||||
final PsiElement element = getPsiElement();
|
||||
assert element instanceof XmlAttributeValue;
|
||||
doRenameFxId(((XmlAttributeValue)element), newName, isSearchInComments(), isPreviewUsages());
|
||||
close(DialogWrapper.OK_EXIT_CODE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* 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.refactoring;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.SearchScope;
|
||||
import com.intellij.psi.xml.XmlTag;
|
||||
import com.intellij.refactoring.rename.RenamePsiElementProcessor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.javaFX.fxml.FxmlConstants;
|
||||
import org.jetbrains.plugins.javaFX.indexing.JavaFxControllerClassIndex;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Pavel.Dolgov
|
||||
*/
|
||||
public class JavaFxRenameFxIdFieldProcessor extends RenamePsiElementProcessor {
|
||||
@Override
|
||||
public boolean canProcessElement(@NotNull PsiElement element) {
|
||||
final NestedControllerCandidate nestedControllerCandidate = findNestedControllerCandidate(element);
|
||||
final Collection<PsiFile> fxmls = findFxmlWithController(nestedControllerCandidate);
|
||||
return !fxmls.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInplaceRenameSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepareRenaming(PsiElement element, String newName, Map<PsiElement, String> allRenames, SearchScope scope) {
|
||||
final NestedControllerCandidate nestedControllerCandidate = findNestedControllerCandidate(element);
|
||||
if (nestedControllerCandidate != null) {
|
||||
final Collection<PsiFile> fxmls = findFxmlWithController(nestedControllerCandidate);
|
||||
for (PsiFile fxml : fxmls) {
|
||||
final Ref<Boolean> found = new Ref<>(false);
|
||||
fxml.accept(new XmlRecursiveElementVisitor() {
|
||||
@Override
|
||||
public void visitXmlTag(XmlTag tag) {
|
||||
super.visitXmlTag(tag);
|
||||
if (found.get()) return;
|
||||
if (FxmlConstants.FX_INCLUDE.equals(tag.getName())) {
|
||||
final String value = tag.getAttributeValue(FxmlConstants.FX_ID);
|
||||
if (StringUtil.equals(nestedControllerCandidate.fxId, value)) {
|
||||
found.set(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
if (found.get()) {
|
||||
allRenames.put(nestedControllerCandidate.nestedControllerField, newName + FxmlConstants.CONTROLLER_SUFFIX);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static NestedControllerCandidate findNestedControllerCandidate(@NotNull PsiElement element) {
|
||||
if (element instanceof PsiField) {
|
||||
final PsiField field = (PsiField)element;
|
||||
final String fxId = field.getName();
|
||||
if (!StringUtil.isEmpty(fxId)) {
|
||||
final PsiClass containingClass = field.getContainingClass();
|
||||
if (containingClass != null) {
|
||||
final PsiField nestedControllerField = containingClass.findFieldByName(fxId + FxmlConstants.CONTROLLER_SUFFIX, true);
|
||||
if (nestedControllerField != null) {
|
||||
final PsiType psiType = nestedControllerField.getType();
|
||||
if (!(psiType instanceof PsiPrimitiveType) && !(psiType instanceof PsiArrayType)) { // optimization
|
||||
return new NestedControllerCandidate(fxId, nestedControllerField, containingClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Collection<PsiFile> findFxmlWithController(@Nullable NestedControllerCandidate nestedControllerCandidate) {
|
||||
if (nestedControllerCandidate != null) {
|
||||
final String qualifiedName = nestedControllerCandidate.controllerClass.getQualifiedName();
|
||||
if (qualifiedName != null) {
|
||||
final Project project = nestedControllerCandidate.controllerClass.getProject();
|
||||
return JavaFxControllerClassIndex.findFxmlWithController(project, qualifiedName);
|
||||
}
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private static class NestedControllerCandidate {
|
||||
private final String fxId;
|
||||
private final PsiField nestedControllerField;
|
||||
private final PsiClass controllerClass;
|
||||
|
||||
private NestedControllerCandidate(@NotNull String fxId, @NotNull PsiField nestedControllerField, @NotNull PsiClass controllerClass) {
|
||||
this.fxId = fxId;
|
||||
this.nestedControllerField = nestedControllerField;
|
||||
this.controllerClass = controllerClass;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import javafx.fxml.FXML;
|
||||
|
||||
class NestedControllerIdFromFxml {
|
||||
@FXML NestedControllerIdFromFxmlInternal internalController;
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
class NestedControllerIdFromFxmlInternal {
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import javafx.fxml.FXML;
|
||||
|
||||
class NestedControllerIdFromFxml {
|
||||
@FXML NestedControllerIdFromFxmlInternal newNameController;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.layout.VBox;
|
||||
|
||||
class NestedControllerIdFromJava {
|
||||
@FXML
|
||||
private VBox int<caret>ernal;
|
||||
@FXML NestedControllerIdFromJavaInternal internalController;
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
class NestedControllerIdFromJavaInternal {
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.layout.VBox;
|
||||
|
||||
class NestedControllerIdFromJava {
|
||||
@FXML
|
||||
private VBox newName;
|
||||
@FXML NestedControllerIdFromJavaInternal newNameController;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<VBox xmlns:fx="http://javafx.com/fxml" fx:controller="NestedControllerIdFromFxml">
|
||||
<fx:include fx:id="int<caret>ernal" source="nestedControllerIdFromFxmlInternal.fxml"/>
|
||||
</VBox>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<VBox xmlns:fx="http://javafx.com/fxml" fx:controller="NestedControllerIdFromFxmlInternal">
|
||||
<Button/>
|
||||
</VBox>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<VBox xmlns:fx="http://javafx.com/fxml" fx:controller="NestedControllerIdFromFxml">
|
||||
<fx:include fx:id="newName" source="nestedControllerIdFromFxmlInternal.fxml"/>
|
||||
</VBox>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<VBox xmlns:fx="http://javafx.com/fxml" fx:controller="NestedControllerIdFromJava">
|
||||
<fx:include fx:id="internal" source="nestedControllerIdFromJavaInternal.fxml"/>
|
||||
</VBox>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<VBox xmlns:fx="http://javafx.com/fxml" fx:controller="NestedControllerIdFromJavaInternal">
|
||||
<Button/>
|
||||
</VBox>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<VBox xmlns:fx="http://javafx.com/fxml" fx:controller="NestedControllerIdFromJava">
|
||||
<fx:include fx:id="newName" source="nestedControllerIdFromJavaInternal.fxml"/>
|
||||
</VBox>
|
||||
Reference in New Issue
Block a user