package org.jetbrains.android; import com.android.annotations.Nullable; import com.intellij.ide.TitledHandler; import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.xml.XmlAttribute; import com.intellij.psi.xml.XmlAttributeValue; import com.intellij.psi.xml.XmlFile; import com.intellij.psi.xml.XmlTag; import com.intellij.refactoring.rename.RenameDialog; import com.intellij.refactoring.rename.RenameHandler; import com.intellij.util.xml.DomElement; import com.intellij.util.xml.DomManager; import com.intellij.util.xml.GenericAttributeValue; import org.jetbrains.android.dom.manifest.Manifest; import org.jetbrains.android.dom.wrappers.ValueResourceElementWrapper; import org.jetbrains.android.facet.AndroidFacet; import org.jetbrains.android.facet.AndroidRootUtil; import org.jetbrains.android.util.AndroidBundle; import org.jetbrains.android.util.AndroidCommonUtils; import org.jetbrains.android.util.AndroidUtils; import org.jetbrains.annotations.NotNull; /** * @author Eugene.Kudelevsky */ public class AndroidRenameHandler implements RenameHandler, TitledHandler { @Override public boolean isAvailableOnDataContext(DataContext dataContext) { final Editor editor = CommonDataKeys.EDITOR.getData(dataContext); if (editor == null) { return false; } final PsiFile file = CommonDataKeys.PSI_FILE.getData(dataContext); if (file == null) { return false; } if (AndroidUsagesTargetProvider.findValueResourceTagInContext(editor, file) != null) { return true; } final Project project = CommonDataKeys.PROJECT.getData(dataContext); if (project == null) { return false; } final PsiElement element = CommonDataKeys.PSI_ELEMENT.getData(dataContext); return element != null && isPackageAttributeInManifest(project, element); } @Override public boolean isRenaming(DataContext dataContext) { return isAvailableOnDataContext(dataContext); } @Override public void invoke(@NotNull Project project, Editor editor, PsiFile file, DataContext dataContext) { if (file == null || editor == null) { return; } final XmlTag tag = AndroidUsagesTargetProvider.findValueResourceTagInContext(editor, file); if (tag != null) { performValueResourceRenaming(project, editor, dataContext, tag); } else { performApplicationPackageRenaming(project, editor, dataContext); } } private static void performValueResourceRenaming(Project project, Editor editor, DataContext dataContext, XmlTag tag) { final XmlAttribute nameAttribute = tag.getAttribute("name"); if (nameAttribute == null) { return; } final XmlAttributeValue attributeValue = nameAttribute.getValueElement(); if (attributeValue == null) { return; } RenameDialog.showRenameDialog(dataContext, new RenameDialog(project, new ValueResourceElementWrapper(attributeValue), null, editor)); } @Override public void invoke(@NotNull Project project, @NotNull PsiElement[] elements, DataContext dataContext) { final Editor editor = CommonDataKeys.EDITOR.getData(dataContext); if (editor == null) { return; } final PsiFile file = CommonDataKeys.PSI_FILE.getData(dataContext); if (file == null) { return; } invoke(project, editor, file, dataContext); } @Override public String getActionTitle() { return "Rename Android value resource"; } static boolean isPackageAttributeInManifest(@NotNull Project project, @Nullable PsiElement element) { final PsiFile psiFile = element.getContainingFile(); if (!(psiFile instanceof XmlFile)) { return false; } final AndroidFacet facet = AndroidFacet.getInstance(psiFile); if (facet == null) { return false; } final VirtualFile vFile = psiFile.getVirtualFile(); if (vFile == null || !vFile.equals(AndroidRootUtil.getManifestFile(facet))) { return false; } if (!(element instanceof XmlAttributeValue)) { return false; } final PsiElement parent = element.getParent(); if (!(parent instanceof XmlAttribute)) { return false; } final GenericAttributeValue attrValue = DomManager.getDomManager(project).getDomElement((XmlAttribute)parent); if (attrValue == null) { return false; } final DomElement parentDomElement = attrValue.getParent(); return parentDomElement instanceof Manifest && attrValue.equals(((Manifest)parentDomElement).getPackage()); } private static void performApplicationPackageRenaming(@NotNull Project project, @NotNull Editor editor, @NotNull DataContext context) { PsiElement element = CommonDataKeys.PSI_ELEMENT.getData(context); if (!(element instanceof XmlAttributeValue)) { return; } final Module module = ModuleUtilCore.findModuleForPsiElement(element); if (module == null) { return; } RenameDialog.showRenameDialog(context, new RenameDialog(project, element, null, editor) { @NotNull @Override protected String getLabelText() { return "Rename Android application package of module '" + module.getName() + "' to:"; } @Override protected void canRun() throws ConfigurationException { final String name = getNewName(); if (name.length() == 0) { throw new ConfigurationException(AndroidBundle.message("specify.package.name.error")); } if (!AndroidUtils.isValidAndroidPackageName(name)) { throw new ConfigurationException(AndroidBundle.message("not.valid.package.name.error", name)); } if (!AndroidCommonUtils.contains2Identifiers(name)) { throw new ConfigurationException(AndroidBundle.message("package.name.must.contain.2.ids.error")); } super.canRun(); } }); } }