blob: 84284d43e194314c7b8a6410bfcc5022036dceea [file] [log] [blame]
package org.jetbrains.android;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.search.ProjectScope;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlAttributeValue;
import com.intellij.psi.xml.XmlTag;
import com.intellij.refactoring.safeDelete.JavaSafeDeleteProcessor;
import com.intellij.refactoring.safeDelete.NonCodeUsageSearchInfo;
import com.intellij.refactoring.safeDelete.SafeDeleteProcessorDelegateBase;
import com.intellij.usageView.UsageInfo;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.android.dom.AndroidAttributeValue;
import org.jetbrains.android.dom.manifest.*;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.android.util.AndroidUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* @author Eugene.Kudelevsky
*/
public class AndroidSafeDeleteProcessorDelegate extends SafeDeleteProcessorDelegateBase {
private final JavaSafeDeleteProcessor myBaseHandler = new JavaSafeDeleteProcessor();
private JavaSafeDeleteProcessor getBaseHandler() {
return myBaseHandler;
}
@Override
public boolean handlesElement(PsiElement element) {
return getBaseHandler().handlesElement(element) &&
element instanceof PsiClass &&
AndroidFacet.getInstance(element) != null &&
isAndroidComponent((PsiClass)element);
}
private static boolean isAndroidComponent(@NotNull PsiClass c) {
final String[] componentClasses =
{AndroidUtils.ACTIVITY_BASE_CLASS_NAME, AndroidUtils.SERVICE_CLASS_NAME, AndroidUtils.RECEIVER_CLASS_NAME,
AndroidUtils.PROVIDER_CLASS_NAME};
final Project project = c.getProject();
final JavaPsiFacade facade = JavaPsiFacade.getInstance(project);
for (String componentClassName : componentClasses) {
final PsiClass componentClass = facade.findClass(componentClassName, ProjectScope.getAllScope(project));
if (componentClass != null && c.isInheritor(componentClass, true)) {
return true;
}
}
return false;
}
@Override
public NonCodeUsageSearchInfo findUsages(PsiElement element, PsiElement[] allElementsToDelete, List<UsageInfo> result) {
final ArrayList<UsageInfo> usages = new ArrayList<UsageInfo>();
final NonCodeUsageSearchInfo info = getBaseHandler().findUsages(element, allElementsToDelete, usages);
if (info == null) {
return info;
}
assert element instanceof PsiClass;
final PsiClass componentClass = (PsiClass)element;
final AndroidAttributeValue<PsiClass> declaration = findComponentDeclarationInManifest(componentClass);
if (declaration == null) {
return info;
}
final XmlAttributeValue declarationAttributeValue = declaration.getXmlAttributeValue();
for (UsageInfo usage : usages) {
if (declarationAttributeValue != usage.getElement()) {
result.add(usage);
}
}
return info;
}
@Override
public Collection<? extends PsiElement> getElementsToSearch(PsiElement element,
@Nullable Module module,
Collection<PsiElement> allElementsToDelete) {
return getBaseHandler().getElementsToSearch(element, module, allElementsToDelete);
}
@Override
public Collection<PsiElement> getAdditionalElementsToDelete(PsiElement element,
Collection<PsiElement> allElementsToDelete,
boolean askUser) {
return getBaseHandler().getAdditionalElementsToDelete(element, allElementsToDelete, askUser);
}
@Override
public Collection<String> findConflicts(PsiElement element, PsiElement[] allElementsToDelete) {
return getBaseHandler().findConflicts(element, allElementsToDelete);
}
@Override
public UsageInfo[] preprocessUsages(Project project, UsageInfo[] usages) {
return usages;
}
@Override
public void prepareForDeletion(PsiElement element) throws IncorrectOperationException {
assert element instanceof PsiClass;
final AndroidAttributeValue<PsiClass> declaration = findComponentDeclarationInManifest((PsiClass)element);
if (declaration != null) {
final XmlAttribute declarationAttr = declaration.getXmlAttribute();
if (declarationAttr != null) {
final XmlTag declarationTag = declarationAttr.getParent();
if (declarationTag != null) {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
declarationTag.delete();
}
});
}
}
}
getBaseHandler().prepareForDeletion(element);
}
@Nullable
private static AndroidAttributeValue<PsiClass> findComponentDeclarationInManifest(@NotNull PsiClass aClass) {
final AndroidFacet facet = AndroidFacet.getInstance(aClass);
if (facet == null) {
return null;
}
final Manifest manifest = facet.getManifest();
if (manifest == null) {
return null;
}
final Application application = manifest.getApplication();
if (application == null) {
return null;
}
if (isInheritor(aClass, AndroidUtils.ACTIVITY_BASE_CLASS_NAME)) {
for (Activity activity : application.getActivities()) {
final AndroidAttributeValue<PsiClass> activityClass = activity.getActivityClass();
if (activityClass.getValue() == aClass) {
return activityClass;
}
}
}
else if (isInheritor(aClass, AndroidUtils.SERVICE_CLASS_NAME)) {
for (Service service : application.getServices()) {
final AndroidAttributeValue<PsiClass> serviceClass = service.getServiceClass();
if (serviceClass.getValue() == aClass) {
return serviceClass;
}
}
}
else if (isInheritor(aClass, AndroidUtils.RECEIVER_CLASS_NAME)) {
for (Receiver receiver : application.getReceivers()) {
final AndroidAttributeValue<PsiClass> receiverClass = receiver.getReceiverClass();
if (receiverClass.getValue() == aClass) {
return receiverClass;
}
}
}
else if (isInheritor(aClass, AndroidUtils.PROVIDER_CLASS_NAME)) {
for (Provider provider : application.getProviders()) {
final AndroidAttributeValue<PsiClass> providerClass = provider.getProviderClass();
if (providerClass.getValue() == aClass) {
return providerClass;
}
}
}
return null;
}
private static boolean isInheritor(@NotNull PsiClass aClass, @NotNull String baseClassQName) {
final Project project = aClass.getProject();
final PsiClass baseClass = JavaPsiFacade.getInstance(project).findClass(baseClassQName, ProjectScope.getAllScope(project));
return baseClass != null && aClass.isInheritor(baseClass, true);
}
@Override
public boolean isToSearchInComments(PsiElement element) {
return getBaseHandler().isToSearchInComments(element);
}
@Override
public void setToSearchInComments(PsiElement element, boolean enabled) {
getBaseHandler().setToSearchInComments(element, enabled);
}
@Override
public boolean isToSearchForTextOccurrences(PsiElement element) {
return getBaseHandler().isToSearchForTextOccurrences(element);
}
@Override
public void setToSearchForTextOccurrences(PsiElement element, boolean enabled) {
getBaseHandler().setToSearchForTextOccurrences(element, enabled);
}
}