2 * Copyright 2000-2015 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.
18 * Created by IntelliJ IDEA.
22 * To change template for new interface use
23 * Code Style | Class Templates options (Tools | IDE Options).
25 package com.intellij.codeInspection.ex;
27 import com.intellij.codeInspection.CommonProblemDescriptor;
28 import com.intellij.codeInspection.HTMLComposer;
29 import com.intellij.codeInspection.InspectionsBundle;
30 import com.intellij.codeInspection.export.HTMLExporter;
31 import com.intellij.codeInspection.lang.HTMLComposerExtension;
32 import com.intellij.codeInspection.lang.InspectionExtensionsFactory;
33 import com.intellij.codeInspection.reference.*;
34 import com.intellij.lang.Language;
35 import com.intellij.openapi.extensions.Extensions;
36 import com.intellij.openapi.project.ProjectUtilCore;
37 import com.intellij.openapi.util.Key;
38 import com.intellij.openapi.vfs.VirtualFile;
39 import com.intellij.psi.PsiElement;
40 import com.intellij.psi.PsiFile;
41 import com.intellij.psi.util.PsiUtilCore;
42 import org.jetbrains.annotations.NonNls;
43 import org.jetbrains.annotations.NotNull;
44 import org.jetbrains.annotations.Nullable;
46 import java.util.HashMap;
52 public abstract class HTMLComposerImpl extends HTMLComposer {
53 protected HTMLExporter myExporter;
54 private final int[] myListStack;
55 private int myListStackTop;
56 private final Map<Key, HTMLComposerExtension> myExtensions = new HashMap<Key, HTMLComposerExtension>();
57 private final Map<Language, HTMLComposerExtension> myLanguageExtensions = new HashMap<Language, HTMLComposerExtension>();
58 @NonNls protected static final String BR = "<br>";
59 @NonNls protected static final String NBSP = " ";
60 @NonNls protected static final String CODE_CLOSING = "</code>";
61 @NonNls protected static final String CODE_OPENING = "<code>";
62 @NonNls protected static final String B_OPENING = "<b>";
63 @NonNls protected static final String B_CLOSING = "</b>";
65 @NonNls protected static final String CLOSE_TAG = "\">";
66 @NonNls protected static final String A_HREF_OPENING = "<a HREF=\"";
67 @NonNls protected static final String A_CLOSING = "</a>";
69 protected HTMLComposerImpl() {
70 myListStack = new int[5];
72 for (InspectionExtensionsFactory factory : Extensions.getExtensions(InspectionExtensionsFactory.EP_NAME)) {
73 final HTMLComposerExtension extension = factory.createHTMLComposerExtension(this);
74 if (extension != null) {
75 myExtensions.put(extension.getID(), extension);
76 myLanguageExtensions.put(extension.getLanguage(), extension);
81 public abstract void compose(StringBuffer buf, RefEntity refEntity);
83 public void compose(StringBuffer buf, RefEntity refElement, CommonProblemDescriptor descriptor) {}
85 public void composeWithExporter(StringBuffer buf, RefEntity refEntity, HTMLExporter exporter) {
86 myExporter = exporter;
87 compose(buf, refEntity);
91 protected void genPageHeader(final StringBuffer buf, RefEntity refEntity) {
92 if (refEntity instanceof RefElement) {
93 RefElement refElement = (RefElement)refEntity;
95 appendHeading(buf, InspectionsBundle.message("inspection.export.results.capitalized.location"));
96 buf.append("<div class=\"location\">");
97 appendShortName(buf, refElement);
100 appendLocation(buf, refElement);
101 buf.append("</div>");
102 buf.append(BR).append(BR);
106 private void appendLocation(final StringBuffer buf, final RefElement refElement) {
107 final HTMLComposerExtension extension = getLanguageExtension(refElement);
108 if (extension != null) {
109 extension.appendLocation(refElement, buf);
111 if (refElement instanceof RefFile){
112 buf.append(InspectionsBundle.message("inspection.export.results.file"));
114 appendElementReference(buf, refElement, false);
119 private HTMLComposerExtension getLanguageExtension(final RefElement refElement) {
120 final PsiElement element = refElement.getElement();
121 return element != null ? myLanguageExtensions.get(element.getLanguage()) : null;
124 private void appendShortName(final StringBuffer buf, RefElement refElement) {
125 final HTMLComposerExtension extension = getLanguageExtension(refElement);
126 if (extension != null) {
127 extension.appendShortName(refElement, buf);
129 refElement.accept(new RefVisitor() {
130 @Override public void visitFile(@NotNull RefFile file) {
131 final PsiFile psiFile = file.getElement();
132 if (psiFile != null) {
133 buf.append(B_OPENING);
134 buf.append(psiFile.getName());
135 buf.append(B_CLOSING);
142 protected void appendQualifiedName(StringBuffer buf, RefEntity refEntity) {
143 if (refEntity == null) return;
146 while (!(refEntity instanceof RefProject)) {
147 if (qName.length() > 0) qName = "." + qName;
150 if (refEntity instanceof RefElement) {
151 final HTMLComposerExtension extension = getLanguageExtension((RefElement)refEntity);
152 if (extension != null) {
153 name = extension.getQualifiedName(refEntity);
158 name = refEntity.getName();
161 qName = name + qName;
162 refEntity = refEntity.getOwner();
169 public void appendElementReference(final StringBuffer buf, RefElement refElement) {
170 appendElementReference(buf, refElement, true);
174 public void appendElementReference(final StringBuffer buf, RefElement refElement, String linkText, @NonNls String frameName) {
175 if (myExporter == null) {
176 final String url = ((RefElementImpl)refElement).getURL();
178 appendElementReference(buf, url, linkText, frameName);
182 appendElementReference(buf, myExporter.getURL(refElement), linkText, frameName);
187 public void appendElementReference(final StringBuffer buf, String url, String linkText, @NonNls String frameName) {
188 buf.append(A_HREF_OPENING);
190 if (frameName != null) {
191 @NonNls final String target = "\" target=\"";
193 buf.append(frameName);
197 buf.append(linkText);
198 buf.append(A_CLOSING);
201 protected void appendQuickFix(@NonNls final StringBuffer buf, String text, int index) {
202 if (myExporter == null) {
203 buf.append("<a HREF=\"file://bred.txt#invoke:").append(index);
211 public void appendElementReference(final StringBuffer buf, RefElement refElement, boolean isPackageIncluded) {
212 final HTMLComposerExtension extension = getLanguageExtension(refElement);
214 if (extension != null) {
215 extension.appendReferencePresentation(refElement, buf, isPackageIncluded);
216 } else if (refElement instanceof RefFile) {
217 buf.append(A_HREF_OPENING);
219 if (myExporter == null) {
220 buf.append(((RefElementImpl)refElement).getURL());
223 buf.append(myExporter.getURL(refElement));
227 String refElementName = refElement.getName();
228 final PsiElement element = refElement.getElement();
229 if (element != null) {
230 final VirtualFile virtualFile = PsiUtilCore.getVirtualFile(element);
231 if (virtualFile != null) {
232 refElementName = ProjectUtilCore.displayUrlRelativeToProject(virtualFile, virtualFile.getPresentableUrl(), element.getProject(),
236 buf.append(refElementName);
237 buf.append(A_CLOSING);
242 public String composeNumereables(int n, String statement, String singleEnding, String multipleEnding) {
243 final StringBuilder buf = new StringBuilder();
246 buf.append(statement);
248 if (n % 10 == 1 && n % 100 != 11) {
249 buf.append(singleEnding);
252 buf.append(multipleEnding);
254 return buf.toString();
258 public void appendElementInReferences(StringBuffer buf, RefElement refElement) {
259 if (refElement.getInReferences().size() > 0) {
260 appendHeading(buf, InspectionsBundle.message("inspection.export.results.used.from"));
262 for (RefElement refCaller : refElement.getInReferences()) {
263 appendListItem(buf, refCaller);
270 public void appendElementOutReferences(StringBuffer buf, RefElement refElement) {
271 if (refElement.getOutReferences().size() > 0) {
272 appendHeading(buf, InspectionsBundle.message("inspection.export.results.uses"));
274 for (RefElement refCallee : refElement.getOutReferences()) {
275 appendListItem(buf, refCallee);
282 public void appendListItem(StringBuffer buf, RefElement refElement) {
284 appendElementReference(buf, refElement, true);
285 appendAdditionalListItemInfo(buf, refElement);
289 protected void appendAdditionalListItemInfo(StringBuffer buf, RefElement refElement) {
290 // Default appends nothing.
293 protected void appendResolution(StringBuffer buf, RefEntity where, String[] quickFixes) {
294 if (myExporter != null) return;
295 if (where instanceof RefElement && !where.isValid()) return;
296 if (quickFixes != null) {
297 boolean listStarted = false;
298 for (int i = 0; i < quickFixes.length; i++) {
299 final String text = quickFixes[i];
300 if (text == null) continue;
302 appendHeading(buf, InspectionsBundle.message("inspection.problem.resolution"));
307 appendQuickFix(buf, text, i);
319 public void startList(@NonNls final StringBuffer buf) {
320 if (myListStackTop == -1) {
321 buf.append("<div class=\"problem-description\">");
325 myListStack[myListStackTop] = 0;
329 public void doneList(@NonNls StringBuffer buf) {
331 if (myListStack[myListStackTop] != 0) {
332 buf.append("<table cellpadding=\"0\" border=\"0\" cellspacing=\"0\"><tr><td> </td></tr></table>");
334 if (myListStackTop == 0) {
335 buf.append("</div>");
341 public void startListItem(@NonNls StringBuffer buf) {
342 myListStack[myListStackTop]++;
346 public static void doneListItem(@NonNls StringBuffer buf) {
351 public void appendNoProblems(StringBuffer buf) {
352 buf.append("<p class=\"problem-description-group\">");;
353 buf.append(InspectionsBundle.message("inspection.export.results.no.problems.found"));
358 public <T> T getExtension(final Key<T> key) {
359 return (T)myExtensions.get(key);