javafx: required attrs for default tags; accept static properties for default tags accepting them

This commit is contained in:
Anna Kozlova
2013-01-31 16:26:01 +04:00
parent 5e69ea09ab
commit bcf913b0fc
11 changed files with 120 additions and 87 deletions
@@ -47,7 +47,14 @@ public class FxmlConstants {
public static final Map<String, List<String>> FX_ELEMENT_ATTRIBUTES = new HashMap<String, List<String>>();
static {
FX_ELEMENT_ATTRIBUTES.put(FX_INCLUDE, Arrays.asList(FX_ELEMENT_SOURCE));
FX_ELEMENT_ATTRIBUTES.put(FX_INCLUDE, Arrays.asList(FX_ELEMENT_SOURCE, FX_ID));
FX_ELEMENT_ATTRIBUTES.put(FX_REFERENCE, Arrays.asList(FX_ELEMENT_SOURCE));
}
public static final Map<String, List<String>> FX_REQUIRED_ELEMENT_ATTRIBUTES = new HashMap<String, List<String>>();
static {
FX_REQUIRED_ELEMENT_ATTRIBUTES.put(FX_INCLUDE, Arrays.asList(FX_ELEMENT_SOURCE));
FX_REQUIRED_ELEMENT_ATTRIBUTES.put(FX_REFERENCE, Arrays.asList(FX_ELEMENT_SOURCE));
}
}
@@ -1,9 +1,7 @@
package org.jetbrains.plugins.javaFX.fxml;
import com.intellij.codeInsight.daemon.Validator;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.xml.*;
import com.intellij.util.ArrayUtil;
import com.intellij.xml.XmlElementDescriptor;
@@ -12,11 +10,6 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.javaFX.fxml.descriptors.JavaFxClassBackedElementDescriptor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
/**
* User: anna
* Date: 1/9/13
@@ -29,7 +22,7 @@ public class JavaFXNSDescriptor implements XmlNSDescriptor, Validator<XmlDocumen
public XmlElementDescriptor getElementDescriptor(@NotNull XmlTag tag) {
final String name = tag.getName();
if (JavaFxClassBackedElementDescriptor.isClassTag(name)) {
if (JavaFxPsiUtil.isClassTag(name)) {
return new JavaFxClassBackedElementDescriptor(name, tag);
}
else {
@@ -21,6 +21,7 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.PostprocessReformattingAspect;
import com.intellij.psi.util.PropertyUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.psi.xml.*;
@@ -149,4 +150,38 @@ public class JavaFxPsiUtil {
}
return null;
}
public static boolean isClassTag(String name) {
final String shortName = StringUtil.getShortName(name);
return StringUtil.isCapitalized(name) && name.equals(shortName);
}
public static PsiMethod findPropertySetter(String attributeName, XmlTag context) {
final String packageName = StringUtil.getPackageName(attributeName);
if (context != null && !StringUtil.isEmptyOrSpaces(packageName)) {
final PsiClass classWithStaticProperty = findPsiClass(packageName, context);
if (classWithStaticProperty != null) {
return findPropertySetter(attributeName, classWithStaticProperty);
}
}
return null;
}
public static PsiMethod findPropertySetter(String attributeName, PsiClass classWithStaticProperty) {
final String setterName = PropertyUtil.suggestSetterName(StringUtil.getShortName(attributeName));
final PsiMethod[] setters = classWithStaticProperty.findMethodsByName(setterName, true);
if (setters.length == 1) {
return setters[0];
}
return null;
}
public static PsiMethod findPropertyGetter(String attributeName, PsiClass classWithStaticProperty) {
final String getterName = PropertyUtil.suggestGetterName(StringUtil.getShortName(attributeName), null);
final PsiMethod[] getters = classWithStaticProperty.findMethodsByName(getterName, true);
if (getters.length >= 1) {
return getters[0];
}
return null;
}
}
@@ -69,20 +69,14 @@ public class JavaFxClassBackedElementDescriptor implements XmlElementDescriptor,
}
});
collectParentStaticProperties(context, children, new Function<PsiMethod, XmlElementDescriptor>() {
@Override
public XmlElementDescriptor fun(PsiMethod method) {
final PsiClass aClass = method.getContainingClass();
return new JavaFxPropertyElementDescriptor(aClass, PropertyUtil.getPropertyName(method.getName()), true);
}
});
collectStaticElementDescriptors(context, children);
final PsiAnnotation annotation = AnnotationUtil.findAnnotationInHierarchy(myPsiClass, Collections.singleton(JavaFxCommonClassNames.JAVAFX_BEANS_DEFAULT_PROPERTY));
if (annotation != null) {
final PsiAnnotationMemberValue memberValue = annotation.findAttributeValue(null);
if (memberValue != null) {
final String propertyName = StringUtil.stripQuotesAroundValue(memberValue.getText());
final PsiMethod getter = findPropertyGetter(propertyName, myPsiClass);
final PsiMethod getter = JavaFxPsiUtil.findPropertyGetter(propertyName, myPsiClass);
if (getter != null) {
final PsiType returnType = getter.getReturnType();
JavaFxPropertyElementDescriptor.collectDescriptorsByCollection(returnType, myPsiClass.getResolveScope(), children);
@@ -102,6 +96,25 @@ public class JavaFxClassBackedElementDescriptor implements XmlElementDescriptor,
return XmlElementDescriptor.EMPTY_ARRAY;
}
static void collectStaticAttributesDescriptors(XmlTag context, List<XmlAttributeDescriptor> simpleAttrs) {
collectParentStaticProperties(context.getParentTag(), simpleAttrs, new Function<PsiMethod, XmlAttributeDescriptor>() {
@Override
public XmlAttributeDescriptor fun(PsiMethod method) {
return new JavaFxSetterAttributeDescriptor(method, method.getContainingClass());
}
});
}
protected static void collectStaticElementDescriptors(XmlTag context, List<XmlElementDescriptor> children) {
collectParentStaticProperties(context, children, new Function<PsiMethod, XmlElementDescriptor>() {
@Override
public XmlElementDescriptor fun(PsiMethod method) {
final PsiClass aClass = method.getContainingClass();
return new JavaFxPropertyElementDescriptor(aClass, PropertyUtil.getPropertyName(method.getName()), true);
}
});
}
private static <T> void collectParentStaticProperties(XmlTag context, List<T> children, Function<PsiMethod, T> factory) {
XmlTag tag = context;
while (tag != null) {
@@ -127,13 +140,13 @@ public class JavaFxClassBackedElementDescriptor implements XmlElementDescriptor,
@Override
public XmlElementDescriptor getElementDescriptor(XmlTag childTag, XmlTag contextTag) {
final String name = childTag.getName();
if (isClassTag(name)) {
if (JavaFxPsiUtil.isClassTag(name)) {
return new JavaFxClassBackedElementDescriptor(name, childTag);
}
else {
final String shortName = StringUtil.getShortName(name);
if (!name.equals(shortName)) { //static property
final PsiMethod propertySetter = findPropertySetter(name, childTag);
final PsiMethod propertySetter = JavaFxPsiUtil.findPropertySetter(name, childTag);
if (propertySetter != null) {
return new JavaFxPropertyElementDescriptor(propertySetter.getContainingClass(), shortName, true);
}
@@ -146,11 +159,6 @@ public class JavaFxClassBackedElementDescriptor implements XmlElementDescriptor,
}
}
public static boolean isClassTag(String name) {
final String shortName = StringUtil.getShortName(name);
return StringUtil.isCapitalized(name) && name.equals(shortName);
}
@Override
public XmlAttributeDescriptor[] getAttributesDescriptors(@Nullable XmlTag context) {
//todo filter
@@ -164,12 +172,7 @@ public class JavaFxClassBackedElementDescriptor implements XmlElementDescriptor,
return new JavaFxPropertyAttributeDescriptor(field.getName(), myPsiClass);
}
});
collectParentStaticProperties(context.getParentTag(), simpleAttrs, new Function<PsiMethod, XmlAttributeDescriptor>() {
@Override
public XmlAttributeDescriptor fun(PsiMethod method) {
return new JavaFxSetterAttributeDescriptor(method, method.getContainingClass());
}
});
collectStaticAttributesDescriptors(context, simpleAttrs);
for (String defaultProperty : FxmlConstants.FX_DEFAULT_PROPERTIES) {
simpleAttrs.add(new JavaFxDefaultAttributeDescriptor(defaultProperty, myPsiClass));
}
@@ -203,7 +206,7 @@ public class JavaFxClassBackedElementDescriptor implements XmlElementDescriptor,
if (FxmlConstants.FX_DEFAULT_PROPERTIES.contains(attributeName)){
return new JavaFxDefaultAttributeDescriptor(attributeName, myPsiClass);
} else {
final PsiMethod propertySetter = findPropertySetter(attributeName, context);
final PsiMethod propertySetter = JavaFxPsiUtil.findPropertySetter(attributeName, context);
if (propertySetter != null) {
return new JavaFxStaticPropertyAttributeDescriptor(propertySetter, attributeName);
}
@@ -301,33 +304,4 @@ public class JavaFxClassBackedElementDescriptor implements XmlElementDescriptor,
}
}
}
public static PsiMethod findPropertySetter(String attributeName, XmlTag context) {
final String packageName = StringUtil.getPackageName(attributeName);
if (context != null && !StringUtil.isEmptyOrSpaces(packageName)) {
final PsiClass classWithStaticProperty = JavaFxPsiUtil.findPsiClass(packageName, context);
if (classWithStaticProperty != null) {
return findPropertySetter(attributeName, classWithStaticProperty);
}
}
return null;
}
public static PsiMethod findPropertySetter(String attributeName, PsiClass classWithStaticProperty) {
final String setterName = PropertyUtil.suggestSetterName(StringUtil.getShortName(attributeName));
final PsiMethod[] setters = classWithStaticProperty.findMethodsByName(setterName, true);
if (setters.length == 1) {
return setters[0];
}
return null;
}
public static PsiMethod findPropertyGetter(String attributeName, PsiClass classWithStaticProperty) {
final String getterName = PropertyUtil.suggestGetterName(StringUtil.getShortName(attributeName), null);
final PsiMethod[] getters = classWithStaticProperty.findMethodsByName(getterName, true);
if (getters.length >= 1) {
return getters[0];
}
return null;
}
}
@@ -21,6 +21,8 @@ import com.intellij.psi.PsiField;
import com.intellij.psi.PsiModifier;
import org.jetbrains.plugins.javaFX.fxml.FxmlConstants;
import java.util.List;
/**
* User: anna
* Date: 1/10/13
@@ -28,10 +30,16 @@ import org.jetbrains.plugins.javaFX.fxml.FxmlConstants;
public class JavaFxDefaultAttributeDescriptor extends JavaFxPropertyAttributeDescriptor {
private static final Logger LOG = Logger.getInstance("#" + JavaFxDefaultAttributeDescriptor.class.getName());
private String myDefaultPropertyName = null;
public JavaFxDefaultAttributeDescriptor(String name, PsiClass psiClass) {
super(name, psiClass);
}
public JavaFxDefaultAttributeDescriptor(String name, String defaultPropertyName) {
super(name, null);
myDefaultPropertyName = defaultPropertyName;
}
@Override
public boolean hasIdType() {
return getName().equals(FxmlConstants.FX_ID);
@@ -42,6 +50,15 @@ public class JavaFxDefaultAttributeDescriptor extends JavaFxPropertyAttributeDes
return getName().equals("fx:constant");
}
@Override
public boolean isRequired() {
if (myDefaultPropertyName != null) {
final List<String> requiredAttrs = FxmlConstants.FX_REQUIRED_ELEMENT_ATTRIBUTES.get(myDefaultPropertyName);
if (requiredAttrs != null && requiredAttrs.contains(getName())) return true;
}
return false;
}
@Override
protected PsiClass getEnum() {
return isEnumerated() ? getPsiClass() : null ;
@@ -16,6 +16,7 @@
package org.jetbrains.plugins.javaFX.fxml.descriptors;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlTag;
import com.intellij.util.ArrayUtil;
@@ -26,6 +27,7 @@ import com.intellij.xml.XmlNSDescriptor;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.javaFX.fxml.FxmlConstants;
import org.jetbrains.plugins.javaFX.fxml.JavaFxPsiUtil;
import java.util.ArrayList;
import java.util.List;
@@ -69,8 +71,9 @@ public class JavaFxDefaultPropertyElementDescriptor implements XmlElementDescrip
if (defaultAttributeList != null) {
final List<XmlAttributeDescriptor> descriptors = new ArrayList<XmlAttributeDescriptor>();
for (String defaultAttrName : defaultAttributeList) {
descriptors.add(new JavaFxDefaultAttributeDescriptor(defaultAttrName, null));
descriptors.add(new JavaFxDefaultAttributeDescriptor(defaultAttrName, getName()));
}
JavaFxClassBackedElementDescriptor.collectStaticAttributesDescriptors(context, descriptors);
return descriptors.toArray(new XmlAttributeDescriptor[descriptors.size()]);
}
return XmlAttributeDescriptor.EMPTY;
@@ -80,8 +83,14 @@ public class JavaFxDefaultPropertyElementDescriptor implements XmlElementDescrip
@Override
public XmlAttributeDescriptor getAttributeDescriptor(@NonNls String attributeName, @Nullable XmlTag context) {
final List<String> defaultAttributeList = FxmlConstants.FX_ELEMENT_ATTRIBUTES.get(getName());
if (defaultAttributeList != null && defaultAttributeList.contains(attributeName)) {
return new JavaFxDefaultAttributeDescriptor(attributeName, null);
if (defaultAttributeList != null) {
if (defaultAttributeList.contains(attributeName)) {
return new JavaFxDefaultAttributeDescriptor(attributeName, getName());
}
final PsiMethod propertySetter = JavaFxPsiUtil.findPropertySetter(attributeName, context);
if (propertySetter != null) {
return new JavaFxStaticPropertyAttributeDescriptor(propertySetter, attributeName);
}
}
return null;
}
@@ -20,6 +20,7 @@ import com.intellij.xml.XmlNSDescriptor;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.javaFX.fxml.FxmlConstants;
import org.jetbrains.plugins.javaFX.fxml.JavaFxPsiUtil;
import java.util.ArrayList;
import java.util.List;
@@ -89,7 +90,7 @@ public class JavaFxPropertyElementDescriptor implements XmlElementDescriptor {
if (FxmlConstants.FX_DEFAULT_ELEMENTS.contains(name)) {
return new JavaFxDefaultPropertyElementDescriptor(name, childTag);
}
if (JavaFxClassBackedElementDescriptor.isClassTag(name)) {
if (JavaFxPsiUtil.isClassTag(name)) {
return new JavaFxClassBackedElementDescriptor(name, childTag);
}
else if (myPsiClass != null) {
@@ -144,7 +145,7 @@ public class JavaFxPropertyElementDescriptor implements XmlElementDescriptor {
if (field != null) {
return field;
}
return JavaFxClassBackedElementDescriptor.findPropertySetter(myName, myPsiClass);
return JavaFxPsiUtil.findPropertySetter(myName, myPsiClass);
}
@Override
@@ -32,27 +32,6 @@ class JavaFxFieldIdReferenceProvider extends JavaFxControllerBasedReferenceProvi
XmlAttributeValue xmlAttributeValue,
ProcessingContext context) {
final PsiField field = aClass.findFieldByName(xmlAttributeValue.getValue(), false);
return field == null ? PsiReference.EMPTY_ARRAY : new PsiReference[]{new JavaFxIdReference(xmlAttributeValue, field)};
}
private static class JavaFxIdReference extends PsiReferenceBase<XmlAttributeValue> {
private final PsiField myField;
public JavaFxIdReference(XmlAttributeValue xmlAttributeValue, PsiField field) {
super(xmlAttributeValue);
myField = field;
}
@Nullable
@Override
public PsiElement resolve() {
return myField;
}
@NotNull
@Override
public Object[] getVariants() {
return ArrayUtil.EMPTY_OBJECT_ARRAY;
}
return field == null ? PsiReference.EMPTY_ARRAY : new PsiReference[]{new PsiReferenceBase.Immediate<XmlAttributeValue>(xmlAttributeValue, field)};
}
}
@@ -0,0 +1,5 @@
<?import javafx.scene.layout.GridPane?>
<GridPane xmlns:fx="http://javafx.com/fxml">
<fx:define <error descr="Attribute GridPane.halignment is not allowed here">GridPane.halignment</error>="CENTER" />
<fx:define/>
</GridPane>
@@ -0,0 +1,5 @@
<?import javafx.scene.layout.GridPane?>
<GridPane xmlns:fx="http://javafx.com/fxml">
<fx:reference GridPane.halignment="CENTER" />
<fx:reference GridPane.halignment="CENTER" source="lbl"/>
</GridPane>
@@ -110,6 +110,14 @@ public class JavaFXHighlightingTest extends DaemonAnalyzerTestCase {
doTest();
}
public void testReferenceAttributes() throws Exception {
doTest();
}
public void testDefineAttributes() throws Exception {
doTest();
}
@NotNull
@Override
protected String getTestDataPath() {