package com.intellij.lang.javascript.validation.fixes; import com.intellij.codeInsight.FileModificationService; import com.intellij.codeInsight.template.Template; import com.intellij.codeInsight.template.TemplateManager; import com.intellij.javascript.flex.FlexPredefinedTagNames; import com.intellij.javascript.flex.mxml.FlexCommonTypeNames; import com.intellij.javascript.flex.mxml.MxmlJSClass; import com.intellij.lang.javascript.JSBundle; import com.intellij.lang.javascript.JavaScriptSupportLoader; import com.intellij.lang.javascript.psi.JSReferenceExpression; import com.intellij.lang.javascript.psi.ecmal4.XmlBackedJSClassFactory; import com.intellij.openapi.application.WriteAction; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.XmlElementFactory; import com.intellij.psi.xml.XmlAttribute; import com.intellij.psi.xml.XmlFile; import com.intellij.psi.xml.XmlTag; import com.intellij.util.IncorrectOperationException; import com.intellij.xml.XmlElementDescriptor; import org.jetbrains.annotations.NotNull; public class CreateEventMetadataByMxmlAttributeFix extends BaseCreateFix { private final String myEventName; public CreateEventMetadataByMxmlAttributeFix(final String eventName) { myEventName = eventName; } @NotNull public String getName() { return JSBundle.message("declare.event.0", myEventName); } @Override protected void applyFix(final Project project, final PsiElement psiElement, PsiFile file, Editor editor) { assert psiElement instanceof XmlAttribute; final XmlTag tag = (XmlTag)psiElement.getParent(); final XmlElementDescriptor descriptor = tag.getDescriptor(); PsiElement type = descriptor == null ? null : descriptor.getDeclaration(); if (type == null) { return; // can not resolve } if (!FileModificationService.getInstance().preparePsiElementForWrite(type)) { return; } file = type.getContainingFile(); editor = getEditor(project, file); if (editor == null) { return; } final boolean addingToMxml = type instanceof XmlFile; final TemplateManager templateManager = TemplateManager.getInstance(project); final Template template = templateManager.createTemplate("", ""); template.setToReformat(true); if (addingToMxml) { template.addTextSegment("\n"); } template.addTextSegment("[Event(name=\"" + myEventName + "\", type=\""); template.addVariable(new MyExpression(FlexCommonTypeNames.FLASH_EVENT_FQN), true); template.addTextSegment("\")]"); if (!addingToMxml) { template.addTextSegment("\n"); } final int offset; if (addingToMxml) { XmlTag metadataTag = WriteAction.compute(() -> createOrGetMetadataTag((XmlFile)type)); offset = metadataTag.getValue().getTextRange().getStartOffset(); } else { offset = type.getTextRange().getStartOffset(); } navigate(project, editor, offset, file.getVirtualFile()); templateManager.startTemplate(editor, template); } protected void buildTemplate(final Template template, final JSReferenceExpression referenceExpression, final boolean staticContext, final PsiFile file, final PsiElement anchorParent) { assert false; // not used } private static XmlTag createOrGetMetadataTag(final XmlFile xmlFile) throws IncorrectOperationException { assert JavaScriptSupportLoader.isFlexMxmFile(xmlFile) : xmlFile; final XmlTag rootTag = XmlBackedJSClassFactory.getRootTag(xmlFile); final XmlTag[] metadataTags = MxmlJSClass.findLanguageSubTags(rootTag, FlexPredefinedTagNames.METADATA); return metadataTags.length > 0 ? metadataTags[0] : createMetadataTag(rootTag); } private static XmlTag createMetadataTag(final XmlTag rootTag) { String prefix = rootTag.getPrefixByNamespace(JavaScriptSupportLoader.MXML_URI3); if (prefix == null) prefix = rootTag.getPrefixByNamespace(JavaScriptSupportLoader.MXML_URI); if (prefix == null) prefix = ""; final String qName = prefix + (prefix.isEmpty() ? "" : ":") + FlexPredefinedTagNames.METADATA; final XmlTag newTag = XmlElementFactory.getInstance(rootTag.getProject()).createTagFromText("<" + qName + ">\n</" + qName + ">"); final XmlTag[] subTags = rootTag.getSubTags(); return subTags.length > 0 && MxmlJSClass.isFxLibraryTag(subTags[0]) ? (XmlTag)rootTag.addAfter(newTag, subTags[0]) : rootTag.addSubTag(newTag, true); } }