update copyright
[fedora-idea.git] / java / java-impl / src / com / intellij / codeInsight / daemon / quickFix / CreateClassOrPackageFix.java
blobc07ed8ada65cb0e45fd74d5c2c3ad4afbb705d8e
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.
16 package com.intellij.codeInsight.daemon.quickFix;
18 import com.intellij.codeInsight.daemon.QuickFixBundle;
19 import com.intellij.codeInsight.daemon.impl.quickfix.CreateClassKind;
20 import com.intellij.codeInsight.daemon.impl.quickfix.CreateFromUsageUtils;
21 import com.intellij.codeInsight.intention.IntentionAction;
22 import com.intellij.codeInspection.LocalQuickFix;
23 import com.intellij.codeInspection.ProblemDescriptor;
24 import com.intellij.ide.util.DirectoryChooserUtil;
25 import com.intellij.openapi.application.ApplicationManager;
26 import com.intellij.openapi.application.Result;
27 import com.intellij.openapi.command.WriteCommandAction;
28 import com.intellij.openapi.editor.Editor;
29 import com.intellij.openapi.module.Module;
30 import com.intellij.openapi.project.Project;
31 import com.intellij.openapi.roots.ProjectFileIndex;
32 import com.intellij.openapi.roots.ProjectRootManager;
33 import com.intellij.openapi.vfs.VirtualFile;
34 import com.intellij.psi.*;
35 import com.intellij.psi.search.GlobalSearchScope;
36 import com.intellij.psi.util.ClassKind;
37 import com.intellij.psi.util.CreateClassUtil;
38 import com.intellij.util.IncorrectOperationException;
39 import org.jetbrains.annotations.NotNull;
40 import org.jetbrains.annotations.Nullable;
42 import java.util.*;
44 /**
45 * @author peter
47 public class CreateClassOrPackageFix implements IntentionAction, LocalQuickFix {
49 private final List<PsiDirectory> myWritableDirectoryList;
50 private final PsiElement myContext;
51 private final String myPresentation;
53 @Nullable private final ClassKind myClassKind;
54 @Nullable private final String mySuperClass;
55 private final String myRedPart;
56 @Nullable private final String myTemplateName;
58 @Nullable
59 public static CreateClassOrPackageFix createFix(@NotNull final String qualifiedName,
60 @NotNull final GlobalSearchScope scope,
61 @NotNull final PsiElement context,
62 @Nullable final PsiPackage basePackage,
63 @Nullable ClassKind kind,
64 @Nullable String superClass,
65 @Nullable String templateName) {
66 final List<PsiDirectory> directories = getWritableDirectoryListDefault(basePackage, scope, context.getManager());
67 if (directories.isEmpty()) {
68 return null;
70 final String redPart = basePackage == null ? qualifiedName : qualifiedName.substring(basePackage.getQualifiedName().length() + 1);
71 final int dot = redPart.indexOf('.');
72 final boolean fixPath = dot >= 0;
73 final String firstRedName = fixPath ? redPart.substring(0, dot) : redPart;
74 for (Iterator<PsiDirectory> i = directories.iterator(); i.hasNext(); ) {
75 if (!checkCreateClassOrPackage(kind != null && !fixPath, i.next(), firstRedName)) {
76 i.remove();
79 return directories.isEmpty() ? null : new CreateClassOrPackageFix(directories,
80 context,
81 fixPath ? qualifiedName : redPart,
82 redPart,
83 kind,
84 superClass,
85 templateName);
88 @Nullable
89 public static CreateClassOrPackageFix createFix(@NotNull final String qualifiedName,
90 @NotNull final PsiElement context,
91 @Nullable ClassKind kind, final String superClass) {
92 return createFix(qualifiedName, context.getResolveScope(), context, null, kind, superClass, null);
95 private CreateClassOrPackageFix(final List<PsiDirectory> writableDirectoryList,
96 final PsiElement context,
97 final String presentation,
98 final String redPart,
99 @Nullable ClassKind kind,
100 @Nullable String superClass,
101 @Nullable final String templateName) {
102 myRedPart = redPart;
103 myTemplateName = templateName;
104 myWritableDirectoryList = writableDirectoryList;
105 myContext = context;
106 myClassKind = kind;
107 mySuperClass = superClass;
108 myPresentation = presentation;
111 @NotNull
112 public String getText() {
113 return QuickFixBundle.message(
114 myClassKind == ClassKind.INTERFACE ? "create.interface.text" : myClassKind != null ? "create.class.text" : "create.package.text",
115 myPresentation);
118 @NotNull
119 public String getName() {
120 return getText();
123 @NotNull
124 public String getFamilyName() {
125 return getText();
128 public void applyFix(@NotNull final Project project, @NotNull ProblemDescriptor descriptor) {
129 final PsiFile file = descriptor.getPsiElement().getContainingFile();
130 if (isAvailable(project, null, file)) {
131 new WriteCommandAction(project) {
132 protected void run(Result result) throws Throwable {
133 invoke(project, null, file);
135 }.execute();
139 private static boolean checkCreateClassOrPackage(final boolean createJavaClass, final PsiDirectory directory, final String name) {
141 try {
142 if (createJavaClass) {
143 JavaDirectoryService.getInstance().checkCreateClass(directory, name);
145 else {
146 directory.checkCreateSubdirectory(name);
148 return true;
150 catch (IncorrectOperationException ex) {
151 return false;
155 public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
156 return true;
159 public void invoke(@NotNull Project project, Editor editor, PsiFile file) {
161 final PsiDirectory directory = chooseDirectory(project, file);
162 if (directory == null) return;
163 ApplicationManager.getApplication().runWriteAction(new Runnable() {
164 public void run() {
165 doCreate(directory);
170 @Nullable
171 private PsiDirectory chooseDirectory(final Project project, final PsiFile file) {
172 PsiDirectory preferredDirectory = myWritableDirectoryList.isEmpty() ? null : myWritableDirectoryList.get(0);
173 final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(project).getFileIndex();
174 final VirtualFile virtualFile = file.getVirtualFile();
175 assert virtualFile != null;
176 final Module moduleForFile = fileIndex.getModuleForFile(virtualFile);
177 if (myWritableDirectoryList.size() > 1 && !ApplicationManager.getApplication().isUnitTestMode()) {
178 if (moduleForFile != null) {
179 for (PsiDirectory directory : myWritableDirectoryList) {
180 if (fileIndex.getModuleForFile(directory.getVirtualFile()) == moduleForFile) {
181 preferredDirectory = directory;
182 break;
187 return DirectoryChooserUtil
188 .chooseDirectory(myWritableDirectoryList.toArray(new PsiDirectory[myWritableDirectoryList.size()]),
189 preferredDirectory, project,
190 new HashMap<PsiDirectory, String>());
192 return preferredDirectory;
195 private void doCreate(final PsiDirectory baseDirectory) {
196 final PsiManager manager = baseDirectory.getManager();
197 PsiDirectory directory = baseDirectory;
198 String lastName;
199 for (StringTokenizer st = new StringTokenizer(myRedPart, "."); ;) {
200 lastName = st.nextToken();
201 if (st.hasMoreTokens()) {
202 try {
203 final PsiDirectory subdirectory = directory.findSubdirectory(lastName);
204 directory = subdirectory != null ? subdirectory : directory.createSubdirectory(lastName);
206 catch (IncorrectOperationException e) {
207 CreateFromUsageUtils.scheduleFileOrPackageCreationFailedMessageBox(e, lastName, directory, true);
208 return;
211 else {
212 break;
215 if (myClassKind != null) {
216 PsiClass createdClass;
217 if (myTemplateName != null) {
218 createdClass = CreateClassUtil.createClassFromCustomTemplate(directory, null, lastName, myTemplateName);
220 else {
221 createdClass = CreateFromUsageUtils
222 .createClass(myClassKind == ClassKind.INTERFACE ? CreateClassKind.INTERFACE : CreateClassKind.CLASS, directory, lastName,
223 manager, myContext, null, mySuperClass);
225 if (createdClass != null) {
226 createdClass.navigate(true);
229 else {
230 try {
231 directory.createSubdirectory(lastName);
233 catch (IncorrectOperationException e) {
234 CreateFromUsageUtils.scheduleFileOrPackageCreationFailedMessageBox(e, lastName, directory, true);
239 public boolean startInWriteAction() {
240 return false;
243 public static List<PsiDirectory> getWritableDirectoryListDefault(@Nullable final PsiPackage context,
244 final GlobalSearchScope scope,
245 final PsiManager psiManager) {
246 final List<PsiDirectory> writableDirectoryList = new ArrayList<PsiDirectory>();
247 if (context != null) {
248 for (PsiDirectory directory : context.getDirectories()) {
249 if (directory.isWritable() && scope.contains(directory.getVirtualFile())) {
250 writableDirectoryList.add(directory);
254 else {
255 for (VirtualFile root : ProjectRootManager.getInstance(psiManager.getProject()).getContentSourceRoots()) {
256 PsiDirectory directory = psiManager.findDirectory(root);
257 if (directory != null && directory.isWritable() && scope.contains(directory.getVirtualFile())) {
258 writableDirectoryList.add(directory);
262 return writableDirectoryList;