update copyright
[fedora-idea.git] / java / java-impl / src / com / intellij / codeInsight / intention / impl / CreateSubclassAction.java
blob6de444d8e6d34240df5e64f07cbddecedd0e0f11
1 /*
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.
19 * User: mike
20 * Date: Aug 26, 2002
21 * Time: 2:33:58 PM
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.codeInsight.CodeInsightUtil;
29 import com.intellij.codeInsight.daemon.impl.analysis.HighlightNamesUtil;
30 import com.intellij.codeInsight.daemon.impl.quickfix.CreateClassKind;
31 import com.intellij.codeInsight.generation.OverrideImplementUtil;
32 import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction;
33 import com.intellij.openapi.application.ApplicationManager;
34 import com.intellij.openapi.diagnostic.Logger;
35 import com.intellij.openapi.editor.Editor;
36 import com.intellij.openapi.fileEditor.ex.IdeDocumentHistory;
37 import com.intellij.openapi.module.ModuleUtil;
38 import com.intellij.openapi.project.Project;
39 import com.intellij.openapi.ui.Messages;
40 import com.intellij.openapi.util.Computable;
41 import com.intellij.openapi.util.TextRange;
42 import com.intellij.psi.*;
43 import com.intellij.psi.impl.source.PostprocessReformattingAspect;
44 import com.intellij.psi.util.PsiTreeUtil;
45 import com.intellij.util.IncorrectOperationException;
46 import org.jetbrains.annotations.NonNls;
47 import org.jetbrains.annotations.NotNull;
48 import org.jetbrains.annotations.Nullable;
50 public class CreateSubclassAction extends PsiElementBaseIntentionAction {
51 private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.intention.impl.ImplementAbstractClassAction");
52 private String myText = CodeInsightBundle.message("intention.implement.abstract.class.default.text");
53 @NonNls private static final String IMPL_SUFFIX = "Impl";
55 @NotNull
56 public String getText() {
57 return myText;
60 @NotNull
61 public String getFamilyName() {
62 return CodeInsightBundle.message("intention.implement.abstract.class.family");
65 public boolean isAvailable(@NotNull Project project, Editor editor, @Nullable PsiElement element) {
66 if (element == null) return false;
67 PsiClass psiClass = PsiTreeUtil.getParentOfType(element, PsiClass.class);
68 if (psiClass == null || psiClass.isAnnotationType() || psiClass.isEnum() || psiClass instanceof PsiAnonymousClass ||
69 psiClass.hasModifierProperty(PsiModifier.FINAL)) {
70 return false;
72 final PsiMethod[] constructors = psiClass.getConstructors();
73 if (constructors.length > 0) {
74 boolean hasNonPrivateConstructor = false;
75 for (PsiMethod constructor : constructors) {
76 if (!constructor.hasModifierProperty(PsiModifier.PRIVATE)) {
77 hasNonPrivateConstructor = true;
78 break;
81 if (!hasNonPrivateConstructor) return false;
83 PsiJavaToken lBrace = psiClass.getLBrace();
84 if (lBrace == null) return false;
85 if (element.getTextOffset() >= lBrace.getTextOffset()) return false;
87 TextRange declarationRange = HighlightNamesUtil.getClassDeclarationTextRange(psiClass);
88 if (!declarationRange.contains(element.getTextRange())) return false;
90 myText = psiClass.isInterface()
91 ? CodeInsightBundle.message("intention.implement.abstract.class.interface.text")
92 : psiClass.hasModifierProperty(PsiModifier.ABSTRACT)
93 ? CodeInsightBundle.message("intention.implement.abstract.class.default.text")
94 : CodeInsightBundle.message("intention.implement.abstract.class.subclass.text");
95 return true;
98 public void invoke(@NotNull final Project project, Editor editor, final PsiFile file) throws IncorrectOperationException {
99 PsiElement element = file.findElementAt(editor.getCaretModel().getOffset());
100 final PsiClass psiClass = PsiTreeUtil.getParentOfType(element, PsiClass.class);
102 PsiDirectory sourceDir = file.getContainingDirectory();
104 final PsiPackage aPackage = JavaDirectoryService.getInstance().getPackage(sourceDir);
105 final CreateClassDialog dialog = new CreateClassDialog(
106 project,
107 myText,
108 psiClass.getName() + IMPL_SUFFIX,
109 aPackage != null ? aPackage.getQualifiedName() : "",
110 CreateClassKind.CLASS, true, ModuleUtil.findModuleForPsiElement(file));
111 dialog.show();
112 if (!dialog.isOK()) return;
113 final PsiDirectory targetDirectory = dialog.getTargetDirectory();
114 if (targetDirectory == null) return;
116 createSubclass(psiClass, targetDirectory, dialog.getClassName());
119 public static void createSubclass(final PsiClass psiClass, final PsiDirectory targetDirectory, final String className) {
120 final Project project = psiClass.getProject();
121 PostprocessReformattingAspect.getInstance(project).postponeFormattingInside(new Runnable () {
122 public void run() {
123 PsiClass targetClass = ApplicationManager.getApplication().runWriteAction(new Computable<PsiClass>() {
124 public PsiClass compute() {
126 IdeDocumentHistory.getInstance(project).includeCurrentPlaceAsChangePlace();
128 final PsiTypeParameterList oldTypeParameterList = psiClass.getTypeParameterList();
129 PsiClass targetClass;
130 try {
131 targetClass = JavaDirectoryService.getInstance().createClass(targetDirectory, className);
132 if (psiClass.hasTypeParameters()) {
133 final PsiTypeParameterList typeParameterList = targetClass.getTypeParameterList();
134 assert typeParameterList != null;
135 typeParameterList.replace(oldTypeParameterList);
138 catch (final IncorrectOperationException e) {
139 ApplicationManager.getApplication().invokeLater(new Runnable() {
140 public void run() {
141 Messages.showErrorDialog(project, CodeInsightBundle.message("intention.error.cannot.create.class.message", className) +
142 "\n"+e.getLocalizedMessage(),
143 CodeInsightBundle.message("intention.error.cannot.create.class.title"));
146 return null;
148 final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(project).getElementFactory();
149 PsiJavaCodeReferenceElement ref = elementFactory.createClassReferenceElement(psiClass);
150 try {
151 if (psiClass.isInterface()) {
152 ref = (PsiJavaCodeReferenceElement)targetClass.getImplementsList().add(ref);
154 else {
155 ref = (PsiJavaCodeReferenceElement)targetClass.getExtendsList().add(ref);
158 if (oldTypeParameterList != null) {
159 for (PsiTypeParameter parameter : oldTypeParameterList.getTypeParameters()) {
160 ref.getParameterList().add(elementFactory.createTypeElement(elementFactory.createType(parameter)));
164 catch (IncorrectOperationException e) {
165 LOG.error(e);
168 return targetClass;
171 if (targetClass == null) return;
173 if (!ApplicationManager.getApplication().isUnitTestMode()) {
174 final Editor editor1 = CodeInsightUtil.positionCursor(project, targetClass.getContainingFile(), targetClass.getLBrace());
175 if (editor1 == null) return;
176 OverrideImplementUtil.chooseAndImplementMethods(project, editor1, targetClass);
182 public boolean startInWriteAction() {
183 return false;