@Nullable private static XmlTag getAnchor( @NotNull XmlTag contextTag, Editor editor, XmlElementDescriptor selected) { XmlContentDFA contentDFA = XmlContentDFA.getContentDFA(contextTag); int offset = editor.getCaretModel().getOffset(); if (contentDFA == null) { return null; } XmlTag anchor = null; boolean previousPositionIsPossible = true; for (XmlTag subTag : contextTag.getSubTags()) { if (contentDFA.getPossibleElements().contains(selected)) { if (subTag.getTextOffset() > offset) { break; } anchor = subTag; previousPositionIsPossible = true; } else { previousPositionIsPossible = false; } contentDFA.transition(subTag); } return previousPositionIsPossible ? null : anchor; }
@Override public void annotate(@NotNull final PsiElement element, @NotNull AnnotationHolder holder) { final PsiFile containingFile = element.getContainingFile(); if (!JavaFxFileTypeFactory.isFxml(containingFile)) return; if (element instanceof XmlAttributeValue) { final String value = ((XmlAttributeValue) element).getValue(); if (!JavaFxPsiUtil.isExpressionBinding(value) && !JavaFxPsiUtil.isIncorrectExpressionBinding(value)) { final PsiReference[] references = element.getReferences(); for (PsiReference reference : references) { if (reference instanceof JavaFxColorReference) { attachColorIcon(element, holder, StringUtil.unquoteString(element.getText())); continue; } final PsiElement resolve = reference.resolve(); if (resolve instanceof PsiMember) { if (!JavaFxPsiUtil.isVisibleInFxml((PsiMember) resolve)) { final String symbolPresentation = "'" + SymbolPresentationUtil.getSymbolPresentableText(resolve) + "'"; final Annotation annotation = holder.createErrorAnnotation( element, symbolPresentation + (resolve instanceof PsiClass ? " should be public" : " should be public or annotated with @FXML")); if (!(resolve instanceof PsiClass)) { annotation.registerUniversalFix( new AddAnnotationFix( JavaFxCommonNames.JAVAFX_FXML_ANNOTATION, (PsiMember) resolve, ArrayUtil.EMPTY_STRING_ARRAY), null, null); } } } } } } else if (element instanceof XmlAttribute) { final XmlAttribute attribute = (XmlAttribute) element; final String attributeName = attribute.getName(); if (!FxmlConstants.FX_BUILT_IN_ATTRIBUTES.contains(attributeName) && !attribute.isNamespaceDeclaration() && JavaFxPsiUtil.isReadOnly(attributeName, attribute.getParent())) { holder.createErrorAnnotation( element.getNavigationElement(), "Property '" + attributeName + "' is read-only"); } if (FxmlConstants.SOURCE.equals(attributeName)) { final XmlAttributeValue valueElement = attribute.getValueElement(); if (valueElement != null) { final XmlTag xmlTag = attribute.getParent(); if (xmlTag != null) { final XmlTag referencedTag = JavaFxBuiltInTagDescriptor.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())); } } } } } } else if (element instanceof XmlTag) { if (FxmlConstants.FX_SCRIPT.equals(((XmlTag) element).getName())) { final XmlTagValue tagValue = ((XmlTag) element).getValue(); if (!StringUtil.isEmptyOrSpaces(tagValue.getText())) { final List<String> langs = JavaFxPsiUtil.parseInjectedLanguages((XmlFile) element.getContainingFile()); if (langs.isEmpty()) { final ASTNode openTag = element.getNode().findChildByType(XmlTokenType.XML_NAME); final Annotation annotation = holder.createErrorAnnotation( openTag != null ? openTag.getPsi() : element, "Page language not specified."); annotation.registerFix(new JavaFxInjectPageLanguageIntention()); } } } } }