javafx: wrap with fx:define fix (IDEA-104180)

This commit is contained in:
anna
2013-04-01 20:36:27 +02:00
parent 497644d544
commit a1da1fbceb
9 changed files with 115 additions and 22 deletions
@@ -55,6 +55,14 @@ public class JavaFXQuickfixTest extends LightCodeInsightFixtureTestCase {
doTest("Create Field 'btn'", ".java");
}
public void testWrapWithDefine() throws Exception {
final IntentionAction intention =
myFixture.getAvailableIntention("Wrap \"lb\" with fx:define", getTestName(true) + ".fxml");
assertNotNull(intention);
myFixture.launchAction(intention);
myFixture.checkResultByFile(getTestName(true) + "_after.fxml");
}
private void doTest(final String actionName, final String extension) throws Exception {
String path = getTestName(true) + ".fxml";
final IntentionAction intention =
@@ -0,0 +1,64 @@
/*
* 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.codeInsight.intentions;
import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.XmlElementFactory;
import com.intellij.psi.xml.XmlTag;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.javaFX.fxml.FxmlConstants;
/**
* User: anna
* Date: 4/1/13
*/
public class JavaFxWrapWithDefineIntention extends PsiElementBaseIntentionAction {
private final XmlTag myTag;
private final String myId;
public JavaFxWrapWithDefineIntention(@NotNull XmlTag tag, @NotNull String id) {
myTag = tag;
myId = id;
}
@NotNull
@Override
public String getFamilyName() {
return "Wrap with fx:define";
}
@Override
public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) {
setText("Wrap \"" + myId + "\" with fx:define");
return myTag.isValid();
}
@Override
public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) throws IncorrectOperationException {
final XmlTag tagFromText = XmlElementFactory.getInstance(project).createTagFromText("<" + FxmlConstants.FX_DEFINE + "/>");
tagFromText.addSubTag(myTag, true);
myTag.replace(tagFromText);
}
@Override
public boolean startInWriteAction() {
return true;
}
}
@@ -20,7 +20,6 @@ import com.intellij.psi.*;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlAttributeValue;
import com.intellij.psi.xml.XmlElement;
import com.intellij.psi.xml.XmlTag;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.javaFX.fxml.FxmlConstants;
import org.jetbrains.plugins.javaFX.fxml.JavaFxPsiUtil;
@@ -88,19 +87,6 @@ public class JavaFxDefaultAttributeDescriptor extends JavaFxPropertyAttributeDes
return "Unable to coerce '" + value + "' to " + tagClass.getQualifiedName() + ".";
}
}
} else if (FxmlConstants.FX_ELEMENT_SOURCE.equals(attributeName)) {
final XmlTag xmlTag = attribute.getParent();
if (xmlTag != null) {
final XmlTag referencedTag = JavaFxDefaultPropertyElementDescriptor.getReferencedTag(xmlTag);
if (referencedTag != null) {
if (referencedTag.getTextOffset() > xmlTag.getTextOffset()) {
return ((XmlAttributeValue)context).getValue() + " not found";
}
if (xmlTag.getParentTag() == referencedTag.getParentTag()) {
return "Duplicate child added";
}
}
}
}
}
}
@@ -137,7 +137,7 @@ public class JavaFxDefaultPropertyElementDescriptor implements XmlElementDescrip
}
@Nullable
protected static XmlTag getReferencedTag(XmlTag tag) {
public static XmlTag getReferencedTag(XmlTag tag) {
final String tagName = tag.getName();
if (FxmlConstants.FX_REFERENCE.equals(tagName) || FxmlConstants.FX_COPY.equals(tagName)) {
final XmlAttribute attribute = tag.getAttribute(FxmlConstants.FX_ELEMENT_SOURCE);
@@ -30,6 +30,7 @@ import com.intellij.psi.*;
import com.intellij.psi.presentation.java.SymbolPresentationUtil;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlAttributeValue;
import com.intellij.psi.xml.XmlTag;
import com.intellij.ui.ColorUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.ui.ColorIcon;
@@ -39,6 +40,8 @@ import org.jetbrains.plugins.javaFX.fxml.FxmlConstants;
import org.jetbrains.plugins.javaFX.fxml.JavaFxCommonClassNames;
import org.jetbrains.plugins.javaFX.fxml.JavaFxFileTypeFactory;
import org.jetbrains.plugins.javaFX.fxml.JavaFxPsiUtil;
import org.jetbrains.plugins.javaFX.fxml.codeInsight.intentions.JavaFxWrapWithDefineIntention;
import org.jetbrains.plugins.javaFX.fxml.descriptors.JavaFxDefaultPropertyElementDescriptor;
import javax.swing.*;
import java.awt.*;
@@ -72,12 +75,30 @@ public class JavaFxAnnotator implements Annotator {
attachColorIcon(element, holder, StringUtil.stripQuotesAroundValue(element.getText()));
}
} else if (element instanceof XmlAttribute) {
final String attributeName = ((XmlAttribute)element).getName();
if (!FxmlConstants.FX_DEFAULT_PROPERTIES.contains(attributeName) &&
!((XmlAttribute)element).isNamespaceDeclaration() &&
JavaFxPsiUtil.isReadOnly(attributeName, ((XmlAttribute)element).getParent())) {
final XmlAttribute attribute = (XmlAttribute)element;
final String attributeName = attribute.getName();
if (!FxmlConstants.FX_DEFAULT_PROPERTIES.contains(attributeName) &&
!attribute.isNamespaceDeclaration() &&
JavaFxPsiUtil.isReadOnly(attributeName, attribute.getParent())) {
holder.createErrorAnnotation(element.getNavigationElement(), "Property '" + attributeName + "' is read-only");
}
if (FxmlConstants.FX_ELEMENT_SOURCE.equals(attributeName)) {
final XmlAttributeValue valueElement = attribute.getValueElement();
if (valueElement != null) {
final XmlTag xmlTag = attribute.getParent();
if (xmlTag != null) {
final XmlTag referencedTag = JavaFxDefaultPropertyElementDescriptor.getReferencedTag(xmlTag);
if (referencedTag != null) {
if (referencedTag.getTextOffset() > xmlTag.getTextOffset()) {
holder.createErrorAnnotation(valueElement.getValueTextRange(), valueElement.getValue() + " not found");
} else if (xmlTag.getParentTag() == referencedTag.getParentTag()) {
final Annotation annotation = holder.createErrorAnnotation(valueElement.getValueTextRange(), "Duplicate child added");
annotation.registerFix(new JavaFxWrapWithDefineIntention(referencedTag, valueElement.getValue()));
}
}
}
}
}
}
}
@@ -1,5 +1,5 @@
<?import javafx.scene.control.Button?>
<fx:root type="javafx.scene.layout.GridPane" xmlns:fx="http://javafx.com/fxml">
<<error descr="Copy constructor not found for 'Button'">fx:copy</error> source=<error descr="btn not found">"btn"</error>/>
<<error descr="Copy constructor not found for 'Button'">fx:copy</error> source="<error descr="btn not found">btn</error>"/>
<Button fx:id="btn"/>
</fx:root>
@@ -1,12 +1,12 @@
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.control.Button?>
<GridPane xmlns:fx="http://javafx.com/fxml">
<fx:reference source=<error descr="btn not found">"btn"</error>/>
<fx:reference source="<error descr="btn not found">btn</error>"/>
<GridPane>
<Button fx:id="btn"/>
<Button fx:id="btn1"/>
</GridPane>
<fx:reference source="btn1"/>
<Button fx:id="btn2"/>
<fx:reference source=<error descr="Duplicate child added">"btn2"</error>/>
<fx:reference source="<error descr="Duplicate child added">btn2</error>"/>
</GridPane>
@@ -0,0 +1,6 @@
<?import javafx.scene.control.Label?>
<?import javafx.layout.*?>
<GridPane xmlns:fx="http://javafx.com/fxml">
<Label fx:id="lb"/>
<fx:reference source="l<caret>b"/>
</GridPane>
@@ -0,0 +1,8 @@
<?import javafx.scene.control.Label?>
<?import javafx.layout.*?>
<GridPane xmlns:fx="http://javafx.com/fxml">
<fx:define>
<Label fx:id="lb"/>
</fx:define>
<fx:reference source="lb"/>
</GridPane>