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
.javadoc
;
18 import com
.intellij
.execution
.CantRunException
;
19 import com
.intellij
.execution
.ExecutionException
;
20 import com
.intellij
.execution
.Executor
;
21 import com
.intellij
.execution
.configurations
.*;
22 import com
.intellij
.execution
.filters
.RegexpFilter
;
23 import com
.intellij
.execution
.filters
.TextConsoleBuilder
;
24 import com
.intellij
.execution
.filters
.TextConsoleBuilderFactory
;
25 import com
.intellij
.execution
.process
.OSProcessHandler
;
26 import com
.intellij
.execution
.process
.ProcessAdapter
;
27 import com
.intellij
.execution
.process
.ProcessEvent
;
28 import com
.intellij
.execution
.process
.ProcessTerminatedListener
;
29 import com
.intellij
.execution
.runners
.ExecutionEnvironment
;
30 import com
.intellij
.ide
.BrowserUtil
;
31 import com
.intellij
.openapi
.application
.ApplicationManager
;
32 import com
.intellij
.openapi
.fileTypes
.FileTypeManager
;
33 import com
.intellij
.openapi
.fileTypes
.StdFileTypes
;
34 import com
.intellij
.openapi
.module
.Module
;
35 import com
.intellij
.openapi
.module
.ModuleUtil
;
36 import com
.intellij
.openapi
.project
.Project
;
37 import com
.intellij
.openapi
.projectRoots
.JavaSdk
;
38 import com
.intellij
.openapi
.projectRoots
.JavaSdkType
;
39 import com
.intellij
.openapi
.projectRoots
.Sdk
;
40 import com
.intellij
.openapi
.projectRoots
.ex
.PathUtilEx
;
41 import com
.intellij
.openapi
.roots
.*;
42 import com
.intellij
.openapi
.util
.*;
43 import com
.intellij
.openapi
.vfs
.VirtualFile
;
44 import com
.intellij
.psi
.*;
45 import com
.intellij
.util
.PathUtil
;
46 import com
.intellij
.util
.containers
.HashSet
;
47 import org
.jdom
.Element
;
48 import org
.jetbrains
.annotations
.NonNls
;
49 import org
.jetbrains
.annotations
.NotNull
;
50 import org
.jetbrains
.annotations
.Nullable
;
53 import java
.util
.ArrayList
;
54 import java
.util
.Collection
;
57 * @author Eugene Zhuravlev
60 public class JavadocConfiguration
implements ModuleRunProfile
, JDOMExternalizable
{
61 public String OUTPUT_DIRECTORY
;
62 public String OPTION_SCOPE
= PsiKeyword
.PROTECTED
;
63 public boolean OPTION_HIERARCHY
= true;
64 public boolean OPTION_NAVIGATOR
= true;
65 public boolean OPTION_INDEX
= true;
66 public boolean OPTION_SEPARATE_INDEX
= true;
67 public boolean OPTION_DOCUMENT_TAG_USE
= false;
68 public boolean OPTION_DOCUMENT_TAG_AUTHOR
= false;
69 public boolean OPTION_DOCUMENT_TAG_VERSION
= false;
70 public boolean OPTION_DOCUMENT_TAG_DEPRECATED
= true;
71 public boolean OPTION_DEPRECATED_LIST
= true;
72 public String OTHER_OPTIONS
= "";
73 public String HEAP_SIZE
;
75 public boolean OPEN_IN_BROWSER
= true;
77 private final Project myProject
;
78 private GenerationOptions myGenerationOptions
;
80 public static final class GenerationOptions
{
81 public final String myPackageFQName
;
82 public final PsiDirectory myDirectory
;
83 public final boolean isGenerationForPackage
;
84 public final boolean isGenerationWithSubpackages
;
86 public GenerationOptions(String packageFQName
, PsiDirectory directory
, boolean generationForPackage
, boolean generationWithSubpackages
) {
87 myPackageFQName
= packageFQName
;
88 myDirectory
= directory
;
89 isGenerationForPackage
= generationForPackage
;
90 isGenerationWithSubpackages
= generationWithSubpackages
;
94 public void setGenerationOptions(GenerationOptions generationOptions
) {
95 myGenerationOptions
= generationOptions
;
98 public JavadocConfiguration(Project project
) {
102 public RunProfileState
getState(@NotNull final Executor executor
, @NotNull final ExecutionEnvironment env
) throws ExecutionException
{
103 return new MyJavaCommandLineState(myProject
, myGenerationOptions
);
106 public String
getName() {
107 return JavadocBundle
.message("javadoc.settings.title");
110 public void checkConfiguration() throws RuntimeConfigurationException
{
111 if (myGenerationOptions
== null) {
112 throw new RuntimeConfigurationError(JavadocBundle
.message("javadoc.settings.not.specified"));
116 public JavadocConfigurable
createConfigurable() {
117 return new JavadocConfigurable(this);
121 public Module
[] getModules() {
122 return Module
.EMPTY_ARRAY
;
125 public void readExternal(Element element
) throws InvalidDataException
{
126 DefaultJDOMExternalizer
.readExternal(this, element
);
129 public void writeExternal(Element element
) throws WriteExternalException
{
130 DefaultJDOMExternalizer
.writeExternal(this, element
);
133 private class MyJavaCommandLineState
extends CommandLineState
{
134 private final GenerationOptions myGenerationOptions
;
135 private final Project myProject
;
136 @NonNls private static final String INDEX_HTML
= "index.html";
138 public MyJavaCommandLineState(Project project
, GenerationOptions generationOptions
) {
140 myGenerationOptions
= generationOptions
;
142 TextConsoleBuilder builder
= TextConsoleBuilderFactory
.getInstance().createBuilder(project
);
143 builder
.addFilter(new RegexpFilter(project
, "$FILE_PATH$:$LINE$:[^\\^]+\\^"));
144 builder
.addFilter(new RegexpFilter(project
, "$FILE_PATH$:$LINE$: warning - .+$"));
145 setConsoleBuilder(builder
);
148 protected GeneralCommandLine
createCommandLine() throws ExecutionException
{
149 final GeneralCommandLine cmdLine
= new GeneralCommandLine();
150 final Sdk jdk
= PathUtilEx
.getAnyJdk(myProject
);
151 setupExeParams(jdk
, cmdLine
);
152 setupProgramParameters(jdk
, cmdLine
);
156 private void setupExeParams(final Sdk jdk
, GeneralCommandLine cmdLine
) throws ExecutionException
{
157 final String jdkPath
= jdk
!= null && jdk
.getSdkType() instanceof JavaSdkType ?
((JavaSdkType
)jdk
.getSdkType()).getBinPath(jdk
) : null;
158 if (jdkPath
== null) {
159 throw new CantRunException(JavadocBundle
.message("javadoc.generate.no.jdk.path"));
161 String versionString
= jdk
.getVersionString();
162 if (HEAP_SIZE
!= null && HEAP_SIZE
.trim().length() != 0) {
163 if (versionString
.indexOf("1.1") > -1) {
164 cmdLine
.getParametersList().prepend("-J-mx" + HEAP_SIZE
+ "m");
167 cmdLine
.getParametersList().prepend("-J-Xmx" + HEAP_SIZE
+ "m");
170 cmdLine
.setWorkingDirectory(null);
171 @NonNls final String javadocExecutableName
= File
.separator
+ (SystemInfo
.isWindows ?
"javadoc.exe" : "javadoc");
172 @NonNls String exePath
= jdkPath
.replace('/', File
.separatorChar
) + javadocExecutableName
;
173 if (new File(exePath
).exists()) {
174 cmdLine
.setExePath(exePath
);
175 } else { //try to use wrapper jdk
176 exePath
= new File(jdkPath
).getParent().replace('/', File
.separatorChar
) + javadocExecutableName
;
177 if (!new File(exePath
).exists()){
178 final File parent
= new File(System
.getProperty("java.home")).getParentFile(); //try system jre
179 exePath
= parent
.getPath() + File
.separator
+ "bin" + javadocExecutableName
;
180 if (!new File(exePath
).exists()){
181 throw new CantRunException(JavadocBundle
.message("javadoc.generate.no.jdk.path"));
184 cmdLine
.setExePath(exePath
);
188 private void setupProgramParameters(final Sdk jdk
, final GeneralCommandLine cmdLine
) throws CantRunException
{
189 @NonNls final ParametersList parameters
= cmdLine
.getParametersList();
191 if (LOCALE
!= null && LOCALE
.length() > 0) {
192 parameters
.add("-locale");
193 parameters
.add(LOCALE
);
196 if (OPTION_SCOPE
!= null) {
197 parameters
.add("-" + OPTION_SCOPE
);
200 if (!OPTION_HIERARCHY
) {
201 parameters
.add("-notree");
204 if (!OPTION_NAVIGATOR
) {
205 parameters
.add("-nonavbar");
209 parameters
.add("-noindex");
211 else if (OPTION_SEPARATE_INDEX
) {
212 parameters
.add("-splitindex");
215 if (OPTION_DOCUMENT_TAG_USE
) {
216 parameters
.add("-use");
219 if (OPTION_DOCUMENT_TAG_AUTHOR
) {
220 parameters
.add("-author");
223 if (OPTION_DOCUMENT_TAG_VERSION
) {
224 parameters
.add("-version");
227 if (!OPTION_DOCUMENT_TAG_DEPRECATED
) {
228 parameters
.add("-nodeprecated");
230 else if (!OPTION_DEPRECATED_LIST
) {
231 parameters
.add("-nodeprecatedlist");
234 parameters
.addParametersString(OTHER_OPTIONS
);
236 final String classPath
= jdk
.getSdkType() instanceof JavaSdk
237 ? ProjectRootsTraversing
.collectRoots(myProject
, ProjectRootsTraversing
.PROJECT_LIBRARIES
).getPathsString()
238 : ProjectRootsTraversing
.collectRoots(myProject
, ProjectRootsTraversing
.LIBRARIES_AND_JDK
).getPathsString(); //libraries are included into jdk
239 if (classPath
.length() >0) {
240 parameters
.add("-classpath");
241 parameters
.add(classPath
);
244 parameters
.add("-sourcepath");
245 parameters
.add(ProjectRootsTraversing
.collectRoots(myProject
, ProjectRootsTraversing
.PROJECT_SOURCES
).getPathsString());
247 if (OUTPUT_DIRECTORY
!= null) {
248 parameters
.add("-d");
249 parameters
.add(OUTPUT_DIRECTORY
.replace('/', File
.separatorChar
));
252 final Collection
<String
> packages
= new HashSet
<String
>();
253 final Collection
<String
> sources
= new HashSet
<String
>();
254 ApplicationManager
.getApplication().runReadAction(
257 FileIndex fileIndex
= ProjectRootManager
.getInstance(myProject
).getFileIndex();
258 VirtualFile startingFile
= null;
259 if (myGenerationOptions
.isGenerationForPackage
) {
260 if (!myGenerationOptions
.isGenerationWithSubpackages
) {
261 packages
.add(myGenerationOptions
.myPackageFQName
);
264 startingFile
= myGenerationOptions
.myDirectory
.getVirtualFile();
266 MyContentIterator contentIterator
= new MyContentIterator(myProject
, packages
, sources
);
267 if (startingFile
== null) {
268 fileIndex
.iterateContent(contentIterator
);
271 fileIndex
.iterateContentUnderDirectory(startingFile
, contentIterator
);
276 if (packages
.size() + sources
.size() == 0) {
277 throw new CantRunException(JavadocBundle
.message("javadoc.generate.no.classes.in.selected.packages.error"));
279 parameters
.addAll(new ArrayList
<String
>(packages
));
280 parameters
.addAll(new ArrayList
<String
>(sources
));
283 protected OSProcessHandler
startProcess() throws ExecutionException
{
284 final OSProcessHandler handler
= JavaCommandLineStateUtil
.startProcess(createCommandLine());
285 ProcessTerminatedListener
.attach(handler
, myProject
, JavadocBundle
.message("javadoc.generate.exited"));
286 handler
.addProcessListener(new ProcessAdapter() {
287 public void processTerminated(ProcessEvent event
) {
288 if (OPEN_IN_BROWSER
) {
289 File url
= new File(OUTPUT_DIRECTORY
, INDEX_HTML
);
290 if (url
.exists() && event
.getExitCode() == 0) {
291 BrowserUtil
.launchBrowser(url
.getPath());
300 private static class MyContentIterator
implements ContentIterator
{
301 private final PsiManager myPsiManager
;
302 private final Collection
<String
> myPackages
;
303 private final Collection
<String
> mySourceFiles
;
305 public MyContentIterator(Project project
, Collection
<String
> packages
, Collection
<String
> sources
) {
306 myPsiManager
= PsiManager
.getInstance(project
);
307 myPackages
= packages
;
308 mySourceFiles
= sources
;
311 public boolean processFile(VirtualFile fileOrDir
) {
312 if (!fileOrDir
.isInLocalFileSystem()) {
315 final Module module
= ModuleUtil
.findModuleForFile(fileOrDir
, myPsiManager
.getProject());
316 final PsiDirectory directory
= getPsiDirectory(fileOrDir
);
317 if (directory
== null) {
318 if (!StdFileTypes
.JAVA
.equals(FileTypeManager
.getInstance().getFileTypeByFile(fileOrDir
))) {
321 PsiPackage psiPackage
= getPsiPackage(fileOrDir
.getParent());
322 if (psiPackage
!= null) {
323 if (psiPackage
.getQualifiedName().length() == 0 || containsPackagePrefix(module
, psiPackage
.getQualifiedName())) {
324 mySourceFiles
.add(PathUtil
.getLocalPath(fileOrDir
));
330 processDirWithJavaFiles(directory
, myPackages
, mySourceFiles
, module
);
337 private PsiDirectory
getPsiDirectory(VirtualFile fileOrDir
) {
338 return fileOrDir
!= null ? myPsiManager
.findDirectory(fileOrDir
) : null;
342 private PsiPackage
getPsiPackage(VirtualFile dir
) {
343 PsiDirectory directory
= getPsiDirectory(dir
);
344 return directory
!= null ? JavaDirectoryService
.getInstance().getPackage(directory
) : null;
348 private static boolean processDirWithJavaFiles(PsiDirectory dir
, Collection
<String
> packages
, final Collection
<String
> sources
, final Module module
) {
349 PsiFile
[] files
= dir
.getFiles();
350 for (PsiFile file
: files
) {
351 if (file
instanceof PsiJavaFile
) {
352 final PsiJavaFile javaFile
= (PsiJavaFile
)file
;
353 if (containsPackagePrefix(module
, javaFile
.getPackageName())) {
354 sources
.add(PathUtil
.getLocalPath(javaFile
.getVirtualFile()));
356 packages
.add(javaFile
.getPackageName());
364 public static boolean containsPackagePrefix(Module module
, String packageFQName
) {
365 if (module
== null) return false;
366 final ContentEntry
[] contentEntries
= ModuleRootManager
.getInstance(module
).getContentEntries();
367 for (ContentEntry contentEntry
: contentEntries
) {
368 final SourceFolder
[] sourceFolders
= contentEntry
.getSourceFolders();
369 for (SourceFolder sourceFolder
: sourceFolders
) {
370 final String packagePrefix
= sourceFolder
.getPackagePrefix();
371 final int prefixLength
= packagePrefix
.length();
372 if (prefixLength
> 0 && packageFQName
.startsWith(packagePrefix
)) {