update copyright
[fedora-idea.git] / java / java-impl / src / com / intellij / javadoc / JavadocConfiguration.java
blob06801b122828d84d5e912d917ed5f7b2c75a607e
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.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;
52 import java.io.File;
53 import java.util.ArrayList;
54 import java.util.Collection;
56 /**
57 * @author Eugene Zhuravlev
58 * Date: Apr 24, 2004
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;
74 public String LOCALE;
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) {
99 myProject = 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);
120 @NotNull
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) {
139 super(null);
140 myGenerationOptions = generationOptions;
141 myProject = project;
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);
153 return 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");
166 else {
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");
208 if (!OPTION_INDEX) {
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(
255 new Runnable(){
256 public void run() {
257 FileIndex fileIndex = ProjectRootManager.getInstance(myProject).getFileIndex();
258 VirtualFile startingFile = null;
259 if (myGenerationOptions.isGenerationForPackage) {
260 if (!myGenerationOptions.isGenerationWithSubpackages) {
261 packages.add(myGenerationOptions.myPackageFQName);
262 return;
264 startingFile = myGenerationOptions.myDirectory.getVirtualFile();
266 MyContentIterator contentIterator = new MyContentIterator(myProject, packages, sources);
267 if (startingFile == null) {
268 fileIndex.iterateContent(contentIterator);
270 else {
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());
296 return handler;
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()) {
313 return true;
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))) {
319 return true;
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));
327 return true;
329 else {
330 processDirWithJavaFiles(directory, myPackages, mySourceFiles, module);
333 return true;
336 @Nullable
337 private PsiDirectory getPsiDirectory(VirtualFile fileOrDir) {
338 return fileOrDir != null ? myPsiManager.findDirectory(fileOrDir) : null;
341 @Nullable
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()));
355 } else {
356 packages.add(javaFile.getPackageName());
358 return true;
361 return false;
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)) {
373 return true;
377 return false;