diff --git a/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFxCompletionTest.java b/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFxCompletionTest.java index 092dd4bf7c62..bd9e61feb7ce 100644 --- a/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFxCompletionTest.java +++ b/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFxCompletionTest.java @@ -165,11 +165,17 @@ public class JavaFxCompletionTest extends LightFixtureCompletionTestCase { assertContainsElements(myFixture.getLookupElementStrings(), "true", "false"); } + public void testPropertyNameWithoutField() throws Exception { + myFixture.configureByFiles(getTestName(true) + ".fxml"); + complete(); + assertContainsElements(myFixture.getLookupElementStrings(), "disable"); + } + public void testDefaultPropertyIncludeOnce() throws Exception { myFixture.configureByFiles(getTestName(true) + ".fxml"); myItems = myFixture.completeBasic(); assertContainsElements(myFixture.getLookupElementStrings(), "fx:reference"); - assertEquals(5, myItems.length); + assertEquals(3, myItems.length); } public void testAcceptableSourceOnly() throws Exception { diff --git a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/JavaFxCommonClassNames.java b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/JavaFxCommonClassNames.java index b6fea16ad785..5b278347cab3 100644 --- a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/JavaFxCommonClassNames.java +++ b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/JavaFxCommonClassNames.java @@ -27,6 +27,7 @@ import java.util.Map; */ public class JavaFxCommonClassNames { @NonNls public static final String JAVAFX_BEANS_PROPERTY = "javafx.beans.property.Property"; + @NonNls public static final String JAVAFX_OBSERVABLE_LIST_PROPERTY = "javafx.collections.ObservableList"; @NonNls public static final String JAVAFX_ANCHOR_PANE = "javafx.scene.layout.AnchorPane"; @NonNls public static final String JAVAFX_EVENT = "javafx.event.Event"; @NonNls public static final String JAVAFX_BEANS_DEFAULT_PROPERTY = "javafx.beans.DefaultProperty"; diff --git a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/descriptors/JavaFxClassBackedElementDescriptor.java b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/descriptors/JavaFxClassBackedElementDescriptor.java index 582882b74639..027b04f2e68f 100644 --- a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/descriptors/JavaFxClassBackedElementDescriptor.java +++ b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/descriptors/JavaFxClassBackedElementDescriptor.java @@ -61,10 +61,10 @@ public class JavaFxClassBackedElementDescriptor implements XmlElementDescriptor, if (context != null) { if (myPsiClass != null) { final List children = new ArrayList(); - collectProperties(children, new Function() { + collectProperties(children, new Function() { @Override - public XmlElementDescriptor fun(PsiField field) { - return new JavaFxPropertyElementDescriptor(myPsiClass, field.getName(), false); + public XmlElementDescriptor fun(PsiMember member) { + return new JavaFxPropertyElementDescriptor(myPsiClass, member instanceof PsiMethod ? PropertyUtil.getPropertyName(member) : member.getName(), false); } }, false); @@ -232,21 +232,21 @@ public class JavaFxClassBackedElementDescriptor implements XmlElementDescriptor, } protected void collectInstanceProperties(List simpleAttrs) { - collectProperties(simpleAttrs, new Function() { + collectProperties(simpleAttrs, new Function() { @Override - public XmlAttributeDescriptor fun(PsiField field) { - return new JavaFxPropertyAttributeDescriptor(field.getName(), myPsiClass); + public XmlAttributeDescriptor fun(PsiMember member) { + return new JavaFxPropertyAttributeDescriptor(member instanceof PsiMethod ? PropertyUtil.getPropertyName(member) : member.getName(), myPsiClass); } }, true); } - private void collectProperties(final List children, final Function factory, final boolean acceptPrimitive) { - final List fieldList = - CachedValuesManager.getManager(myPsiClass.getProject()).getCachedValue(myPsiClass, new CachedValueProvider>() { + private void collectProperties(final List children, final Function factory, final boolean acceptPrimitive) { + final List fieldList = + CachedValuesManager.getManager(myPsiClass.getProject()).getCachedValue(myPsiClass, new CachedValueProvider>() { @Nullable @Override - public Result> compute() { - List acceptableFields = new ArrayList(); + public Result> compute() { + List acceptableFields = new ArrayList(); final PsiField[] fields = myPsiClass.getAllFields(); if (fields.length > 0) { for (PsiField field : fields) { @@ -254,18 +254,36 @@ public class JavaFxClassBackedElementDescriptor implements XmlElementDescriptor, final PsiType fieldType = field.getType(); if (!JavaFxPsiUtil.isReadOnly(myPsiClass, field) && InheritanceUtil.isInheritor(fieldType, JavaFxCommonClassNames.JAVAFX_BEANS_PROPERTY) || - fieldType.equalsToText(CommonClassNames.JAVA_LANG_STRING) || - (acceptPrimitive && fieldType instanceof PsiPrimitiveType) || - GenericsHighlightUtil.getCollectionItemType(field.getType(), myPsiClass.getResolveScope()) != null) { + acceptablePropertyType(fieldType)) { acceptableFields.add(field); } } } + for (PsiMethod method : myPsiClass.getAllMethods()) { + if (PropertyUtil.isSimplePropertySetter(method) && !method.hasModifierProperty(PsiModifier.STATIC)) { + final String propertyName = PropertyUtil.getPropertyName(method); + assert propertyName != null; + final PsiParameter[] parameters = method.getParameterList().getParameters(); + if (parameters.length != 1) continue; + if (myPsiClass.findFieldByName(propertyName, true) != null) continue; + final PsiType propertyType = parameters[0].getType(); + final String suggestedGetterName = PropertyUtil.suggestGetterName(propertyName, propertyType); + if (myPsiClass.findMethodsByName(suggestedGetterName, true).length == 0) continue; + if (!acceptablePropertyType(propertyType)) continue; + acceptableFields.add(method); + } + } return Result.create(acceptableFields, PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT); } + + private boolean acceptablePropertyType(PsiType fieldType) { + return fieldType.equalsToText(CommonClassNames.JAVA_LANG_STRING) || + (acceptPrimitive && fieldType instanceof PsiPrimitiveType) || + InheritanceUtil.isInheritor(fieldType, JavaFxCommonClassNames.JAVAFX_OBSERVABLE_LIST_PROPERTY) && GenericsHighlightUtil.getCollectionItemType(fieldType, myPsiClass.getResolveScope()) != null; + } }); if (fieldList != null) { - for (PsiField field : fieldList) { + for (PsiMember field : fieldList) { children.add(factory.fun(field)); } } diff --git a/plugins/javaFX/testData/completion/propertyNameWithoutField.fxml b/plugins/javaFX/testData/completion/propertyNameWithoutField.fxml new file mode 100644 index 000000000000..6d82c9120d38 --- /dev/null +++ b/plugins/javaFX/testData/completion/propertyNameWithoutField.fxml @@ -0,0 +1,2 @@ + +/> \ No newline at end of file