| /* |
| * 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; |
| } |
| } |
| } |