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 extends Artifact> 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