update copyright
[fedora-idea.git] / java / java-impl / src / com / intellij / lang / java / JavaDocumentationProvider.java
blob26745d57a7bb419be19d3eac2b547de3d77921f7
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.
17 package com.intellij.lang.java;
19 import com.intellij.codeInsight.CodeInsightBundle;
20 import com.intellij.codeInsight.documentation.DocumentationManager;
21 import com.intellij.codeInsight.editorActions.CodeDocumentationUtil;
22 import com.intellij.codeInsight.javadoc.JavaDocExternalFilter;
23 import com.intellij.codeInsight.javadoc.JavaDocInfoGenerator;
24 import com.intellij.codeInsight.javadoc.JavaDocUtil;
25 import com.intellij.featureStatistics.FeatureUsageTracker;
26 import com.intellij.ide.BrowserUtil;
27 import com.intellij.ide.DataManager;
28 import com.intellij.lang.CodeDocumentationAwareCommenter;
29 import com.intellij.lang.LangBundle;
30 import com.intellij.lang.LanguageCommenters;
31 import com.intellij.lang.documentation.CodeDocumentationProvider;
32 import com.intellij.openapi.module.Module;
33 import com.intellij.openapi.module.ModuleUtil;
34 import com.intellij.openapi.project.Project;
35 import com.intellij.openapi.roots.*;
36 import com.intellij.openapi.ui.Messages;
37 import com.intellij.openapi.ui.popup.JBPopup;
38 import com.intellij.openapi.ui.popup.JBPopupFactory;
39 import com.intellij.openapi.ui.popup.PopupStep;
40 import com.intellij.openapi.ui.popup.util.BaseListPopupStep;
41 import com.intellij.openapi.util.io.FileUtil;
42 import com.intellij.openapi.vfs.JarFileSystem;
43 import com.intellij.openapi.vfs.VirtualFile;
44 import com.intellij.openapi.vfs.VirtualFileManager;
45 import com.intellij.openapi.vfs.VirtualFileSystem;
46 import com.intellij.openapi.vfs.ex.http.HttpFileSystem;
47 import com.intellij.psi.*;
48 import com.intellij.psi.impl.beanProperties.BeanPropertyElement;
49 import com.intellij.psi.impl.source.javadoc.PsiDocParamRef;
50 import com.intellij.psi.infos.CandidateInfo;
51 import com.intellij.psi.javadoc.PsiDocComment;
52 import com.intellij.psi.javadoc.PsiDocTag;
53 import com.intellij.psi.util.PsiFormatUtil;
54 import com.intellij.util.ArrayUtil;
55 import com.intellij.util.StringBuilderSpinAllocator;
56 import com.intellij.util.containers.HashMap;
57 import org.jetbrains.annotations.NonNls;
58 import org.jetbrains.annotations.NotNull;
59 import org.jetbrains.annotations.Nullable;
61 import java.util.*;
63 /**
64 * Created by IntelliJ IDEA.
65 * User: Maxim.Mossienko
66 * Date: Apr 11, 2006
67 * Time: 7:45:12 PM
68 * To change this template use File | Settings | File Templates.
70 public class JavaDocumentationProvider implements CodeDocumentationProvider {
71 private static final String LINE_SEPARATOR = "\n";
73 @NonNls private static final String PARAM_TAG = "@param";
74 @NonNls private static final String RETURN_TAG = "@return";
75 @NonNls private static final String THROWS_TAG = "@throws";
76 @NonNls public static final String HTML_EXTENSION = ".html";
77 @NonNls public static final String PACKAGE_SUMMARY_FILE = "package-summary.html";
79 public String getQuickNavigateInfo(PsiElement element) {
80 if (element instanceof PsiClass) {
81 return generateClassInfo((PsiClass)element);
83 else if (element instanceof PsiMethod) {
84 return generateMethodInfo((PsiMethod)element);
86 else if (element instanceof PsiField) {
87 return generateFieldInfo((PsiField)element);
89 else if (element instanceof PsiVariable) {
90 return generateVariableInfo((PsiVariable)element);
92 else if (element instanceof PsiPackage) {
93 return generatePackageInfo((PsiPackage)element);
95 else if (element instanceof BeanPropertyElement) {
96 return generateMethodInfo(((BeanPropertyElement) element).getMethod());
98 return null;
101 public List<String> getUrlFor(final PsiElement element, final PsiElement originalElement) {
102 return getExternalJavaDocUrl(element);
105 private static void newLine(StringBuffer buffer) {
106 // Don't know why space has to be added after newline for good text alignment...
107 buffer.append("\n ");
110 private static void generateType(@NonNls StringBuffer buffer, PsiType type, PsiElement context) {
111 if (type instanceof PsiPrimitiveType) {
112 buffer.append(type.getCanonicalText());
114 return;
117 if (type instanceof PsiWildcardType) {
118 PsiWildcardType wc = ((PsiWildcardType)type);
119 PsiType bound = wc.getBound();
121 buffer.append("?");
123 if (bound != null) {
124 buffer.append(wc.isExtends() ? " extends " : " super ");
125 generateType(buffer, bound, context);
129 if (type instanceof PsiArrayType) {
130 generateType(buffer, ((PsiArrayType)type).getComponentType(), context);
131 if (type instanceof PsiEllipsisType) {
132 buffer.append("...");
134 else {
135 buffer.append("[]");
138 return;
141 if (type instanceof PsiClassType) {
142 PsiClassType.ClassResolveResult result = ((PsiClassType)type).resolveGenerics();
143 PsiClass psiClass = result.getElement();
144 PsiSubstitutor psiSubst = result.getSubstitutor();
146 if (psiClass == null || psiClass instanceof PsiTypeParameter) {
147 buffer.append(type.getPresentableText());
148 return;
151 buffer.append(JavaDocUtil.getShortestClassName(psiClass, context));
153 if (psiClass.hasTypeParameters()) {
154 StringBuffer subst = new StringBuffer();
155 boolean goodSubst = true;
157 PsiTypeParameter[] params = psiClass.getTypeParameters();
159 subst.append("<");
160 for (int i = 0; i < params.length; i++) {
161 PsiType t = psiSubst.substitute(params[i]);
163 if (t == null) {
164 goodSubst = false;
165 break;
168 generateType(subst, t, context);
170 if (i < params.length - 1) {
171 subst.append(", ");
175 if (goodSubst) {
176 subst.append(">");
177 String text = subst.toString();
179 buffer.append(text);
185 private static void generateInitializer(StringBuffer buffer, PsiVariable variable) {
186 PsiExpression initializer = variable.getInitializer();
187 if (initializer != null) {
188 String text = initializer.getText().trim();
189 int index1 = text.indexOf('\n');
190 if (index1 < 0) index1 = text.length();
191 int index2 = text.indexOf('\r');
192 if (index2 < 0) index2 = text.length();
193 int index = Math.min(index1, index2);
194 boolean trunc = index < text.length();
195 text = text.substring(0, index);
196 buffer.append(" = ");
197 buffer.append(text);
198 if (trunc) {
199 buffer.append("...");
204 private static void generateModifiers(StringBuffer buffer, PsiElement element) {
205 String modifiers = PsiFormatUtil.formatModifiers(element, PsiFormatUtil.JAVADOC_MODIFIERS_ONLY);
207 if (modifiers.length() > 0) {
208 buffer.append(modifiers);
209 buffer.append(" ");
213 private static String generatePackageInfo(PsiPackage aPackage) {
214 return aPackage.getQualifiedName();
217 @SuppressWarnings({"HardCodedStringLiteral"})
218 private static String generateClassInfo(PsiClass aClass) {
219 StringBuffer buffer = new StringBuffer();
221 if (aClass instanceof PsiAnonymousClass) return LangBundle.message("java.terms.anonymous.class");
223 PsiFile file = aClass.getContainingFile();
224 final Module module = ModuleUtil.findModuleForPsiElement(file);
225 if (module != null) {
226 buffer.append('[').append(module.getName()).append("] ");
229 if (file instanceof PsiJavaFile) {
230 String packageName = ((PsiJavaFile)file).getPackageName();
231 if (packageName.length() > 0) {
232 buffer.append(packageName);
233 newLine(buffer);
237 generateModifiers(buffer, aClass);
239 final String classString = aClass.isAnnotationType() ? "java.terms.annotation.interface"
240 : aClass.isInterface()
241 ? "java.terms.interface"
242 : aClass instanceof PsiTypeParameter
243 ? "java.terms.type.parameter"
244 : aClass.isEnum() ? "java.terms.enum" : "java.terms.class";
245 buffer.append(LangBundle.message(classString)).append(" ");
247 buffer.append(JavaDocUtil.getShortestClassName(aClass, aClass));
249 if (aClass.hasTypeParameters()) {
250 PsiTypeParameter[] parms = aClass.getTypeParameters();
252 buffer.append("<");
254 for (int i = 0; i < parms.length; i++) {
255 PsiTypeParameter p = parms[i];
257 buffer.append(p.getName());
259 PsiClassType[] refs = p.getExtendsList().getReferencedTypes();
261 if (refs.length > 0) {
262 buffer.append(" extends ");
264 for (int j = 0; j < refs.length; j++) {
265 generateType(buffer, refs[j], aClass);
267 if (j < refs.length - 1) {
268 buffer.append(" & ");
273 if (i < parms.length - 1) {
274 buffer.append(", ");
278 buffer.append(">");
281 PsiClassType[] refs;
282 if (!aClass.isEnum() && !aClass.isAnnotationType()) {
283 PsiReferenceList extendsList = aClass.getExtendsList();
284 refs = extendsList == null ? PsiClassType.EMPTY_ARRAY : extendsList.getReferencedTypes();
285 if (refs.length > 0 || !aClass.isInterface() && !"java.lang.Object".equals(aClass.getQualifiedName())) {
286 buffer.append(" extends ");
287 if (refs.length == 0) {
288 buffer.append("Object");
290 else {
291 for (int i = 0; i < refs.length; i++) {
292 generateType(buffer, refs[i], aClass);
294 if (i < refs.length - 1) {
295 buffer.append(", ");
302 refs = aClass.getImplementsListTypes();
303 if (refs.length > 0) {
304 newLine(buffer);
305 buffer.append("implements ");
306 for (int i = 0; i < refs.length; i++) {
307 generateType(buffer, refs[i], aClass);
309 if (i < refs.length - 1) {
310 buffer.append(", ");
315 return buffer.toString();
318 @SuppressWarnings({"HardCodedStringLiteral"})
319 public static String generateMethodInfo(PsiMethod method) {
320 StringBuffer buffer = new StringBuffer();
322 PsiClass parentClass = method.getContainingClass();
324 if (parentClass != null) {
325 buffer.append(JavaDocUtil.getShortestClassName(parentClass, method));
326 newLine(buffer);
329 generateModifiers(buffer, method);
331 PsiTypeParameter[] params = method.getTypeParameters();
333 if (params.length > 0) {
334 buffer.append("<");
335 for (int i = 0; i < params.length; i++) {
336 PsiTypeParameter param = params[i];
338 buffer.append(param.getName());
340 PsiClassType[] extendees = param.getExtendsList().getReferencedTypes();
342 if (extendees.length > 0) {
343 buffer.append(" extends ");
345 for (int j = 0; j < extendees.length; j++) {
346 generateType(buffer, extendees[j], method);
348 if (j < extendees.length - 1) {
349 buffer.append(" & ");
354 if (i < params.length - 1) {
355 buffer.append(", ");
358 buffer.append("> ");
361 if (method.getReturnType() != null) {
362 generateType(buffer, method.getReturnType(), method);
363 buffer.append(" ");
366 buffer.append(method.getName());
368 buffer.append(" (");
369 PsiParameter[] parms = method.getParameterList().getParameters();
370 for (int i = 0; i < parms.length; i++) {
371 PsiParameter parm = parms[i];
372 generateType(buffer, parm.getType(), method);
373 buffer.append(" ");
374 if (parm.getName() != null) {
375 buffer.append(parm.getName());
377 if (i < parms.length - 1) {
378 buffer.append(", ");
382 buffer.append(")");
384 PsiClassType[] refs = method.getThrowsList().getReferencedTypes();
385 if (refs.length > 0) {
386 newLine(buffer);
387 buffer.append(" throws ");
388 for (int i = 0; i < refs.length; i++) {
389 PsiClass throwsClass = refs[i].resolve();
391 if (throwsClass != null) {
392 buffer.append(JavaDocUtil.getShortestClassName(throwsClass, method));
394 else {
395 buffer.append(refs[i].getPresentableText());
398 if (i < refs.length - 1) {
399 buffer.append(", ");
404 return buffer.toString();
407 private static String generateFieldInfo(PsiField field) {
408 StringBuffer buffer = new StringBuffer();
409 PsiClass parentClass = field.getContainingClass();
411 if (parentClass != null) {
412 buffer.append(JavaDocUtil.getShortestClassName(parentClass, field));
413 newLine(buffer);
416 generateModifiers(buffer, field);
418 generateType(buffer, field.getType(), field);
419 buffer.append(" ");
420 buffer.append(field.getName());
422 generateInitializer(buffer, field);
424 return buffer.toString();
427 private static String generateVariableInfo(PsiVariable variable) {
428 StringBuffer buffer = new StringBuffer();
430 generateModifiers(buffer, variable);
432 generateType(buffer, variable.getType(), variable);
434 buffer.append(" ");
436 buffer.append(variable.getName());
437 generateInitializer(buffer, variable);
439 return buffer.toString();
442 public PsiComment findExistingDocComment(final PsiComment _element) {
443 PsiElement parentElement = _element.getParent();
445 return parentElement instanceof PsiDocCommentOwner ? ((PsiDocCommentOwner)parentElement).getDocComment() : null;
448 public String generateDocumentationContentStub(PsiComment _element) {
449 PsiElement parentElement = _element.getParent();
450 final Project project = _element.getProject();
451 final StringBuilder builder = StringBuilderSpinAllocator.alloc();
452 try {
453 if (parentElement instanceof PsiMethod) {
454 PsiMethod psiMethod = (PsiMethod)parentElement;
455 final PsiParameter[] parameters = psiMethod.getParameterList().getParameters();
456 final CodeDocumentationAwareCommenter commenter = (CodeDocumentationAwareCommenter)LanguageCommenters.INSTANCE
457 .forLanguage(parentElement.getLanguage());
458 final Map<String, String> param2Description = new HashMap<String, String>();
459 final PsiMethod[] superMethods = psiMethod.findSuperMethods();
460 for (PsiMethod superMethod : superMethods) {
461 final PsiDocComment comment = superMethod.getDocComment();
462 if (comment != null) {
463 final PsiDocTag[] params = comment.findTagsByName("param");
464 for (PsiDocTag param : params) {
465 final PsiElement[] dataElements = param.getDataElements();
466 if (dataElements != null) {
467 String paramName = null;
468 for (PsiElement dataElement : dataElements) {
469 if (dataElement instanceof PsiDocParamRef) {
470 paramName = dataElement.getReference().getCanonicalText();
471 break;
474 if (paramName != null) {
475 param2Description.put(paramName, param.getText());
481 for (PsiParameter parameter : parameters) {
482 String description = param2Description.get(parameter.getName());
483 if (description != null) {
484 builder.append(CodeDocumentationUtil.createDocCommentLine("", project, commenter));
485 if (description.indexOf('\n') > -1) description = description.substring(0, description.lastIndexOf('\n'));
486 builder.append(description);
488 else {
489 builder.append(CodeDocumentationUtil.createDocCommentLine(PARAM_TAG, project, commenter));
490 builder.append(parameter.getName());
492 builder.append(LINE_SEPARATOR);
495 final PsiTypeParameterList typeParameterList = psiMethod.getTypeParameterList();
496 if (typeParameterList != null) {
497 createTypeParamsListComment(builder, project, commenter, typeParameterList);
499 if (psiMethod.getReturnType() != null && psiMethod.getReturnType() != PsiType.VOID) {
500 builder.append(CodeDocumentationUtil.createDocCommentLine(RETURN_TAG, project, commenter));
501 builder.append(LINE_SEPARATOR);
504 final PsiJavaCodeReferenceElement[] references = psiMethod.getThrowsList().getReferenceElements();
505 for (PsiJavaCodeReferenceElement reference : references) {
506 builder.append(CodeDocumentationUtil.createDocCommentLine(THROWS_TAG, project, commenter));
507 builder.append(reference.getText());
508 builder.append(LINE_SEPARATOR);
511 else if (parentElement instanceof PsiClass) {
512 final PsiTypeParameterList typeParameterList = ((PsiClass)parentElement).getTypeParameterList();
513 if (typeParameterList != null) {
514 final CodeDocumentationAwareCommenter commenter = (CodeDocumentationAwareCommenter)LanguageCommenters.INSTANCE
515 .forLanguage(parentElement.getLanguage());
516 createTypeParamsListComment(builder, project, commenter, typeParameterList);
519 return builder.length() > 0 ? builder.toString() : null;
521 finally {
522 StringBuilderSpinAllocator.dispose(builder);
526 private static void createTypeParamsListComment(final StringBuilder buffer,
527 final Project project,
528 final CodeDocumentationAwareCommenter commenter,
529 final PsiTypeParameterList typeParameterList) {
530 final PsiTypeParameter[] typeParameters = typeParameterList.getTypeParameters();
531 for (PsiTypeParameter typeParameter : typeParameters) {
532 buffer.append(CodeDocumentationUtil.createDocCommentLine(PARAM_TAG, project, commenter));
533 buffer.append("<").append(typeParameter.getName()).append(">");
534 buffer.append(LINE_SEPARATOR);
538 public String generateDoc(final PsiElement element, final PsiElement originalElement) {
539 if (element instanceof PsiMethodCallExpression) {
540 return getMethodCandidateInfo((PsiMethodCallExpression)element);
544 //external documentation finder
545 return generateExternalJavadoc(element);
548 public PsiElement getDocumentationElementForLookupItem(final PsiManager psiManager, final Object object, final PsiElement element) {
549 return null;
552 @Nullable
553 public static String generateExternalJavadoc(final PsiElement element) {
554 final JavaDocInfoGenerator javaDocInfoGenerator = new JavaDocInfoGenerator(element.getProject(), element);
555 JavaDocExternalFilter docFilter = new JavaDocExternalFilter(element.getProject());
556 List<String> docURLs = getExternalJavaDocUrl(element);
558 if (docURLs != null) {
559 for (String docURL : docURLs) {
560 final String javadoc = generateExternalJavadoc(element, docURL, true, docFilter);
561 if (javadoc != null) return javadoc;
565 return JavaDocExternalFilter.filterInternalDocInfo(javaDocInfoGenerator.generateDocInfo());
569 @Nullable
570 private static String generateExternalJavadoc(final PsiElement element, String fromUrl, boolean checkCompiled, JavaDocExternalFilter filter) {
571 if (!checkCompiled || element instanceof PsiCompiledElement) {
572 try {
573 String externalDoc = filter.getExternalDocInfoForElement(fromUrl, element);
574 if (externalDoc != null && externalDoc.length() > 0) {
575 return externalDoc;
578 catch (Exception e) {
579 //try to generate some javadoc
582 return null;
585 private String getMethodCandidateInfo(PsiMethodCallExpression expr) {
586 final PsiResolveHelper rh = JavaPsiFacade.getInstance(expr.getProject()).getResolveHelper();
587 final CandidateInfo[] candidates = rh.getReferencedMethodCandidates(expr, true);
588 final String text = expr.getText();
589 if (candidates.length > 0) {
590 @NonNls final StringBuffer sb = new StringBuffer();
592 for (final CandidateInfo candidate : candidates) {
593 final PsiElement element = candidate.getElement();
595 if (!(element instanceof PsiMethod)) {
596 continue;
599 final String str = PsiFormatUtil.formatMethod((PsiMethod)element, candidate.getSubstitutor(),
600 PsiFormatUtil.SHOW_NAME | PsiFormatUtil.SHOW_TYPE | PsiFormatUtil.SHOW_PARAMETERS,
601 PsiFormatUtil.SHOW_TYPE);
602 createElementLink(sb, element, str);
605 return CodeInsightBundle.message("javadoc.candiates", text, sb);
608 return CodeInsightBundle.message("javadoc.candidates.not.found", text);
611 private void createElementLink(@NonNls final StringBuffer sb, final PsiElement element, final String str) {
612 sb.append("&nbsp;&nbsp;<a href=\"psi_element://");
613 sb.append(JavaDocUtil.getReferenceText(element.getProject(), element));
614 sb.append("\">");
615 sb.append(str);
616 sb.append("</a>");
617 sb.append("<br>");
620 public boolean isExternalDocumentationEnabled(final PsiElement element, final PsiElement originalElement) {
621 boolean actionEnabled = element != null && getExternalJavaDocUrl(element) != null;
622 if (element instanceof PsiVariable && !(element instanceof PsiField)) {
623 actionEnabled = false;
625 return actionEnabled;
628 public String getExternalDocumentation(@NotNull final String url, final Project project) throws Exception {
629 if (JavaDocExternalFilter.isJavaDocURL(url)) {
630 String text = new JavaDocExternalFilter(project).getExternalDocInfo(url);
631 if (text != null) {
632 return text;
635 return null;
638 public void openExternalDocumentation(final PsiElement element, final PsiElement originalElement) {
639 FeatureUsageTracker.getInstance().triggerFeatureUsed("codeassists.javadoc.external");
640 List<String> urls = getExternalJavaDocUrl(element);
641 if (urls != null && !urls.isEmpty()) {
642 final JavaDocExternalFilter filter = new JavaDocExternalFilter(element.getProject());
643 for (Iterator<String> it = urls.iterator(); it.hasNext();) {
644 String url = it.next();
645 if (generateExternalJavadoc(element, url, false, filter) == null) it.remove();
647 final HashSet<String> set = new HashSet<String>(urls);
648 if (set.size() > 1) {
649 JBPopupFactory.getInstance().createListPopup(new BaseListPopupStep<String>("Choose javadoc root", ArrayUtil.toStringArray(set)) {
650 public PopupStep onChosen(final String selectedValue, final boolean finalChoice) {
651 BrowserUtil.launchBrowser(selectedValue);
652 return PopupStep.FINAL_CHOICE;
654 }).showInBestPositionFor(DataManager.getInstance().getDataContext());
656 else if (set.size() == 1){
657 BrowserUtil.launchBrowser(urls.get(0));
660 else {
661 final JBPopup docInfoHint = DocumentationManager.getInstance(element.getProject()).getDocInfoHint();
662 if (docInfoHint != null && docInfoHint.isVisible()) {
663 docInfoHint.cancel();
665 Messages.showMessageDialog(element.getProject(), CodeInsightBundle.message("javadoc.documentation.not.found.message"),
666 CodeInsightBundle.message("javadoc.documentation.not.found.title"), Messages.getErrorIcon());
670 @Nullable
671 public static List<String> getExternalJavaDocUrl(final PsiElement element) {
672 List<String> urls = null;
674 if (element instanceof PsiClass) {
675 urls = findUrlForClass((PsiClass)element);
677 else if (element instanceof PsiField) {
678 PsiField field = (PsiField)element;
679 PsiClass aClass = field.getContainingClass();
680 if (aClass != null) {
681 urls = findUrlForClass(aClass);
682 if (urls != null) {
683 for (int i = 0; i < urls.size(); i++) {
684 urls.set(i, urls.get(i) + "#" + field.getName());
689 else if (element instanceof PsiMethod) {
690 PsiMethod method = (PsiMethod)element;
691 PsiClass aClass = method.getContainingClass();
692 if (aClass != null) {
693 final List<String> classUrls = findUrlForClass(aClass);
695 if (classUrls != null) {
696 urls = new ArrayList<String>();
697 String signature = PsiFormatUtil.formatMethod(method, PsiSubstitutor.EMPTY,
698 PsiFormatUtil.SHOW_NAME | PsiFormatUtil.SHOW_PARAMETERS | PsiFormatUtil.SHOW_RAW_TYPE,
699 PsiFormatUtil.SHOW_TYPE | PsiFormatUtil.SHOW_FQ_CLASS_NAMES | PsiFormatUtil.SHOW_RAW_TYPE, 999);
700 for (String classUrl : classUrls) {
701 urls.add(classUrl + "#" + signature);
703 signature = PsiFormatUtil.formatMethod(method, PsiSubstitutor.EMPTY,
704 PsiFormatUtil.SHOW_NAME | PsiFormatUtil.SHOW_PARAMETERS,
705 PsiFormatUtil.SHOW_TYPE | PsiFormatUtil.SHOW_FQ_CLASS_NAMES, 999);
706 for (String classUrl : classUrls) {
707 urls.add(classUrl + "#" + signature);
712 else if (element instanceof PsiPackage) {
713 urls = findUrlForPackage((PsiPackage)element);
715 else if (element instanceof PsiDirectory) {
716 PsiPackage aPackage = JavaDirectoryService.getInstance().getPackage(((PsiDirectory)element));
717 if (aPackage != null) {
718 urls = findUrlForPackage(aPackage);
722 if (urls == null) {
723 return null;
725 else {
726 for (int i = 0; i < urls.size(); i++) {
727 urls.set(i, FileUtil.toSystemIndependentName(urls.get(i)));
729 return urls;
733 @Nullable
734 public static List<String> findUrlForClass(PsiClass aClass) {
735 String qName = aClass.getQualifiedName();
736 if (qName == null) return null;
737 PsiFile file = aClass.getContainingFile();
738 if (!(file instanceof PsiJavaFile)) return null;
739 String packageName = ((PsiJavaFile)file).getPackageName();
741 String relPath;
742 if (packageName.length() > 0) {
743 relPath = packageName.replace('.', '/') + '/' + qName.substring(packageName.length() + 1) + HTML_EXTENSION;
745 else {
746 relPath = qName + HTML_EXTENSION;
749 final PsiFile containingFile = aClass.getContainingFile();
750 if (containingFile == null) return null;
751 final VirtualFile virtualFile = containingFile.getVirtualFile();
752 if (virtualFile == null) return null;
754 return findUrlForVirtualFile(containingFile.getProject(), virtualFile, relPath);
757 @Nullable
758 public static List<String> findUrlForVirtualFile(final Project project, final VirtualFile virtualFile, final String relPath) {
759 final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(project).getFileIndex();
760 Module module = fileIndex.getModuleForFile(virtualFile);
761 if (module == null) {
762 final VirtualFileSystem fs = virtualFile.getFileSystem();
763 if (fs instanceof JarFileSystem) {
764 final VirtualFile jar = ((JarFileSystem)fs).getVirtualFileForJar(virtualFile);
765 if (jar != null) {
766 module = fileIndex.getModuleForFile(jar);
770 if (module != null) {
771 String[] javadocPaths = ModuleRootManager.getInstance(module).getRootUrls(JavadocOrderRootType.getInstance());
772 List<String> httpRoot = getHttpRoots(javadocPaths, relPath);
773 if (httpRoot != null) return httpRoot;
776 final List<OrderEntry> orderEntries = fileIndex.getOrderEntriesForFile(virtualFile);
777 for (OrderEntry orderEntry : orderEntries) {
778 final String[] files = orderEntry.getUrls(JavadocOrderRootType.getInstance());
779 final List<String> httpRoot = getHttpRoots(files, relPath);
780 if (httpRoot != null) return httpRoot;
782 return null;
785 @Nullable
786 public static List<String> getHttpRoots(final String[] roots, String relPath) {
787 final ArrayList<String> result = new ArrayList<String>();
788 for (String root : roots) {
789 final VirtualFile virtualFile = VirtualFileManager.getInstance().findFileByUrl(root);
790 if (virtualFile != null) {
791 if (virtualFile.getFileSystem() instanceof HttpFileSystem) {
792 String url = virtualFile.getUrl();
793 if (!url.endsWith("/")) url += "/";
794 result.add(url + relPath);
796 else {
797 VirtualFile file = virtualFile.findFileByRelativePath(relPath);
798 if (file != null) result.add(file.getUrl());
803 return result.isEmpty() ? null : result;
806 @Nullable
807 public static List<String> findUrlForPackage(PsiPackage aPackage) {
808 String qName = aPackage.getQualifiedName();
809 qName = qName.replace('.', '/') + '/' + PACKAGE_SUMMARY_FILE;
810 for (PsiDirectory directory : aPackage.getDirectories()) {
811 List<String> url = findUrlForVirtualFile(aPackage.getProject(), directory.getVirtualFile(), qName);
812 if (url != null) {
813 return url;
816 return null;
819 public PsiElement getDocumentationElementForLink(final PsiManager psiManager, final String link, final PsiElement context) {
820 return JavaDocUtil.findReferenceTarget(psiManager, link, context);