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
;
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
;
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()) {
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
)) {
79 return directories
.isEmpty() ?
null : new CreateClassOrPackageFix(directories
,
81 fixPath ? qualifiedName
: redPart
,
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
,
99 @Nullable ClassKind kind
,
100 @Nullable String superClass
,
101 @Nullable final String templateName
) {
103 myTemplateName
= templateName
;
104 myWritableDirectoryList
= writableDirectoryList
;
107 mySuperClass
= superClass
;
108 myPresentation
= presentation
;
112 public String
getText() {
113 return QuickFixBundle
.message(
114 myClassKind
== ClassKind
.INTERFACE ?
"create.interface.text" : myClassKind
!= null ?
"create.class.text" : "create.package.text",
119 public String
getName() {
124 public String
getFamilyName() {
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
);
139 private static boolean checkCreateClassOrPackage(final boolean createJavaClass
, final PsiDirectory directory
, final String name
) {
142 if (createJavaClass
) {
143 JavaDirectoryService
.getInstance().checkCreateClass(directory
, name
);
146 directory
.checkCreateSubdirectory(name
);
150 catch (IncorrectOperationException ex
) {
155 public boolean isAvailable(@NotNull Project project
, Editor editor
, PsiFile file
) {
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() {
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
;
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
;
199 for (StringTokenizer st
= new StringTokenizer(myRedPart
, "."); ;) {
200 lastName
= st
.nextToken();
201 if (st
.hasMoreTokens()) {
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);
215 if (myClassKind
!= null) {
216 PsiClass createdClass
;
217 if (myTemplateName
!= null) {
218 createdClass
= CreateClassUtil
.createClassFromCustomTemplate(directory
, null, lastName
, myTemplateName
);
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);
231 directory
.createSubdirectory(lastName
);
233 catch (IncorrectOperationException e
) {
234 CreateFromUsageUtils
.scheduleFileOrPackageCreationFailedMessageBox(e
, lastName
, directory
, true);
239 public boolean startInWriteAction() {
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
);
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
;