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
.ide
.util
;
18 import com
.intellij
.ide
.IdeBundle
;
19 import com
.intellij
.openapi
.application
.ApplicationManager
;
20 import com
.intellij
.openapi
.command
.CommandProcessor
;
21 import com
.intellij
.openapi
.diagnostic
.Logger
;
22 import com
.intellij
.openapi
.module
.Module
;
23 import com
.intellij
.openapi
.project
.Project
;
24 import com
.intellij
.openapi
.project
.ProjectBundle
;
25 import com
.intellij
.openapi
.projectRoots
.impl
.ProjectRootUtil
;
26 import com
.intellij
.openapi
.roots
.ModulePackageIndex
;
27 import com
.intellij
.openapi
.roots
.ModuleRootManager
;
28 import com
.intellij
.openapi
.roots
.OrderRootType
;
29 import com
.intellij
.openapi
.roots
.ui
.configuration
.CommonContentEntriesEditor
;
30 import com
.intellij
.openapi
.roots
.ui
.configuration
.ProjectSettingsService
;
31 import com
.intellij
.openapi
.ui
.Messages
;
32 import com
.intellij
.openapi
.util
.Computable
;
33 import com
.intellij
.openapi
.vfs
.VirtualFile
;
34 import com
.intellij
.psi
.*;
35 import com
.intellij
.util
.ActionRunner
;
36 import com
.intellij
.util
.IncorrectOperationException
;
37 import com
.intellij
.util
.Processor
;
38 import com
.intellij
.util
.Query
;
39 import org
.jetbrains
.annotations
.NotNull
;
40 import org
.jetbrains
.annotations
.Nullable
;
43 import java
.io
.IOException
;
44 import java
.util
.ArrayList
;
45 import java
.util
.List
;
47 public class PackageUtil
{
48 private static final Logger LOG
= Logger
.getInstance("com.intellij.ide.util.PackageUtil");
51 public static PsiDirectory
findPossiblePackageDirectoryInModule(Module module
, String packageName
) {
52 PsiDirectory psiDirectory
= null;
53 if (!"".equals(packageName
)) {
54 PsiPackage rootPackage
= findLongestExistingPackage(module
.getProject(), packageName
);
55 if (rootPackage
!= null) {
56 final PsiDirectory
[] psiDirectories
= getPackageDirectoriesInModule(rootPackage
, module
);
57 if (psiDirectories
.length
> 0) {
58 psiDirectory
= psiDirectories
[0];
62 if (psiDirectory
== null) {
63 if (checkSourceRootsConfigured(module
)) {
64 final VirtualFile
[] sourceRoots
= ModuleRootManager
.getInstance(module
).getSourceRoots();
65 for (VirtualFile sourceRoot
: sourceRoots
) {
66 final PsiDirectory directory
= PsiManager
.getInstance(module
.getProject()).findDirectory(sourceRoot
);
67 if (directory
!= null) {
68 psiDirectory
= directory
;
81 public static PsiDirectory
findOrCreateDirectoryForPackage(Project project
,
84 boolean askUserToCreate
) throws IncorrectOperationException
{
86 PsiDirectory psiDirectory
= null;
88 if (!"".equals(packageName
)) {
89 PsiPackage rootPackage
= findLongestExistingPackage(project
, packageName
);
90 if (rootPackage
!= null) {
91 int beginIndex
= rootPackage
.getQualifiedName().length() + 1;
92 packageName
= beginIndex
< packageName
.length() ? packageName
.substring(beginIndex
) : "";
93 String postfixToShow
= packageName
.replace('.', File
.separatorChar
);
94 if (packageName
.length() > 0) {
95 postfixToShow
= File
.separatorChar
+ postfixToShow
;
97 psiDirectory
= DirectoryChooserUtil
.selectDirectory(project
, rootPackage
.getDirectories(), baseDir
, postfixToShow
);
98 if (psiDirectory
== null) return null;
102 if (psiDirectory
== null) {
103 PsiDirectory
[] sourceDirectories
= ProjectRootUtil
.getRootDirectories(project
, OrderRootType
.SOURCES
);
104 psiDirectory
= DirectoryChooserUtil
.selectDirectory(project
, sourceDirectories
, baseDir
,
105 File
.separatorChar
+ packageName
.replace('.', File
.separatorChar
));
106 if (psiDirectory
== null) return null;
109 String restOfName
= packageName
;
110 boolean askedToCreate
= false;
111 while (restOfName
.length() > 0) {
112 final String name
= getLeftPart(restOfName
);
113 PsiDirectory foundExistingDirectory
= psiDirectory
.findSubdirectory(name
);
114 if (foundExistingDirectory
== null) {
115 if (!askedToCreate
&& askUserToCreate
) {
116 int toCreate
= Messages
.showYesNoDialog(project
,
117 IdeBundle
.message("prompt.create.non.existing.package", packageName
),
118 IdeBundle
.message("title.package.not.found"),
119 Messages
.getQuestionIcon());
123 askedToCreate
= true;
125 psiDirectory
= createSubdirectory(psiDirectory
, name
, project
);
128 psiDirectory
= foundExistingDirectory
;
130 restOfName
= cutLeftPart(restOfName
);
135 private static PsiDirectory
createSubdirectory(final PsiDirectory oldDirectory
,
136 final String name
, Project project
) throws IncorrectOperationException
{
137 final PsiDirectory
[] psiDirectory
= new PsiDirectory
[1];
138 final IncorrectOperationException
[] exception
= new IncorrectOperationException
[1];
140 CommandProcessor
.getInstance().executeCommand(project
, new Runnable(){
142 psiDirectory
[0] = ApplicationManager
.getApplication().runWriteAction(new Computable
<PsiDirectory
>() {
143 public PsiDirectory
compute() {
145 return oldDirectory
.createSubdirectory(name
);
147 catch (IncorrectOperationException e
) {
154 }, IdeBundle
.message("command.create.new.subdirectory"), null);
156 if (exception
[0] != null) throw exception
[0];
158 return psiDirectory
[0];
161 public static PsiDirectory
findOrCreateDirectoryForPackage(@NotNull Module module
,
163 PsiDirectory baseDir
,
164 boolean askUserToCreate
) throws IncorrectOperationException
{
165 final Project project
= module
.getProject();
166 PsiDirectory psiDirectory
= null;
167 if (!"".equals(packageName
)) {
168 PsiPackage rootPackage
= findLongestExistingPackage(module
, packageName
);
169 if (rootPackage
!= null) {
170 int beginIndex
= rootPackage
.getQualifiedName().length() + 1;
171 packageName
= beginIndex
< packageName
.length() ? packageName
.substring(beginIndex
) : "";
172 String postfixToShow
= packageName
.replace('.', File
.separatorChar
);
173 if (packageName
.length() > 0) {
174 postfixToShow
= File
.separatorChar
+ postfixToShow
;
176 PsiDirectory
[] moduleDirectories
= getPackageDirectoriesInModule(rootPackage
, module
);
177 psiDirectory
= DirectoryChooserUtil
.selectDirectory(project
, moduleDirectories
, baseDir
, postfixToShow
);
178 if (psiDirectory
== null) return null;
182 if (psiDirectory
== null) {
183 if (!checkSourceRootsConfigured(module
)) return null;
184 final VirtualFile
[] sourceRoots
= ModuleRootManager
.getInstance(module
).getSourceRoots();
185 List
<PsiDirectory
> directoryList
= new ArrayList
<PsiDirectory
>();
186 for (VirtualFile sourceRoot
: sourceRoots
) {
187 final PsiDirectory directory
= PsiManager
.getInstance(project
).findDirectory(sourceRoot
);
188 if (directory
!= null) {
189 directoryList
.add(directory
);
192 PsiDirectory
[] sourceDirectories
= directoryList
.toArray(new PsiDirectory
[directoryList
.size()]);
193 psiDirectory
= DirectoryChooserUtil
.selectDirectory(project
, sourceDirectories
, baseDir
,
194 File
.separatorChar
+ packageName
.replace('.', File
.separatorChar
));
195 if (psiDirectory
== null) return null;
198 String restOfName
= packageName
;
199 boolean askedToCreate
= false;
200 while (restOfName
.length() > 0) {
201 final String name
= getLeftPart(restOfName
);
202 PsiDirectory foundExistingDirectory
= psiDirectory
.findSubdirectory(name
);
203 if (foundExistingDirectory
== null) {
204 if (!askedToCreate
&& askUserToCreate
) {
205 if (!ApplicationManager
.getApplication().isUnitTestMode()) {
206 int toCreate
= Messages
.showYesNoDialog(project
,
207 IdeBundle
.message("prompt.create.non.existing.package", packageName
),
208 IdeBundle
.message("title.package.not.found"),
209 Messages
.getQuestionIcon());
214 askedToCreate
= true;
217 final PsiDirectory psiDirectory1
= psiDirectory
;
219 psiDirectory
= ActionRunner
.runInsideWriteAction(new ActionRunner
.InterruptibleRunnableWithResult
<PsiDirectory
>() {
220 public PsiDirectory
run() throws Exception
{
221 return psiDirectory1
.createSubdirectory(name
);
225 catch(IncorrectOperationException e
) {
228 catch(IOException e
) {
229 throw new IncorrectOperationException(e
.toString(), e
);
231 catch (Exception e
) {
236 psiDirectory
= foundExistingDirectory
;
238 restOfName
= cutLeftPart(restOfName
);
243 private static PsiDirectory
[] getPackageDirectoriesInModule(PsiPackage rootPackage
, Module module
) {
244 final PsiManager manager
= PsiManager
.getInstance(module
.getProject());
245 final String packageName
= rootPackage
.getQualifiedName();
246 final List
<PsiDirectory
> moduleDirectoryList
= new ArrayList
<PsiDirectory
>();
247 ModulePackageIndex
.getInstance(module
).getDirsByPackageName(packageName
, false).forEach(new Processor
<VirtualFile
>() {
248 public boolean process(final VirtualFile directory
) {
249 moduleDirectoryList
.add(manager
.findDirectory(directory
));
254 return moduleDirectoryList
.toArray(new PsiDirectory
[moduleDirectoryList
.size()]);
257 private static PsiPackage
findLongestExistingPackage(Project project
, String packageName
) {
258 PsiManager manager
= PsiManager
.getInstance(project
);
259 String nameToMatch
= packageName
;
261 PsiPackage aPackage
= JavaPsiFacade
.getInstance(manager
.getProject()).findPackage(nameToMatch
);
262 if (aPackage
!= null && isWritablePackage(aPackage
)) return aPackage
;
263 int lastDotIndex
= nameToMatch
.lastIndexOf('.');
264 if (lastDotIndex
>= 0) {
265 nameToMatch
= nameToMatch
.substring(0, lastDotIndex
);
273 private static boolean isWritablePackage(PsiPackage aPackage
) {
274 PsiDirectory
[] directories
= aPackage
.getDirectories();
275 for (PsiDirectory directory
: directories
) {
276 if (directory
.isValid() && directory
.isWritable()) {
283 private static PsiDirectory
getWritableDirectory(Query
<VirtualFile
> vFiles
, PsiManager manager
) {
284 for (VirtualFile vFile
: vFiles
) {
285 PsiDirectory directory
= manager
.findDirectory(vFile
);
286 if (directory
!= null && directory
.isValid() && directory
.isWritable()) {
293 private static PsiPackage
findLongestExistingPackage(Module module
, String packageName
) {
294 final PsiManager manager
= PsiManager
.getInstance(module
.getProject());
296 String nameToMatch
= packageName
;
298 Query
<VirtualFile
> vFiles
= ModulePackageIndex
.getInstance(module
).getDirsByPackageName(nameToMatch
, false);
299 PsiDirectory directory
= getWritableDirectory(vFiles
, manager
);
300 if (directory
!= null) return JavaDirectoryService
.getInstance().getPackage(directory
);
302 int lastDotIndex
= nameToMatch
.lastIndexOf('.');
303 if (lastDotIndex
>= 0) {
304 nameToMatch
= nameToMatch
.substring(0, lastDotIndex
);
312 private static String
getLeftPart(String packageName
) {
313 int index
= packageName
.indexOf('.');
314 return index
> -1 ? packageName
.substring(0, index
) : packageName
;
317 private static String
cutLeftPart(String packageName
) {
318 int index
= packageName
.indexOf('.');
319 return index
> -1 ? packageName
.substring(index
+ 1) : "";
322 public static boolean checkSourceRootsConfigured(final Module module
) {
323 VirtualFile
[] sourceRoots
= ModuleRootManager
.getInstance(module
).getSourceRoots();
324 if (sourceRoots
.length
== 0) {
325 Messages
.showErrorDialog(
327 ProjectBundle
.message("module.source.roots.not.configured.error", module
.getName()),
328 ProjectBundle
.message("module.source.roots.not.configured.title")
331 ProjectSettingsService
.getInstance(module
.getProject()).showModuleConfigurationDialog(module
.getName(), CommonContentEntriesEditor
.NAME
, false);
333 sourceRoots
= ModuleRootManager
.getInstance(module
).getSourceRoots();
334 if (sourceRoots
.length
== 0) {