javafx: static properties in attrs and elements

This commit is contained in:
anna
2013-01-17 16:11:10 +01:00
parent de23b4db0d
commit 2baab02ba6
13 changed files with 329 additions and 37 deletions
@@ -37,7 +37,4 @@ public class FxmlConstants {
@NonNls public static final String FX_SCRIPT = "fx:script";
public static final List<String> FX_DEFAULT_PROPERTIES = Arrays.asList(FX_ID, FX_CONTROLLER, VALUE, FX_VALUE, FX_FACTORY, FX_INCLUDE, FX_REFERENCE, FX_COPY, FX_DEFINE, FX_SCRIPT);
@NonNls public static final String JAVAFX_ANCHOR_PANE = "javafx.scene.layout.AnchorPane";
@NonNls public static final String JAVAFX_EVENT = "javafx.event.Event";
}
@@ -2,7 +2,6 @@ package org.jetbrains.plugins.javaFX.fxml;
import com.intellij.codeInsight.daemon.Validator;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.xml.*;
@@ -29,13 +28,16 @@ public class JavaFXNSDescriptor implements XmlNSDescriptor, Validator<XmlDocumen
public XmlElementDescriptor getElementDescriptor(@NotNull XmlTag tag) {
final String name = tag.getName();
if (StringUtil.isCapitalized(name)) {
if (JavaFxClassBackedElementDescriptor.isClassTag(name)) {
return new JavaFxClassBackedElementDescriptor(name, tag);
}
else {
XmlTag parentTag = tag.getParentTag();
final XmlTag parentTag = tag.getParentTag();
if (parentTag != null) {
return new JavaFxClassBackedElementDescriptor(parentTag.getName(), parentTag).getElementDescriptor(tag, parentTag);
final XmlElementDescriptor descriptor = parentTag.getDescriptor();
if (descriptor != null) {
return descriptor.getElementDescriptor(tag, parentTag);
}
}
}
return null;
@@ -76,7 +76,7 @@ public class JavaFxClassBackedElementDescriptor implements XmlElementDescriptor,
XmlElementDescriptor descriptor = context.getDescriptor();
if (descriptor instanceof JavaFxClassBackedElementDescriptor) {
} else if (descriptor instanceof JavaFxListPropertyElementDescriptor) {
} else if (descriptor instanceof JavaFxPropertyElementDescriptor) {
}
}
@@ -87,14 +87,27 @@ public class JavaFxClassBackedElementDescriptor implements XmlElementDescriptor,
@Override
public XmlElementDescriptor getElementDescriptor(XmlTag childTag, XmlTag contextTag) {
final String name = childTag.getName();
if (StringUtil.isCapitalized(name)) {
if (isClassTag(name)) {
return new JavaFxClassBackedElementDescriptor(name, childTag);
}
else {
return myPsiClass != null ? new JavaFxListPropertyElementDescriptor(myPsiClass, name) : null;
final String shortName = StringUtil.getShortName(name);
if (!name.equals(shortName)) { //static property
final PsiMethod propertySetter = findPropertySetter(name, childTag);
if (propertySetter != null) {
return new JavaFxPropertyElementDescriptor(propertySetter.getContainingClass(), shortName);
}
return null;
}
return myPsiClass != null ? new JavaFxPropertyElementDescriptor(myPsiClass, name) : null;
}
}
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) {
if (context != null) {
@@ -107,8 +120,8 @@ public class JavaFxClassBackedElementDescriptor implements XmlElementDescriptor,
if (field.hasModifierProperty(PsiModifier.STATIC)) continue;
final PsiType fieldType = field.getType();
if (PropertyUtil.findPropertyGetter(myPsiClass, field.getName(), false, true) != null &&
InheritanceUtil.isInheritor(fieldType, "javafx.beans.property.Property")) {//todo filter
simpleAttrs.add(new JavaFxPropertyBackedAttributeDescriptor(field.getName(), myPsiClass));
InheritanceUtil.isInheritor(fieldType, JavaFxCommonClassNames.JAVAFX_BEANS_PROPERTY_PROPERTY)) {//todo filter
simpleAttrs.add(new JavaFxPropertyAttributeDescriptor(field.getName(), myPsiClass));
}
}
}
@@ -121,7 +134,19 @@ public class JavaFxClassBackedElementDescriptor implements XmlElementDescriptor,
@Nullable
@Override
public XmlAttributeDescriptor getAttributeDescriptor(@NonNls String attributeName, @Nullable XmlTag context) {
return new JavaFxPropertyBackedAttributeDescriptor(attributeName, (PsiClass)getDeclaration());
if (myPsiClass == null) return null;
if (myPsiClass.findFieldByName(attributeName, true) == null) {
if (FxmlConstants.FX_DEFAULT_PROPERTIES.contains(attributeName)){
return new JavaFxDefaultAttributeDescriptor(attributeName);
} else {
final PsiMethod propertySetter = findPropertySetter(attributeName, context);
if (propertySetter != null) {
return new JavaFxStaticPropertyAttributeDescriptor(propertySetter, attributeName);
}
return null;
}
}
return new JavaFxPropertyAttributeDescriptor(attributeName, myPsiClass);
}
@Nullable
@@ -190,14 +215,8 @@ public class JavaFxClassBackedElementDescriptor implements XmlElementDescriptor,
private void validateTagAccordingToFieldType(XmlTag context, XmlTag parentTag, ValidationHost host) {
if (myPsiClass != null && myPsiClass.isValid()) {
if (parentTag == null) {
if (!InheritanceUtil.isInheritor(myPsiClass, FxmlConstants.JAVAFX_ANCHOR_PANE)) {
host.addMessage(context.getNavigationElement(), HighlightUtil.formatClass(myPsiClass) + " cannot be cast to " + FxmlConstants.JAVAFX_ANCHOR_PANE, ValidationHost.ErrorType.ERROR);
}
return;
}
final XmlElementDescriptor descriptor = parentTag.getDescriptor();
if (descriptor instanceof JavaFxListPropertyElementDescriptor) {
final XmlElementDescriptor descriptor = parentTag != null ? parentTag.getDescriptor() : null;
if (descriptor instanceof JavaFxPropertyElementDescriptor) {
final PsiElement declaration = descriptor.getDeclaration();
if (declaration instanceof PsiField) {
final PsiType type = ((PsiField)declaration).getType();
@@ -218,4 +237,25 @@ 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 =
findPsiClass(packageName, JavaFXNSDescriptor.parseImports((XmlFile)context.getContainingFile()), context, context.getProject());
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;
}
}
@@ -0,0 +1,29 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.plugins.javaFX.fxml;
import org.jetbrains.annotations.NonNls;
/**
* User: anna
* Date: 1/16/13
*/
public class JavaFxCommonClassNames {
@NonNls public static final String JAVAFX_BEANS_PROPERTY_PROPERTY = "javafx.beans.property.Property";
@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";
}
@@ -0,0 +1,103 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.plugins.javaFX.fxml;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.psi.PsiElement;
import com.intellij.psi.xml.XmlElement;
import com.intellij.util.ArrayUtil;
import com.intellij.xml.XmlAttributeDescriptor;
import org.jetbrains.annotations.Nullable;
/**
* User: anna
* Date: 1/10/13
*/
public class JavaFxDefaultAttributeDescriptor implements XmlAttributeDescriptor {
private static final Logger LOG = Logger.getInstance("#" + JavaFxDefaultAttributeDescriptor.class.getName());
private final String myName;
public JavaFxDefaultAttributeDescriptor(String name) {
myName = name;
}
@Override
public boolean isRequired() {
return false;
}
@Override
public boolean isFixed() {
return false;
}
@Override
public boolean hasIdType() {
return myName.equals(FxmlConstants.FX_ID);
}
@Override
public boolean hasIdRefType() {
return false;
}
@Nullable
@Override
public String getDefaultValue() {
return null;
}
@Override
public boolean isEnumerated() {
return false;
}
@Nullable
@Override
public String[] getEnumeratedValues() {
return new String[0];
}
@Nullable
@Override
public String validateValue(XmlElement context, String value) {
return null;
}
@Override
public PsiElement getDeclaration() {
return null;
}
@Override
public String getName(PsiElement context) {
return getName();
}
@Override
public String getName() {
return myName;
}
@Override
public void init(PsiElement element) {}
@Override
public Object[] getDependences() {
return ArrayUtil.EMPTY_OBJECT_ARRAY;
}
}
@@ -66,7 +66,7 @@ public class JavaFxEventHandlerReference extends PsiReferenceBase<XmlAttributeVa
final PsiParameter[] parameters = psiMethod.getParameterList().getParameters();
if (parameters.length == 1) {
final PsiType parameterType = parameters[0].getType();
if (parameterType.equalsToText(FxmlConstants.JAVAFX_EVENT)) {
if (parameterType.equalsToText(JavaFxCommonClassNames.JAVAFX_EVENT)) {
return true;
}
}
@@ -93,7 +93,7 @@ public class JavaFxEventHandlerReference extends PsiReferenceBase<XmlAttributeVa
}
private static String getHandlerSignature(JavaFxEventHandlerReference ref) {
return "public void " + ref.getElement().getValue().substring(1) + "(" + FxmlConstants.JAVAFX_EVENT + " e)";
return "public void " + ref.getElement().getValue().substring(1) + "(" + JavaFxCommonClassNames.JAVAFX_EVENT + " e)";
}
@NotNull
@@ -11,11 +11,11 @@ import org.jetbrains.annotations.Nullable;
* User: anna
* Date: 1/10/13
*/
public class JavaFxPropertyBackedAttributeDescriptor implements XmlAttributeDescriptor {
public class JavaFxPropertyAttributeDescriptor implements XmlAttributeDescriptor {
private final String myName;
private final PsiClass myPsiClass;
public JavaFxPropertyBackedAttributeDescriptor(String name, PsiClass psiClass) {
public JavaFxPropertyAttributeDescriptor(String name, PsiClass psiClass) {
myName = name;
myPsiClass = psiClass;
}
@@ -1,8 +1,8 @@
package org.jetbrains.plugins.javaFX.fxml;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiField;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlTag;
import com.intellij.util.ArrayUtil;
@@ -17,11 +17,11 @@ import org.jetbrains.annotations.Nullable;
* User: anna
* Date: 1/10/13
*/
public class JavaFxListPropertyElementDescriptor implements XmlElementDescriptor {
public class JavaFxPropertyElementDescriptor implements XmlElementDescriptor {
private final PsiClass myPsiClass;
private final String myName;
public JavaFxListPropertyElementDescriptor(PsiClass psiClass, String name) {
public JavaFxPropertyElementDescriptor(PsiClass psiClass, String name) {
myPsiClass = psiClass;
myName = name;
}
@@ -47,12 +47,13 @@ public class JavaFxListPropertyElementDescriptor implements XmlElementDescriptor
@Override
public XmlElementDescriptor getElementDescriptor(XmlTag childTag, XmlTag contextTag) {
final String name = childTag.getName();
if (StringUtil.isCapitalized(name)) {
if (JavaFxClassBackedElementDescriptor.isClassTag(name)) {
return new JavaFxClassBackedElementDescriptor(name, childTag);
}
else {
return myPsiClass != null ? new JavaFxListPropertyElementDescriptor(myPsiClass, name) : null;
else if (myPsiClass != null) {
return new JavaFxPropertyElementDescriptor(myPsiClass, name);
}
return null;
}
@Override
@@ -96,7 +97,12 @@ public class JavaFxListPropertyElementDescriptor implements XmlElementDescriptor
@Override
public PsiElement getDeclaration() {
return myPsiClass.findFieldByName(myName, true);
if (myPsiClass == null) return null;
final PsiField field = myPsiClass.findFieldByName(myName, true);
if (field != null) {
return field;
}
return JavaFxClassBackedElementDescriptor.findPropertySetter(myName, myPsiClass);
}
@Override
@@ -0,0 +1,105 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.plugins.javaFX.fxml;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.xml.XmlElement;
import com.intellij.util.ArrayUtil;
import com.intellij.xml.XmlAttributeDescriptor;
import org.jetbrains.annotations.Nullable;
/**
* User: anna
* Date: 1/10/13
*/
public class JavaFxStaticPropertyAttributeDescriptor implements XmlAttributeDescriptor {
private static final Logger LOG = Logger.getInstance("#" + JavaFxStaticPropertyAttributeDescriptor.class.getName());
private final PsiMethod mySetter;
private final String myName;
public JavaFxStaticPropertyAttributeDescriptor(PsiMethod setter, String name) {
mySetter = setter;
myName = name;
}
@Override
public boolean isRequired() {
return false;
}
@Override
public boolean isFixed() {
return false;
}
@Override
public boolean hasIdType() {
return false;
}
@Override
public boolean hasIdRefType() {
return false;
}
@Nullable
@Override
public String getDefaultValue() {
return null;
}
@Override
public boolean isEnumerated() {
return false;
}
@Nullable
@Override
public String[] getEnumeratedValues() {
return new String[0];
}
@Nullable
@Override
public String validateValue(XmlElement context, String value) {
return null;
}
@Override
public PsiElement getDeclaration() {
return mySetter;
}
@Override
public String getName(PsiElement context) {
return getName();
}
@Override
public String getName() {
return myName;
}
@Override
public void init(PsiElement element) {}
@Override
public Object[] getDependences() {
return ArrayUtil.EMPTY_OBJECT_ARRAY;
}
}
@@ -1,3 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import java.util.*?>
<<error descr="java.util.ArrayList cannot be cast to javafx.scene.layout.AnchorPane">ArrayList</error> xmlns:fx="http://javafx.com/fxml"/>
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.*?>
<AnchorPane id="AnchorPane" maxHeight="-Infinity" maxWidth="-Infinity" unknownAttr="val" xmlns:fx="http://javafx.com/fxml">
<AnchorPane id="AnchorPane" maxHeight="-Infinity" maxWidth="-Infinity" <error descr="Attribute unknownAttr is not allowed here">unknownAttr</error>="val" xmlns:fx="http://javafx.com/fxml">
<children>
<AnchorPane id="anchorPane2" prefHeight="300.0" AnchorPane.bottomAnchor="200.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.*?>
<AnchorPane xmlns:fx="http://javafx.com/fxml">
<children>
<AnchorPane AnchorPane.leftAnchor="0.0" <error descr="Attribute AnchorPane.leftAnchor1 is not allowed here">AnchorPane.leftAnchor1</error>="0.0">
<AnchorPane.bottomAnchor>200</AnchorPane.bottomAnchor>
<<error descr="Element AnchorPane1.bottomAnchor is not allowed here">AnchorPane1.bottomAnchor</error>>200</<error descr="Element AnchorPane1.bottomAnchor is not allowed here">AnchorPane1.bottomAnchor</error>>
<GridPane.rowIndex>0</GridPane.rowIndex>
</AnchorPane>
</children>
</AnchorPane>
@@ -32,7 +32,7 @@ public class JavaFXHighlightingTest extends DaemonAnalyzerTestCase {
doTest();
}
public void testRootTagConstraint() throws Exception {
public void testStaticProperties() throws Exception {
doTest();
}