blob: c8b7da8aed28ac5b3fd718802288ca0a65b7118c [file] [log] [blame]
/*
* Copyright 2000-2009 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Created by IntelliJ IDEA.
* User: mike
* Date: Sep 4, 2002
* Time: 6:26:27 PM
* To change template for new class use
* Code Style | Class Templates options (Tools | IDE Options).
*/
package com.intellij.codeInsight.intention.impl;
import com.intellij.codeInsight.CodeInsightBundle;
import com.intellij.codeInsight.FileModificationService;
import com.intellij.codeInsight.generation.OverrideImplementUtil;
import com.intellij.ide.util.PsiClassListCellRenderer;
import com.intellij.ide.util.PsiElementListCellRenderer;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.ui.popup.PopupChooserBuilder;
import com.intellij.openapi.util.Computable;
import com.intellij.psi.*;
import com.intellij.psi.search.searches.ClassInheritorsSearch;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.ui.components.JBList;
import com.intellij.util.IncorrectOperationException;
import javax.swing.*;
import java.util.*;
public class ImplementAbstractMethodHandler {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.intention.impl.ImplementAbstractMethodHandler");
private final Project myProject;
private final Editor myEditor;
private final PsiMethod myMethod;
private JList myList;
public ImplementAbstractMethodHandler(Project project, Editor editor, PsiMethod method) {
myProject = project;
myEditor = editor;
myMethod = method;
}
public void invoke() {
PsiDocumentManager.getInstance(myProject).commitAllDocuments();
final PsiElement[][] result = new PsiElement[1][];
ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() {
@Override
public void run() {
ApplicationManager.getApplication().runReadAction(new Runnable() {
@Override
public void run() {
final PsiClass psiClass = myMethod.getContainingClass();
if (!psiClass.isValid()) return;
if (!psiClass.isEnum()) {
result[0] = getClassImplementations(psiClass);
}
else {
final List<PsiElement> enumConstants = new ArrayList<PsiElement>();
for (PsiField field : psiClass.getFields()) {
if (field instanceof PsiEnumConstant) {
final PsiEnumConstantInitializer initializingClass = ((PsiEnumConstant)field).getInitializingClass();
if (initializingClass != null) {
PsiMethod method = initializingClass.findMethodBySignature(myMethod, true);
if (method == null || !method.getContainingClass().equals(initializingClass)) {
enumConstants.add(initializingClass);
}
}
else {
enumConstants.add(field);
}
}
}
result[0] = PsiUtilCore.toPsiElementArray(enumConstants);
}
}
});
}
}, CodeInsightBundle.message("intention.implement.abstract.method.searching.for.descendants.progress"), true, myProject);
if (result[0] == null) return;
if (result[0].length == 0) {
Messages.showMessageDialog(myProject,
CodeInsightBundle.message("intention.implement.abstract.method.error.no.classes.message"),
CodeInsightBundle.message("intention.implement.abstract.method.error.no.classes.title"),
Messages.getInformationIcon());
return;
}
if (result[0].length == 1) {
implementInClass(new Object[] {result[0][0]});
return;
}
final MyPsiElementListCellRenderer elementListCellRenderer = new MyPsiElementListCellRenderer();
elementListCellRenderer.sort(result[0]);
myList = new JBList(result[0]);
myList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
final Runnable runnable = new Runnable(){
@Override
public void run() {
int index = myList.getSelectedIndex();
if (index < 0) return;
implementInClass(myList.getSelectedValues());
}
};
myList.setCellRenderer(elementListCellRenderer);
final PopupChooserBuilder builder = new PopupChooserBuilder(myList);
elementListCellRenderer.installSpeedSearch(builder);
builder.
setTitle(CodeInsightBundle.message("intention.implement.abstract.method.class.chooser.title")).
setItemChoosenCallback(runnable).
createPopup().
showInBestPositionFor(myEditor);
}
public void implementInClass(final Object[] selection) {
for (Object o : selection) {
if (!((PsiElement)o).isValid()) return;
}
CommandProcessor.getInstance().executeCommand(myProject, new Runnable() {
@Override
public void run() {
final LinkedHashSet<PsiClass> classes = new LinkedHashSet<PsiClass>();
for (final Object o : selection) {
if (o instanceof PsiEnumConstant) {
classes.add(ApplicationManager.getApplication().runWriteAction(new Computable<PsiClass>(){
@Override
public PsiClass compute() {
return ((PsiEnumConstant) o).getOrCreateInitializingClass();
}
}));
}
else {
classes.add((PsiClass)o);
}
}
if (!FileModificationService.getInstance().preparePsiElementsForWrite(classes)) return;
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
for (PsiClass psiClass : classes) {
try {
OverrideImplementUtil.overrideOrImplement(psiClass, myMethod);
}
catch (IncorrectOperationException e) {
LOG.error(e);
}
}
}
});
}
}, CodeInsightBundle.message("intention.implement.abstract.method.command.name"), null);
}
private PsiClass[] getClassImplementations(final PsiClass psiClass) {
ArrayList<PsiClass> list = new ArrayList<PsiClass>();
for (PsiClass inheritor : ClassInheritorsSearch.search(psiClass, true)) {
if (!inheritor.isInterface()) {
PsiMethod method = inheritor.findMethodBySignature(myMethod, true);
if (method == null || !method.getContainingClass().equals(psiClass)) continue;
list.add(inheritor);
}
}
return list.toArray(new PsiClass[list.size()]);
}
private static class MyPsiElementListCellRenderer extends PsiElementListCellRenderer<PsiElement> {
private final PsiClassListCellRenderer myRenderer;
public MyPsiElementListCellRenderer() {
myRenderer = new PsiClassListCellRenderer();
}
void sort(PsiElement[] result) {
final Comparator<PsiClass> comparator = myRenderer.getComparator();
Arrays.sort(result, new Comparator<PsiElement>() {
@Override
public int compare(PsiElement o1, PsiElement o2) {
if (o1 instanceof PsiEnumConstant && o2 instanceof PsiEnumConstant) {
return ((PsiEnumConstant)o1).getName().compareTo(((PsiEnumConstant)o2).getName());
}
if (o1 instanceof PsiEnumConstant) return -1;
if (o2 instanceof PsiEnumConstant) return 1;
return comparator.compare((PsiClass)o1, (PsiClass)o2);
}
});
}
@Override
public String getElementText(PsiElement element) {
return element instanceof PsiClass ? myRenderer.getElementText((PsiClass)element)
: ((PsiEnumConstant)element).getName();
}
@Override
protected String getContainerText(PsiElement element, String name) {
return element instanceof PsiClass ? PsiClassListCellRenderer.getContainerTextStatic(element)
: ((PsiEnumConstant)element).getContainingClass().getQualifiedName();
}
@Override
protected int getIconFlags() {
return 0;
}
}
}