From 5706a80f780da22880cd884204012c15cfcf51db Mon Sep 17 00:00:00 2001 From: Pavel Dolgov Date: Mon, 17 Oct 2016 14:34:02 +0300 Subject: [PATCH] Javafx: "Wrap field with JavaFx property" intention (IDEA-102430) --- plugins/javaFX/javaFX-CE/javaFX-CE.iml | 2 + .../JavaFxFieldToPropertyNoArtifactTest.java | 34 ++ .../javaFX/JavaFxFieldToPropertyTest.java | 89 ++++ plugins/javaFX/javaFX.iml | 1 + .../after.java.template | 11 + .../before.java.template | 8 + .../description.html | 5 + .../src/META-INF/common-javaFX-plugin.xml | 6 + .../JavaFxFieldToPropertyIntention.java | 422 ++++++++++++++++++ .../javaFX/fxml/JavaFxCommonNames.java | 13 + .../javaFX/fxml/JavaFxFileTypeFactory.java | 13 +- .../plugins/javaFX/fxml/JavaFxModuleUtil.java | 100 +++++ .../plugins/javaFX/fxml/JavaFxPsiUtil.java | 22 + .../BigDecimalFieldToProperty.java | 17 + .../BigDecimalFieldToProperty_after.java | 19 + .../BoxedFloatFieldToProperty.java | 49 ++ .../BoxedFloatFieldToProperty_after.java | 50 +++ .../fieldToProperty/IntFieldToProperty.java | 59 +++ .../IntFieldToProperty_after.java | 60 +++ .../fieldToProperty/ListFieldToProperty.java | 23 + .../ListFieldToProperty_after.java | 26 ++ .../fieldToProperty/LongFieldToProperty.java | 47 ++ .../LongFieldToProperty_after.java | 49 ++ .../StringFieldToProperty.java | 17 + .../StringFieldToProperty_after.java | 18 + .../intentions/fieldToProperty/sample.fxml | 6 + 26 files changed, 1164 insertions(+), 2 deletions(-) create mode 100644 plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/JavaFxFieldToPropertyNoArtifactTest.java create mode 100644 plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/JavaFxFieldToPropertyTest.java create mode 100644 plugins/javaFX/resources/intentionDescriptions/JavaFxFieldToPropertyIntention/after.java.template create mode 100644 plugins/javaFX/resources/intentionDescriptions/JavaFxFieldToPropertyIntention/before.java.template create mode 100644 plugins/javaFX/resources/intentionDescriptions/JavaFxFieldToPropertyIntention/description.html create mode 100644 plugins/javaFX/src/org/jetbrains/plugins/javaFX/codeInsight/JavaFxFieldToPropertyIntention.java create mode 100644 plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/JavaFxModuleUtil.java create mode 100644 plugins/javaFX/testData/intentions/fieldToProperty/BigDecimalFieldToProperty.java create mode 100644 plugins/javaFX/testData/intentions/fieldToProperty/BigDecimalFieldToProperty_after.java create mode 100644 plugins/javaFX/testData/intentions/fieldToProperty/BoxedFloatFieldToProperty.java create mode 100644 plugins/javaFX/testData/intentions/fieldToProperty/BoxedFloatFieldToProperty_after.java create mode 100644 plugins/javaFX/testData/intentions/fieldToProperty/IntFieldToProperty.java create mode 100644 plugins/javaFX/testData/intentions/fieldToProperty/IntFieldToProperty_after.java create mode 100644 plugins/javaFX/testData/intentions/fieldToProperty/ListFieldToProperty.java create mode 100644 plugins/javaFX/testData/intentions/fieldToProperty/ListFieldToProperty_after.java create mode 100644 plugins/javaFX/testData/intentions/fieldToProperty/LongFieldToProperty.java create mode 100644 plugins/javaFX/testData/intentions/fieldToProperty/LongFieldToProperty_after.java create mode 100644 plugins/javaFX/testData/intentions/fieldToProperty/StringFieldToProperty.java create mode 100644 plugins/javaFX/testData/intentions/fieldToProperty/StringFieldToProperty_after.java create mode 100644 plugins/javaFX/testData/intentions/fieldToProperty/sample.fxml diff --git a/plugins/javaFX/javaFX-CE/javaFX-CE.iml b/plugins/javaFX/javaFX-CE/javaFX-CE.iml index 7eedf1ef09d1..c09b13097680 100644 --- a/plugins/javaFX/javaFX-CE/javaFX-CE.iml +++ b/plugins/javaFX/javaFX-CE/javaFX-CE.iml @@ -15,5 +15,7 @@ + + \ No newline at end of file diff --git a/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/JavaFxFieldToPropertyNoArtifactTest.java b/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/JavaFxFieldToPropertyNoArtifactTest.java new file mode 100644 index 000000000000..f1fe6fb52ad3 --- /dev/null +++ b/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/JavaFxFieldToPropertyNoArtifactTest.java @@ -0,0 +1,34 @@ +package org.jetbrains.plugins.javaFX; + +import com.intellij.codeInsight.intention.IntentionAction; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.roots.ContentEntry; +import com.intellij.openapi.roots.ModifiableRootModel; +import com.intellij.testFramework.fixtures.DefaultLightProjectDescriptor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.javaFX.fxml.AbstractJavaFXTestCase; + +/** + * Same as the base test, but detects the presence of JavaFX using imports and FXMLs, not artifacts + * @author Pavel.Dolgov + */ +public class JavaFxFieldToPropertyNoArtifactTest extends JavaFxFieldToPropertyTest { + public static final DefaultLightProjectDescriptor JAVA_FX_DESCRIPTOR_NO_ARTIFACT = new DefaultLightProjectDescriptor() { + @Override + public void configureModule(@NotNull Module module, @NotNull ModifiableRootModel model, @NotNull ContentEntry contentEntry) { + AbstractJavaFXTestCase.addJavaFxJarAsLibrary(module, model); + super.configureModule(module, model, contentEntry); + } + }; + + @Override + protected void setUpModule() { + super.setUpModule(); + } + + public void testLongFieldToProperty() throws Exception { + final IntentionAction intentionAction = getIntentionAction(false); + // no artifact, no fxml, no javafx.* imports: the intention shoudn't be available + assertNull(intentionAction); + } +} diff --git a/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/JavaFxFieldToPropertyTest.java b/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/JavaFxFieldToPropertyTest.java new file mode 100644 index 000000000000..93474254c727 --- /dev/null +++ b/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/JavaFxFieldToPropertyTest.java @@ -0,0 +1,89 @@ +package org.jetbrains.plugins.javaFX; + +import com.intellij.codeInsight.daemon.DaemonAnalyzerTestCase; +import com.intellij.codeInsight.daemon.impl.HighlightInfo; +import com.intellij.codeInsight.intention.IntentionAction; +import com.intellij.codeInsight.intention.impl.ShowIntentionActionsHandler; +import com.intellij.openapi.application.PluginPathManager; +import com.intellij.openapi.editor.Editor; +import com.intellij.packaging.artifacts.ArtifactManager; +import com.intellij.psi.PsiFile; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.javaFX.fxml.AbstractJavaFXTestCase; +import org.jetbrains.plugins.javaFX.packaging.JavaFxApplicationArtifactType; + +import java.util.List; + +/** + * @author Pavel.Dolgov + * Run this test with 'main_idea_tests' classpath + */ +public class JavaFxFieldToPropertyTest extends DaemonAnalyzerTestCase { + private static final String actionName = "Convert to JavaFX property"; + + @Override + protected void setUpModule() { + super.setUpModule(); + AbstractJavaFXTestCase.addJavaFxJarAsLibrary(getModule()); + ArtifactManager.getInstance(getProject()).addArtifact("fake-javafx", JavaFxApplicationArtifactType.getInstance(), null); + } + + public void testIntFieldToProperty() throws Exception { + doTest(); + } + + public void testBoxedFloatFieldToProperty() throws Exception { + doTest(); + } + + public void testStringFieldToProperty() throws Exception { + doTest(); + } + + public void testListFieldToProperty() throws Exception { + doTest(); + } + + public void testBigDecimalFieldToProperty() throws Exception { + doTest(true); + } + + public void testLongFieldToProperty() throws Exception { + doTest(); + } + + private void doTest() throws Exception { + doTest(false); + } + + private void doTest(boolean withFxml) throws Exception { + final IntentionAction intentionAction = getIntentionAction(withFxml); + assertNotNull(intentionAction); + + Editor editor = getEditor(); + PsiFile file = getFile(); + + assertTrue(ShowIntentionActionsHandler.chooseActionAndInvoke(file, editor, intentionAction,actionName)); + checkResultByFile(getTestName(false) + "_after.java"); + } + + protected IntentionAction getIntentionAction(boolean withFxml) throws Exception { + if (withFxml) { + configureByFiles(null, getTestName(false) + ".java", "sample.fxml"); + } + else { + configureByFiles(null, getTestName(false) + ".java"); + } + final List infos = doHighlighting(); + final Editor editor = getEditor(); + final PsiFile file = getFile(); + return findIntentionAction(infos, actionName, editor, file); + } + + @NotNull + @Override + protected String getTestDataPath() { + return PluginPathManager.getPluginHomePath("javaFX") + "/testData/intentions/fieldToProperty/"; + } + +} diff --git a/plugins/javaFX/javaFX.iml b/plugins/javaFX/javaFX.iml index 0936ae44f5a0..ad4ea7ec5e0e 100644 --- a/plugins/javaFX/javaFX.iml +++ b/plugins/javaFX/javaFX.iml @@ -27,5 +27,6 @@ + \ No newline at end of file diff --git a/plugins/javaFX/resources/intentionDescriptions/JavaFxFieldToPropertyIntention/after.java.template b/plugins/javaFX/resources/intentionDescriptions/JavaFxFieldToPropertyIntention/after.java.template new file mode 100644 index 000000000000..1eff96d39f39 --- /dev/null +++ b/plugins/javaFX/resources/intentionDescriptions/JavaFxFieldToPropertyIntention/after.java.template @@ -0,0 +1,11 @@ +ObservableIntegerValue number; + +int getNumber() { + return number.get(); +} +void setNumber(int newNumber) { + number.set(newNumber); +} +ObservableIntegerValue number() { + return number; +} \ No newline at end of file diff --git a/plugins/javaFX/resources/intentionDescriptions/JavaFxFieldToPropertyIntention/before.java.template b/plugins/javaFX/resources/intentionDescriptions/JavaFxFieldToPropertyIntention/before.java.template new file mode 100644 index 000000000000..557a869c7fb4 --- /dev/null +++ b/plugins/javaFX/resources/intentionDescriptions/JavaFxFieldToPropertyIntention/before.java.template @@ -0,0 +1,8 @@ +int number; + +int getNumber() { + return number; +} +void setNumber(int newNumber) { + number = newNumber; +} \ No newline at end of file diff --git a/plugins/javaFX/resources/intentionDescriptions/JavaFxFieldToPropertyIntention/description.html b/plugins/javaFX/resources/intentionDescriptions/JavaFxFieldToPropertyIntention/description.html new file mode 100644 index 000000000000..1e2bf5ba849c --- /dev/null +++ b/plugins/javaFX/resources/intentionDescriptions/JavaFxFieldToPropertyIntention/description.html @@ -0,0 +1,5 @@ + + +This intention converts a field into JavaFX property. + + \ No newline at end of file diff --git a/plugins/javaFX/src/META-INF/common-javaFX-plugin.xml b/plugins/javaFX/src/META-INF/common-javaFX-plugin.xml index 59b5666860cc..65515493b6db 100644 --- a/plugins/javaFX/src/META-INF/common-javaFX-plugin.xml +++ b/plugins/javaFX/src/META-INF/common-javaFX-plugin.xml @@ -44,6 +44,11 @@ org.jetbrains.plugins.javaFX.fxml.codeInsight.intentions.JavaFxExpandAttributeIntention JavaFX + + org.jetbrains.plugins.javaFX.codeInsight.JavaFxFieldToPropertyIntention + JavaFX + + @@ -65,6 +70,7 @@ + diff --git a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/codeInsight/JavaFxFieldToPropertyIntention.java b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/codeInsight/JavaFxFieldToPropertyIntention.java new file mode 100644 index 000000000000..fe3517d69d4c --- /dev/null +++ b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/codeInsight/JavaFxFieldToPropertyIntention.java @@ -0,0 +1,422 @@ +package org.jetbrains.plugins.javaFX.codeInsight; + +import com.intellij.codeInsight.FileModificationService; +import com.intellij.codeInsight.intention.LowPriorityAction; +import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction; +import com.intellij.lang.java.JavaLanguage; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.codeStyle.CodeStyleManager; +import com.intellij.psi.codeStyle.JavaCodeStyleManager; +import com.intellij.psi.codeStyle.VariableKind; +import com.intellij.psi.impl.PsiDiamondTypeUtil; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.search.searches.ReferencesSearch; +import com.intellij.psi.tree.IElementType; +import com.intellij.psi.util.*; +import com.intellij.refactoring.typeMigration.*; +import com.intellij.refactoring.typeMigration.usageInfo.TypeMigrationUsageInfo; +import com.intellij.refactoring.util.RefactoringUtil; +import com.intellij.util.IncorrectOperationException; +import com.intellij.util.Query; +import com.siyeh.ig.psiutils.ParenthesesUtils; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.javaFX.fxml.JavaFxCommonNames; +import org.jetbrains.plugins.javaFX.fxml.JavaFxModuleUtil; +import org.jetbrains.plugins.javaFX.fxml.JavaFxPsiUtil; + +import java.util.HashSet; +import java.util.Set; + +/** + * @author Pavel.Dolgov + */ +public class JavaFxFieldToPropertyIntention extends PsiElementBaseIntentionAction implements LowPriorityAction { + private static final Logger LOG = Logger.getInstance(JavaFxFieldToPropertyIntention.class); + + @Nls + @NotNull + @Override + public String getFamilyName() { + return "Convert to JavaFX property"; + } + + @NotNull + @Override + public String getText() { + //noinspection DialogTitleCapitalization + return "Convert to JavaFX property"; + } + + @Override + public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) { + final PsiField field = getField(element); + if (field != null) { + final PsiFile file = field.getContainingFile(); + if (JavaFxModuleUtil.isInJavaFxProject(file) || JavaFxPsiUtil.isJavaFxPackageImported(file)) { + return PropertyInfo.createPropertyInfo(field, project) != null; + } + } + return false; + } + + @Override + public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) throws IncorrectOperationException { + final PsiField field = getField(element); + LOG.assertTrue(field != null, "field"); + final PropertyInfo property = PropertyInfo.createPropertyInfo(field, project); + LOG.assertTrue(property != null, "propertyInfo"); + + final Query refs = ReferencesSearch.search(field); + + final Set elements = new HashSet<>(); + elements.add(element); + for (PsiReference reference : refs) { + elements.add(reference.getElement()); + } + if (!FileModificationService.getInstance().preparePsiElementsForWrite(elements)) return; + field.normalizeDeclaration(); + + final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(project).getElementFactory(); + final PsiType fromType = field.getType(); + final PsiType toType = elementFactory.createTypeFromText(property.myObservableType.myText, field); + try { + final TypeMigrationRules rules = new TypeMigrationRules(); + rules.setBoundScope(GlobalSearchScope.fileScope(element.getContainingFile())); + final TypeMigrationLabeler labeler = new TypeMigrationLabeler(rules, toType); + final TypeMigrationUsageInfo[] migratedUsages = labeler.getMigratedUsages(false, field); + + for (PsiReference reference : refs) { + final PsiElement refElement = reference.getElement(); + if (refElement instanceof PsiExpression) { + final TypeConversionDescriptor conversion = + property.myObservableType.findDirectConversion(refElement, toType, fromType, labeler); + if (conversion != null) { + TypeMigrationReplacementUtil.replaceExpression((PsiExpression)refElement, project, conversion, new TypeEvaluator(null, null)); + } + } + } + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + property.convertField(); + } + + @Nullable + private static PsiField getField(@NotNull PsiElement element) { + if (!(element instanceof PsiIdentifier)) return null; + final PsiField field = PsiTreeUtil.getParentOfType(element, PsiField.class); + if (field == null) return null; + if (field.getLanguage() != JavaLanguage.INSTANCE) return null; + if (field.getTypeElement() == null) return null; + if (field.hasModifierProperty(PsiModifier.STATIC) || field.hasModifierProperty(PsiModifier.FINAL)) return null; + return field; + } + + private static class PropertyInfo { + final PsiField myField; + final PsiClass myContainingClass; + final PsiTypeElement myTypeElement; + final String myFieldName; + final ObservableType myObservableType; + + private PropertyInfo(@NotNull PsiField field, + @NotNull PsiClass containingClass, + @NotNull PsiTypeElement typeElement, + @NotNull String fieldName, + @NotNull ObservableType observableType) { + myField = field; + myContainingClass = containingClass; + myTypeElement = typeElement; + myFieldName = fieldName; + myObservableType = observableType; + } + + static PropertyInfo createPropertyInfo(@NotNull PsiField field, @NotNull Project project) { + final String fieldName = field.getName(); + final PsiClass containingClass = field.getContainingClass(); + final PsiTypeElement typeElement = field.getTypeElement(); + if (fieldName != null && containingClass != null && typeElement != null) { + final ObservableType observableType = ObservableType.createObservableType(field, project); + if (observableType != null) { + return new PropertyInfo(field, containingClass, typeElement, fieldName, observableType); + } + } + return null; + } + + private void convertField() { + final Project project = myContainingClass.getProject(); + final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(project).getElementFactory(); + + final PsiTypeElement newTypeElement = elementFactory.createTypeElementFromText(myObservableType.myText, myField); + myTypeElement.replace(newTypeElement); + + final PsiExpression initializer = myField.getInitializer(); + final String propertyName = JavaCodeStyleManager.getInstance(project).variableNameToPropertyName(myFieldName, VariableKind.FIELD); + final String initializerArgs = "this,\"" + propertyName + "\"" + (initializer == null ? "" : "," + initializer.getText()); + + String initializerText = "new " + myObservableType.myText + "(" + initializerArgs + ")"; + final PsiNewExpression newInitializer = (PsiNewExpression)elementFactory.createExpressionFromText(initializerText, myField); + myField.setInitializer(newInitializer); + + final PsiType fieldType = myField.getType(); + if (PsiDiamondTypeUtil.canCollapseToDiamond(newInitializer, newInitializer, fieldType)) { + final PsiJavaCodeReferenceElement classReference = newInitializer.getClassOrAnonymousClassReference(); + if (classReference != null) { + PsiDiamondTypeUtil.replaceExplicitWithDiamond(classReference.getParameterList()); + } + } + myField.setInitializer(newInitializer); + + final JavaCodeStyleManager javaCodeStyleManager = JavaCodeStyleManager.getInstance(project); + final CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project); + codeStyleManager.reformat(javaCodeStyleManager.shortenClassReferences(myField)); + } + } + + static class ObservableType { + final String myText; + + ObservableType(@NotNull String text) { + this.myText = text; + } + + @Nullable + static ObservableType createObservableType(@NotNull PsiField field, @NotNull Project project) { + final PsiType type = field.getType(); + if (type instanceof PsiPrimitiveType) { + final String text = JavaFxCommonNames.ourObservablePrimitiveWrappers.get(type); + return text != null ? new ObservablePrimitive(text, (PsiPrimitiveType)type) : null; + } + final PsiPrimitiveType unboxedType = PsiPrimitiveType.getUnboxedType(type); + if (unboxedType != null) { + final String text = JavaFxCommonNames.ourObservablePrimitiveWrappers.get(unboxedType); + return text != null ? new ObservablePrimitive(text, unboxedType) : null; + } + if (type.equalsToText(CommonClassNames.JAVA_LANG_STRING)) { + return new ObservableString(project); + } + if (type instanceof PsiClassType) { + if (InheritanceUtil.isInheritor(type, JavaFxCommonNames.JAVAFX_BEANS_OBSERVABLE)) { + return null; // already observable + } + if (InheritanceUtil.isInheritor(type, CommonClassNames.JAVA_UTIL_LIST)) { + return ObservableList.createObservableList(type, project); + } + else if (InheritanceUtil.isInheritor(type, CommonClassNames.JAVA_UTIL_COLLECTION) || + InheritanceUtil.isInheritor(type, CommonClassNames.JAVA_UTIL_MAP)) { + return null; // TODO: support SimpleSetProperty, SimpleMapProperty + } + else { + return new ObservableObject(type, project); + } + } + return null; + } + + TypeConversionDescriptor findDirectConversion(@NotNull PsiElement context, + @NotNull PsiType to, + @NotNull PsiType from, + @NotNull TypeMigrationLabeler labeler) { + final PsiClass toTypeClass = PsiUtil.resolveClassInType(to); + LOG.assertTrue(toTypeClass != null); + + final PsiElement parent = context.getParent(); + final PsiElement statementOrLambda = RefactoringUtil.getParentStatement(context, false); + if (parent instanceof PsiAssignmentExpression) { + final PsiAssignmentExpression expression = (PsiAssignmentExpression)parent; + final IElementType tokenType = expression.getOperationTokenType(); + if (tokenType == JavaTokenType.EQ) { + return findSimpleAssignmentConversion(expression); + } + final String sign = expression.getOperationSign().getText(); + final String binarySign = sign.substring(0, sign.length() - 1); + return findCompoundAssignmentConversion(from, expression, sign, binarySign); + } + else if (parent instanceof PsiPostfixExpression) { + final PsiPostfixExpression expression = (PsiPostfixExpression)parent; + final TypeConversionDescriptor conversion = getUpdateConversion(expression, expression.getOperationSign(), true); + if (conversion != null) return conversion; + } + else if (parent instanceof PsiPrefixExpression) { + final PsiPrefixExpression expression = (PsiPrefixExpression)parent; + final TypeConversionDescriptor conversion = getUpdateConversion(expression, expression.getOperationSign(), false); + if (conversion != null) return conversion; + } + else if (context instanceof PsiReferenceExpression) { + final PsiExpression qualifierExpression = ((PsiReferenceExpression)context).getQualifierExpression(); + final PsiExpression expression = context.getParent() instanceof PsiMethodCallExpression && qualifierExpression != null + ? qualifierExpression + : (PsiExpression)context; + return getReadConversion(expression); + } + + return null; + } + + @Nullable + TypeConversionDescriptor findSimpleAssignmentConversion(PsiAssignmentExpression expression) { + return new TypeConversionDescriptor("$qualifier$ = $val$", "$qualifier$.set($val$)", expression); + } + + @Nullable + TypeConversionDescriptor findCompoundAssignmentConversion(@NotNull PsiType from, + @NotNull PsiExpression expression, + @NotNull String sign, + @NotNull String binarySign) { + return null; + } + + @Nullable + TypeConversionDescriptor getUpdateConversion(@NotNull PsiExpression expression, @NotNull PsiJavaToken operationToken, boolean postfix) { + return null; + } + + + @NotNull + TypeConversionDescriptor getReadConversion(PsiExpression expression) { + return new TypeConversionDescriptor("$qualifier$", "$qualifier$.get()", expression); + } + } + + static class ObservablePrimitive extends ObservableType { + final PsiPrimitiveType myType; + + ObservablePrimitive(@NotNull String text, @NotNull PsiPrimitiveType type) { + super(text); + myType = type; + } + + @Nullable + @Override + TypeConversionDescriptor findCompoundAssignmentConversion(@NotNull PsiType from, + @NotNull PsiExpression expression, + @NotNull String sign, + @NotNull String binarySign) { + final PsiPrimitiveType unboxedType = PsiPrimitiveType.getUnboxedType(from); + final String valueType = (unboxedType != null ? unboxedType : from).getCanonicalText(); + return new TypeConversionDescriptor("$qualifier$ " + sign + " $val$", + "$qualifier$.set((" + valueType + ")($qualifier$.get() " + binarySign + " ($val$)))", + expression); + } + + @Nullable + @Override + TypeConversionDescriptor getUpdateConversion(@NotNull PsiExpression expression, @NotNull PsiJavaToken operationToken, boolean postfix) { + final PsiElement parent = ParenthesesUtils.getParentSkipParentheses(expression); + if (parent instanceof PsiExpressionStatement) { + final IElementType tokenType = operationToken.getTokenType(); + if (tokenType == JavaTokenType.PLUSPLUS || tokenType == JavaTokenType.MINUSMINUS) { + final String sign = operationToken.getText(); + return new TypeConversionDescriptor(postfix ? ("$qualifier$" + sign) : (sign + "$qualifier$"), + "$qualifier$.set($qualifier$.get()" + sign.charAt(0) + "1)", expression); + } + } + return null; + } + } + + static class ObservableString extends ObservableType { + ObservableString(@NotNull Project project) { + super(JavaFxCommonNames.JAVAFX_BEANS_PROPERTY_SIMPLE_STRING_PROPERTY); + } + + @Nullable + @Override + TypeConversionDescriptor findCompoundAssignmentConversion(@NotNull PsiType from, + @NotNull PsiExpression expression, + @NotNull String sign, + @NotNull String binarySign) { + return new TypeConversionDescriptor("$qualifier$ " + sign + " $val$", + "$qualifier$.set($qualifier$.get() " + binarySign + " ($val$))", + expression); + } + } + + static class ObservableList extends ObservableType { + final PsiType myOriginalType; + final PsiType myItemType; + + ObservableList(@NotNull PsiType originalType, @NotNull PsiType itemType) { + super(JavaFxCommonNames.JAVAFX_BEANS_PROPERTY_SIMPLE_LIST_PROPERTY + "<" + itemType.getCanonicalText() + ">"); + myOriginalType = originalType; + myItemType = itemType; + } + + @Nullable + private static ObservableType createObservableList(@NotNull PsiType type, @NotNull Project project) { + final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(type); + final PsiClass fieldClass = resolveResult.getElement(); + if (fieldClass != null) { + final PsiClass listClass = JavaPsiFacade.getInstance(project) + .findClass(CommonClassNames.JAVA_UTIL_LIST, GlobalSearchScope.allScope(project)); + if (listClass != null) { + final PsiSubstitutor substitutor = + TypeConversionUtil.getClassSubstitutor(listClass, fieldClass, resolveResult.getSubstitutor()); + if (substitutor != null) { + final PsiType itemType = substitutor.substitute(listClass.getTypeParameters()[0]); + if (itemType != null) { + return new ObservableList(type, itemType); + } + } + } + } + return null; + } + + @Nullable + @Override + TypeConversionDescriptor findSimpleAssignmentConversion(PsiAssignmentExpression expression) { + return new TypeConversionDescriptor("$qualifier$ = $val$", "$qualifier$.setAll($val$)", expression); + } + + @NotNull + @Override + TypeConversionDescriptor getReadConversion(PsiExpression expression) { + return new TypeConversionDescriptor("$qualifier$", "$qualifier$.get()", expression) { + @Override + public PsiExpression replace(PsiExpression expression, TypeEvaluator evaluator) { + final PsiExpression replaced = super.replace(expression, evaluator); + // Replace the getter's return type: List -> ObservableList + final PsiElement parent = replaced.getParent(); + if (parent instanceof PsiReturnStatement) { + final PsiReturnStatement returnStatement = (PsiReturnStatement)parent; + final PsiElement statementParent = returnStatement.getParent(); + if (statementParent instanceof PsiCodeBlock) { + final PsiCodeBlock codeBlock = (PsiCodeBlock)statementParent; + final PsiElement blockParent = codeBlock.getParent(); + if (blockParent instanceof PsiMethod) { + final PsiMethod method = (PsiMethod)blockParent; + final PsiTypeElement returnTypeElement = method.getReturnTypeElement(); + if (returnTypeElement != null && myOriginalType.equals(method.getReturnType())) { + final Project project = expression.getProject(); + final String text = JavaFxCommonNames.JAVAFX_COLLECTIONS_OBSERVABLE_LIST + "<" + myItemType.getCanonicalText() + ">"; + final PsiTypeElement newReturnTypeElement = JavaPsiFacade.getInstance(project) + .getElementFactory().createTypeElementFromText(text, method); + final JavaCodeStyleManager javaCodeStyleManager = JavaCodeStyleManager.getInstance(project); + javaCodeStyleManager.shortenClassReferences(returnTypeElement.replace(newReturnTypeElement)); + } + } + } + } + return replaced; + } + }; + } + } + + static class ObservableObject extends ObservableType { + final PsiType myType; + + ObservableObject(@NotNull PsiType type, @NotNull Project project) { + super(JavaFxCommonNames.JAVAFX_BEANS_PROPERTY_SIMPLE_OBJECT_PROPERTY + "<" + type.getCanonicalText() + ">"); + myType = type; + } + } +} diff --git a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/JavaFxCommonNames.java b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/JavaFxCommonNames.java index 0c7bb16b7a7b..7a88db9b091c 100644 --- a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/JavaFxCommonNames.java +++ b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/JavaFxCommonNames.java @@ -15,6 +15,7 @@ */ package org.jetbrains.plugins.javaFX.fxml; +import com.intellij.psi.PsiPrimitiveType; import com.intellij.psi.PsiType; import org.jetbrains.annotations.NonNls; @@ -50,6 +51,9 @@ public class JavaFxCommonNames { @NonNls public static final String JAVAFX_BEANS_VALUE_WRITABLE_VALUE = "javafx.beans.value.WritableValue"; @NonNls public static final String JAVAFX_SCENE_LAYOUT_PANE = "javafx.scene.layout.Pane"; @NonNls public static final String JAVAFX_BEANS_NAMED_ARG = "javafx.beans.NamedArg"; + @NonNls public static final String JAVAFX_BEANS_PROPERTY_SIMPLE_STRING_PROPERTY = "javafx.beans.property.SimpleStringProperty"; + @NonNls public static final String JAVAFX_BEANS_PROPERTY_SIMPLE_LIST_PROPERTY = "javafx.beans.property.SimpleListProperty"; + @NonNls public static final String JAVAFX_BEANS_PROPERTY_SIMPLE_OBJECT_PROPERTY = "javafx.beans.property.SimpleObjectProperty"; @NonNls public static final String PROPERTY_METHOD_SUFFIX = "Property"; @@ -74,4 +78,13 @@ public class JavaFxCommonNames { @NonNls public static final String JAVA_FX_PARENT = "javafx.scene.Parent"; @NonNls public static final String JAVA_FX_SCENE = "javafx.scene.Scene"; @NonNls public static final String JAVAFX_APPLICATION_APPLICATION = "javafx.application.Application"; + + public static final Map ourObservablePrimitiveWrappers = new HashMap<>(); + static { + ourObservablePrimitiveWrappers.put(PsiPrimitiveType.INT, "javafx.beans.property.SimpleIntegerProperty"); + ourObservablePrimitiveWrappers.put(PsiPrimitiveType.LONG, "javafx.beans.property.SimpleLongProperty"); + ourObservablePrimitiveWrappers.put(PsiPrimitiveType.FLOAT, "javafx.beans.property.SimpleFloatProperty"); + ourObservablePrimitiveWrappers.put(PsiPrimitiveType.DOUBLE, "javafx.beans.property.SimpleDoubleProperty"); + ourObservablePrimitiveWrappers.put(PsiPrimitiveType.BOOLEAN, "javafx.beans.property.SimpleBooleanProperty"); + } } diff --git a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/JavaFxFileTypeFactory.java b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/JavaFxFileTypeFactory.java index 27e0093fb04b..804d338f2dd3 100644 --- a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/JavaFxFileTypeFactory.java +++ b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/JavaFxFileTypeFactory.java @@ -6,6 +6,7 @@ import com.intellij.openapi.fileTypes.FileTypeFactory; import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiFile; +import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; /** @@ -13,7 +14,8 @@ import org.jetbrains.annotations.NotNull; * Date: 1/8/13 */ public class JavaFxFileTypeFactory extends FileTypeFactory { - public static final String FXML_EXTENSION = "fxml"; + @NonNls public static final String FXML_EXTENSION = "fxml"; + @NonNls private static final String DOT_FXML_EXTENSION = "." + FXML_EXTENSION; public static boolean isFxml(@NotNull PsiFile file) { final VirtualFile virtualFile = file.getViewProvider().getVirtualFile(); @@ -23,11 +25,18 @@ public class JavaFxFileTypeFactory extends FileTypeFactory { public static boolean isFxml(@NotNull VirtualFile virtualFile) { if (FXML_EXTENSION.equals(virtualFile.getExtension())) { final FileType fileType = virtualFile.getFileType(); - if (fileType == FileTypeManager.getInstance().getFileTypeByExtension(FXML_EXTENSION) && !fileType.isBinary()) return true; + if (fileType == getFileType() && !fileType.isBinary()) { + return virtualFile.getName().endsWith(DOT_FXML_EXTENSION); + } } return false; } + @NotNull + public static FileType getFileType() { + return FileTypeManager.getInstance().getFileTypeByExtension(FXML_EXTENSION); + } + @Override public void createFileTypes(@NotNull FileTypeConsumer consumer) { final FileType fileType = consumer.getStandardFileTypeByName("XML"); diff --git a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/JavaFxModuleUtil.java b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/JavaFxModuleUtil.java new file mode 100644 index 000000000000..834136fc7c2d --- /dev/null +++ b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/JavaFxModuleUtil.java @@ -0,0 +1,100 @@ +package org.jetbrains.plugins.javaFX.fxml; + +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleUtil; +import com.intellij.openapi.project.DumbService; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ProjectRootManager; +import com.intellij.openapi.startup.StartupActivity; +import com.intellij.openapi.startup.StartupManager; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.packaging.artifacts.Artifact; +import com.intellij.packaging.artifacts.ArtifactManager; +import com.intellij.psi.PsiFile; +import com.intellij.psi.search.FileTypeIndex; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.util.CachedValueProvider; +import com.intellij.psi.util.CachedValuesManager; +import gnu.trove.THashSet; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.javaFX.packaging.JavaFxApplicationArtifactType; + +import java.util.Collection; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * @author Pavel.Dolgov + */ +public class JavaFxModuleUtil { + public static boolean isInJavaFxProject(@NotNull PsiFile file) { + final Project project = file.getProject(); + if (hasJavaFxArtifacts(project)) { + return true; + } + return isInJavaFxModule(file); + } + + private static boolean isInJavaFxModule(@NotNull PsiFile file) { + final VirtualFile virtualFile = file.getVirtualFile(); + if (virtualFile != null) { + final Project project = file.getProject(); + final Module fileModule = ModuleUtil.findModuleForFile(virtualFile, project); + if (fileModule != null) { + return getCachedJavaFxModules(project).contains(fileModule); + } + } + return false; + } + + @NotNull + private static Set getCachedJavaFxModules(@NotNull Project project) { + Set value = CachedValuesManager.getManager(project).getCachedValue( + project, () -> { + final Collection files = + FileTypeIndex.getFiles(JavaFxFileTypeFactory.getFileType(), GlobalSearchScope.projectScope(project)); + + final Set modules = files.stream() + .filter(JavaFxFileTypeFactory::isFxml) + .map(file -> ModuleUtil.findModuleForFile(file, project)) + .collect(Collectors.toCollection(THashSet::new)); + + return CachedValueProvider.Result.create(modules, ProjectRootManager.getInstance(project)); + }); + return value; + } + + @NotNull + private static boolean hasJavaFxArtifacts(@NotNull Project project) { + return CachedValuesManager.getManager(project).getCachedValue( + project, () -> { + final Collection artifacts = + ArtifactManager.getInstance(project).getArtifactsByType(JavaFxApplicationArtifactType.getInstance()); + return CachedValueProvider.Result.create(!artifacts.isEmpty(), ProjectRootManager.getInstance(project)); + }); + } + + /** + * Avoids freeze on first use of Java intentions + */ + public static class JavaFxDetectionStartupActivity implements StartupActivity { + @Override + public void runActivity(@NotNull Project project) { + if (ApplicationManager.getApplication().isUnitTestMode()) { + return; + } + StartupManager.getInstance(project).runWhenProjectIsInitialized( + () -> ApplicationManager.getApplication().executeOnPooledThread( + () -> DumbService.getInstance(project).runReadActionInSmartMode( + () -> populateCachedJavaFxModules(project)))); + } + + private void populateCachedJavaFxModules(@NotNull Project project) { + if (!project.isDisposed() && project.isOpen()) { + hasJavaFxArtifacts(project); + getCachedJavaFxModules(project); + } + } + } +} diff --git a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/JavaFxPsiUtil.java b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/JavaFxPsiUtil.java index 7029408deca3..25cec6a5dbfd 100644 --- a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/JavaFxPsiUtil.java +++ b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/JavaFxPsiUtil.java @@ -1236,4 +1236,26 @@ public class JavaFxPsiUtil { } return true; } + + public static boolean isJavaFxPackageImported(@NotNull PsiFile file) { + if (!(file instanceof PsiJavaFile)) return false; + final PsiJavaFile javaFile = (PsiJavaFile)file; + + return CachedValuesManager.getCachedValue( + javaFile, () -> { + final PsiImportList importList = javaFile.getImportList(); + if (importList != null) { + for (PsiImportStatementBase statementBase : importList.getAllImportStatements()) { + final PsiJavaCodeReferenceElement importReference = statementBase.getImportReference(); + if (importReference != null) { + final String qualifiedName = importReference.getQualifiedName(); + if (qualifiedName != null && qualifiedName.startsWith("javafx.")) { + return CachedValueProvider.Result.create(true, PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT); + } + } + } + } + return CachedValueProvider.Result.create(false, PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT); + }); + } } diff --git a/plugins/javaFX/testData/intentions/fieldToProperty/BigDecimalFieldToProperty.java b/plugins/javaFX/testData/intentions/fieldToProperty/BigDecimalFieldToProperty.java new file mode 100644 index 000000000000..0f141c3df988 --- /dev/null +++ b/plugins/javaFX/testData/intentions/fieldToProperty/BigDecimalFieldToProperty.java @@ -0,0 +1,17 @@ +import java.math.BigDecimal; + +class BigDecimalDemo { + private BigDecimal number = new BigDecimal(42); + + BigDecimalDemo(BigDecimal number) { + this.number = number; + } + + public BigDecimal get() { + return number; + } + + public BigDecimal get(int i) { + return number; + } +} \ No newline at end of file diff --git a/plugins/javaFX/testData/intentions/fieldToProperty/BigDecimalFieldToProperty_after.java b/plugins/javaFX/testData/intentions/fieldToProperty/BigDecimalFieldToProperty_after.java new file mode 100644 index 000000000000..a7565645a1f3 --- /dev/null +++ b/plugins/javaFX/testData/intentions/fieldToProperty/BigDecimalFieldToProperty_after.java @@ -0,0 +1,19 @@ +import javafx.beans.property.SimpleObjectProperty; + +import java.math.BigDecimal; + +class BigDecimalDemo { + private SimpleObjectProperty number = new SimpleObjectProperty<>(this, "number", new BigDecimal(42)); + + BigDecimalDemo(BigDecimal number) { + this.number.set(number); + } + + public BigDecimal get() { + return number.get(); + } + + public BigDecimal get(int i) { + return number.get(); + } +} \ No newline at end of file diff --git a/plugins/javaFX/testData/intentions/fieldToProperty/BoxedFloatFieldToProperty.java b/plugins/javaFX/testData/intentions/fieldToProperty/BoxedFloatFieldToProperty.java new file mode 100644 index 000000000000..5bd7f6939e1a --- /dev/null +++ b/plugins/javaFX/testData/intentions/fieldToProperty/BoxedFloatFieldToProperty.java @@ -0,0 +1,49 @@ +import javafx.scene.Node; + +class BoxedFloatDemo { + private Float f; + + BoxedFloatDemo(Float f) { + this.f = f; + } + + public Float getF() { + return f; + } + + public void setF(Float f) { + this.f = f; + } + + public void preInc() { + ++f; + } + + public void postDec() { + f--; + } + + public void twice() { + f *= 2; + } + + public void half() { + f /= 1; + } + + public Float plusOne() { + return f + 1; + } + + public F lambda() { + return () -> f; + } + + public String toString() { + return "f=" + f; + } + + interface F { + Float get(); + } +} \ No newline at end of file diff --git a/plugins/javaFX/testData/intentions/fieldToProperty/BoxedFloatFieldToProperty_after.java b/plugins/javaFX/testData/intentions/fieldToProperty/BoxedFloatFieldToProperty_after.java new file mode 100644 index 000000000000..669e4154377e --- /dev/null +++ b/plugins/javaFX/testData/intentions/fieldToProperty/BoxedFloatFieldToProperty_after.java @@ -0,0 +1,50 @@ +import javafx.beans.property.SimpleFloatProperty; +import javafx.scene.Node; + +class BoxedFloatDemo { + private SimpleFloatProperty f = new SimpleFloatProperty(this, "f"); + + BoxedFloatDemo(Float f) { + this.f.set(f); + } + + public Float getF() { + return f.get(); + } + + public void setF(Float f) { + this.f.set(f); + } + + public void preInc() { + f.set(f.get() + 1); + } + + public void postDec() { + f.set(f.get() - 1); + } + + public void twice() { + f.set((float) (f.get() * (2))); + } + + public void half() { + f.set((float) (f.get() / (1))); + } + + public Float plusOne() { + return f.get() + 1; + } + + public F lambda() { + return () -> f.get(); + } + + public String toString() { + return "f=" + f.get(); + } + + interface F { + Float get(); + } +} \ No newline at end of file diff --git a/plugins/javaFX/testData/intentions/fieldToProperty/IntFieldToProperty.java b/plugins/javaFX/testData/intentions/fieldToProperty/IntFieldToProperty.java new file mode 100644 index 000000000000..e4a0e2e10ade --- /dev/null +++ b/plugins/javaFX/testData/intentions/fieldToProperty/IntFieldToProperty.java @@ -0,0 +1,59 @@ +import javafx.scene.Node; + +class IntDemo { + int n; + + IntDemo(int n) { + this.n = n; + } + + public int getN() { + return n; + } + + public void setN(int n) { + this.n = n; + } + + public void preInc() { + ++n; + } + + public void postDec() { + n--; + } + + public int preIncVal() { + return ++n; + } + + public void twice() { + n *= 2; + } + + public void half() { + n >>= 1; + } + + public int plusOne() { + return n + 1; + } + + public void forLoop(int a) { + for (n = 0; n < a; n++) { + System.out.println(n); + } + } + + public I lambda() { + return () -> n; + } + + public String toString() { + return "n=" + n; + } + + interface I { + int get(); + } +} \ No newline at end of file diff --git a/plugins/javaFX/testData/intentions/fieldToProperty/IntFieldToProperty_after.java b/plugins/javaFX/testData/intentions/fieldToProperty/IntFieldToProperty_after.java new file mode 100644 index 000000000000..75c84d966390 --- /dev/null +++ b/plugins/javaFX/testData/intentions/fieldToProperty/IntFieldToProperty_after.java @@ -0,0 +1,60 @@ +import javafx.beans.property.SimpleIntegerProperty; +import javafx.scene.Node; + +class IntDemo { + SimpleIntegerProperty n = new SimpleIntegerProperty(this, "n"); + + IntDemo(int n) { + this.n.set(n); + } + + public int getN() { + return n.get(); + } + + public void setN(int n) { + this.n.set(n); + } + + public void preInc() { + n.set(n.get() + 1); + } + + public void postDec() { + n.set(n.get() - 1); + } + + public int preIncVal() { + return ++n; + } + + public void twice() { + n.set((int) (n.get() * (2))); + } + + public void half() { + n.set((int) (n.get() >> (1))); + } + + public int plusOne() { + return n.get() + 1; + } + + public void forLoop(int a) { + for (n.set(0); n.get() < a; n.set(n.get() + 1)) { + System.out.println(n.get()); + } + } + + public I lambda() { + return () -> n.get(); + } + + public String toString() { + return "n=" + n.get(); + } + + interface I { + int get(); + } +} \ No newline at end of file diff --git a/plugins/javaFX/testData/intentions/fieldToProperty/ListFieldToProperty.java b/plugins/javaFX/testData/intentions/fieldToProperty/ListFieldToProperty.java new file mode 100644 index 000000000000..ffeff871dfee --- /dev/null +++ b/plugins/javaFX/testData/intentions/fieldToProperty/ListFieldToProperty.java @@ -0,0 +1,23 @@ +import java.net.URL; +import java.util.List; +import javafx.scene.Node; + +class ListDemo { + private List urls; + + ListDemo(List urls) { + this.urls = urls; + } + + public List getUrls() { + return urls; + } + + public void setUrls(List urls) { + this.urls = urls; + } + + public String toString() { + return "urls=" + urls; + } +} \ No newline at end of file diff --git a/plugins/javaFX/testData/intentions/fieldToProperty/ListFieldToProperty_after.java b/plugins/javaFX/testData/intentions/fieldToProperty/ListFieldToProperty_after.java new file mode 100644 index 000000000000..a1a8d516bcfd --- /dev/null +++ b/plugins/javaFX/testData/intentions/fieldToProperty/ListFieldToProperty_after.java @@ -0,0 +1,26 @@ +import java.net.URL; +import java.util.List; + +import javafx.beans.property.SimpleListProperty; +import javafx.collections.ObservableList; +import javafx.scene.Node; + +class ListDemo { + private SimpleListProperty urls = new SimpleListProperty<>(this, "urls"); + + ListDemo(List urls) { + this.urls.setAll(urls); + } + + public ObservableList getUrls() { + return urls.get(); + } + + public void setUrls(List urls) { + this.urls.setAll(urls); + } + + public String toString() { + return "urls=" + urls.get(); + } +} \ No newline at end of file diff --git a/plugins/javaFX/testData/intentions/fieldToProperty/LongFieldToProperty.java b/plugins/javaFX/testData/intentions/fieldToProperty/LongFieldToProperty.java new file mode 100644 index 000000000000..eebcae5b9359 --- /dev/null +++ b/plugins/javaFX/testData/intentions/fieldToProperty/LongFieldToProperty.java @@ -0,0 +1,47 @@ +class LongDemo { + private long n; + + public long getN() { + return n; + } + + public void setN(long n) { + this.n = n; + } + + public void preInc() { + ++n; + } + + public long preIncVal() { + return ++n; + } + + public void postDec() { + n--; + } + + public void twice() { + n *= 2; + } + + public void half() { + n >>= 1; + } + + public long plusOne() { + return n + 1; + } + + public L lambda() { + return () -> n; + } + + public String toString() { + return "n=" + n; + } + + interface L { + long get(); + } +} \ No newline at end of file diff --git a/plugins/javaFX/testData/intentions/fieldToProperty/LongFieldToProperty_after.java b/plugins/javaFX/testData/intentions/fieldToProperty/LongFieldToProperty_after.java new file mode 100644 index 000000000000..486bc7189cce --- /dev/null +++ b/plugins/javaFX/testData/intentions/fieldToProperty/LongFieldToProperty_after.java @@ -0,0 +1,49 @@ +import javafx.beans.property.SimpleLongProperty; + +class LongDemo { + private SimpleLongProperty n = new SimpleLongProperty(this, "n"); + + public long getN() { + return n.get(); + } + + public void setN(long n) { + this.n.set(n); + } + + public void preInc() { + n.set(n.get() + 1); + } + + public long preIncVal() { + return ++n; + } + + public void postDec() { + n.set(n.get() - 1); + } + + public void twice() { + n.set((long) (n.get() * (2))); + } + + public void half() { + n.set((long) (n.get() >> (1))); + } + + public long plusOne() { + return n.get() + 1; + } + + public L lambda() { + return () -> n.get(); + } + + public String toString() { + return "n=" + n.get(); + } + + interface L { + long get(); + } +} \ No newline at end of file diff --git a/plugins/javaFX/testData/intentions/fieldToProperty/StringFieldToProperty.java b/plugins/javaFX/testData/intentions/fieldToProperty/StringFieldToProperty.java new file mode 100644 index 000000000000..577873121502 --- /dev/null +++ b/plugins/javaFX/testData/intentions/fieldToProperty/StringFieldToProperty.java @@ -0,0 +1,17 @@ +import javafx.scene.Node; + +class StringDemo { + String s = "Something"; + + StringDemo(String s) { + this.s = s; + } + + public void compound(String t) { + s += t; + } + + public String toString() { + return "s=" + s; + } +} \ No newline at end of file diff --git a/plugins/javaFX/testData/intentions/fieldToProperty/StringFieldToProperty_after.java b/plugins/javaFX/testData/intentions/fieldToProperty/StringFieldToProperty_after.java new file mode 100644 index 000000000000..3f467633026c --- /dev/null +++ b/plugins/javaFX/testData/intentions/fieldToProperty/StringFieldToProperty_after.java @@ -0,0 +1,18 @@ +import javafx.beans.property.SimpleStringProperty; +import javafx.scene.Node; + +class StringDemo { + SimpleStringProperty s = new SimpleStringProperty(this, "s", "Something"); + + StringDemo(String s) { + this.s.set(s); + } + + public void compound(String t) { + s.set(s.get() + (t)); + } + + public String toString() { + return "s=" + s.get(); + } +} \ No newline at end of file diff --git a/plugins/javaFX/testData/intentions/fieldToProperty/sample.fxml b/plugins/javaFX/testData/intentions/fieldToProperty/sample.fxml new file mode 100644 index 000000000000..083f45de1589 --- /dev/null +++ b/plugins/javaFX/testData/intentions/fieldToProperty/sample.fxml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file