2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * Created by IntelliJ IDEA.
22 * To change template for new class use
23 * Code Style | Class Templates options (Tools | IDE Options).
25 package com
.intellij
.codeInsight
.intention
.impl
;
27 import com
.intellij
.codeInsight
.CodeInsightBundle
;
28 import com
.intellij
.openapi
.application
.ApplicationManager
;
29 import com
.intellij
.openapi
.editor
.Editor
;
30 import com
.intellij
.openapi
.project
.Project
;
31 import com
.intellij
.psi
.*;
32 import com
.intellij
.psi
.search
.PsiElementProcessor
;
33 import com
.intellij
.psi
.search
.PsiElementProcessorAdapter
;
34 import com
.intellij
.psi
.search
.searches
.ClassInheritorsSearch
;
35 import com
.intellij
.psi
.util
.PsiTreeUtil
;
36 import com
.intellij
.util
.IncorrectOperationException
;
37 import org
.jetbrains
.annotations
.NotNull
;
38 import org
.jetbrains
.annotations
.Nullable
;
40 public class ImplementAbstractMethodAction
extends BaseIntentionAction
{
42 public String
getFamilyName() {
43 return CodeInsightBundle
.message("intention.implement.abstract.method.family");
46 public boolean isAvailable(@NotNull Project project
, Editor editor
, PsiFile file
) {
47 int offset
= editor
.getCaretModel().getOffset();
48 final PsiMethod method
= findMethod(file
, offset
);
50 if (method
== null || !method
.isValid()) return false;
51 setText(getIntentionName(method
));
53 if (!method
.getManager().isInProject(method
)) return false;
55 PsiClass containingClass
= method
.getContainingClass();
56 if (containingClass
== null) return false;
57 if (method
.hasModifierProperty(PsiModifier
.ABSTRACT
)) {
58 MyElementProcessor processor
= new MyElementProcessor(method
);
59 ClassInheritorsSearch
.search(containingClass
, containingClass
.getUseScope(), false).forEach(new PsiElementProcessorAdapter
<PsiClass
>(
61 return isAvailable(processor
);
67 protected String
getIntentionName(final PsiMethod method
) {
68 return CodeInsightBundle
.message("intention.implement.abstract.method.text", method
.getName());
71 static class MyElementProcessor
implements PsiElementProcessor
{
72 private boolean myHasMissingImplementations
;
73 private boolean myHasExistingImplementations
;
74 private final PsiMethod myMethod
;
76 MyElementProcessor(final PsiMethod method
) {
80 public boolean hasMissingImplementations() {
81 return myHasMissingImplementations
;
84 public boolean hasExistingImplementations() {
85 return myHasExistingImplementations
;
88 public boolean execute(PsiElement element
) {
89 if (element
instanceof PsiClass
) {
90 PsiClass aClass
= (PsiClass
) element
;
91 final PsiMethod existingImplementation
= findExistingImplementation(aClass
, myMethod
);
92 if (existingImplementation
!= null && !existingImplementation
.hasModifierProperty(PsiModifier
.ABSTRACT
)) {
93 myHasExistingImplementations
= true;
95 else if (existingImplementation
== null) {
96 myHasMissingImplementations
= true;
98 if (myHasMissingImplementations
&& myHasExistingImplementations
) return false;
104 protected boolean isAvailable(final MyElementProcessor processor
) {
105 return processor
.hasMissingImplementations();
109 static PsiMethod
findExistingImplementation(final PsiClass aClass
, PsiMethod method
) {
110 final PsiMethod
[] methods
= aClass
.findMethodsByName(method
.getName(), false);
111 for(PsiMethod candidate
: methods
) {
112 final PsiMethod
[] superMethods
= candidate
.findSuperMethods(aClass
);
113 for(PsiMethod superMethod
: superMethods
) {
114 if (superMethod
.equals(method
)) {
122 private static PsiMethod
findMethod(PsiFile file
, int offset
) {
123 PsiMethod method
= _findMethod(file
, offset
);
124 if (method
== null) {
125 method
= _findMethod(file
, offset
- 1);
130 private static PsiMethod
_findMethod(PsiFile file
, int offset
) {
131 return PsiTreeUtil
.getParentOfType(file
.findElementAt(offset
), PsiMethod
.class);
134 public void invoke(@NotNull Project project
, Editor editor
, PsiFile file
) throws IncorrectOperationException
{
135 PsiMethod method
= findMethod(file
, editor
.getCaretModel().getOffset());
136 if (method
== null) return;
137 if (!ApplicationManager
.getApplication().isUnitTestMode() && !editor
.getContentComponent().isShowing()) return;
138 invokeHandler(project
, editor
, method
);
141 protected void invokeHandler(final Project project
, final Editor editor
, final PsiMethod method
) {
142 new ImplementAbstractMethodHandler(project
, editor
, method
).invoke();
145 public boolean startInWriteAction() {