package org.jetbrains.android.refactoring; import com.intellij.codeInsight.TargetElementUtilBase; import com.intellij.lang.Language; import com.intellij.lang.refactoring.InlineActionHandler; import com.intellij.lang.xml.XMLLanguage; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiReference; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtilBase; import com.intellij.psi.xml.XmlFile; import com.intellij.psi.xml.XmlTag; import com.intellij.psi.xml.XmlToken; import com.intellij.util.xml.DomManager; import org.jetbrains.android.dom.converters.AndroidResourceReferenceBase; import org.jetbrains.android.dom.layout.LayoutDomFileDescription; import org.jetbrains.android.dom.wrappers.ResourceElementWrapper; import org.jetbrains.android.facet.AndroidFacet; import org.jetbrains.android.util.AndroidBundle; import org.jetbrains.android.util.ErrorReporter; import org.jetbrains.android.util.HintBasedErrorReporter; import org.jetbrains.android.util.ProjectBasedErrorReporter; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; /** * @author Eugene.Kudelevsky */ public class AndroidInlineLayoutHandler extends InlineActionHandler { private static AndroidInlineTestConfig ourTestConfig; @TestOnly public static void setTestConfig(@Nullable AndroidInlineTestConfig testConfig) { ourTestConfig = testConfig; } @Override public boolean isEnabledForLanguage(Language l) { return l == XMLLanguage.INSTANCE; } @Override public boolean canInlineElement(PsiElement element) { return false; } @Override public boolean canInlineElementInEditor(PsiElement element, Editor editor) { if (element instanceof ResourceElementWrapper) { element = ((ResourceElementWrapper)element).getWrappee(); } if (element instanceof XmlFile) { if (AndroidFacet.getInstance(element) == null || ((XmlFile)element).getRootTag() == null) { return false; } return DomManager.getDomManager(element.getProject()).getDomFileDescription((XmlFile)element) instanceof LayoutDomFileDescription; } return getLayoutUsageDataFromContext(editor) != null; } @Nullable private static LayoutUsageData getLayoutUsageDataFromContext(Editor editor) { if (editor == null) { return null; } final PsiElement element = PsiUtilBase.getElementAtCaret(editor); if (!(element instanceof XmlToken) || AndroidFacet.getInstance(element) == null) { return null; } final XmlTag tag = PsiTreeUtil.getParentOfType(element, XmlTag.class); return tag != null ? AndroidInlineUtil.getLayoutUsageData(tag) : null; } @Override public void inlineElement(Project project, Editor editor, PsiElement element) { if (element instanceof ResourceElementWrapper) { element = ((ResourceElementWrapper)element).getWrappee(); } if (element instanceof XmlFile) { PsiElement usageElement = null; if (editor != null) { final PsiReference reference = TargetElementUtilBase.findReference(editor); if (reference != null) { usageElement = reference.getElement(); } } AndroidInlineUtil.doInlineLayoutFile(project, (XmlFile)element, usageElement, ourTestConfig); return; } final LayoutUsageData usageData = getLayoutUsageDataFromContext(editor); assert usageData != null; final AndroidResourceReferenceBase ref = usageData.getReference(); final PsiElement[] elements = ref.computeTargetElements(); final ErrorReporter errorReporter = editor != null ? new HintBasedErrorReporter(editor) : new ProjectBasedErrorReporter(project); final String title = AndroidBundle.message("android.inline.layout.title"); if (elements.length == 0) { final String resName = ref.getResourceValue().getResourceName(); final String message = resName != null ? "Cannot find layout '" + resName + "'" : "Error: cannot find the layout"; errorReporter.report(message, title); return; } if (elements.length > 1) { errorReporter.report("Error: unambiguous reference", title); return; } final PsiElement resolvedElement = elements[0]; if (!(resolvedElement instanceof XmlFile)) { errorReporter.report("Cannot inline reference '" + ref.getValue() + "'", title); return; } AndroidInlineUtil.doInlineLayoutFile(project, (XmlFile)resolvedElement, ref.getElement(), ourTestConfig); } }