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.offline.view.tool.display.name.title"));
97 appendAfterHeaderIndention(buf);
99 appendShortName(buf, refElement);
100 buf.append(BR).append(BR);
102 appendHeading(buf, InspectionsBundle.message("inspection.export.results.capitalized.location"));
104 appendAfterHeaderIndention(buf);
105 appendLocation(buf, refElement);
106 buf.append(BR).append(BR);
110 private void appendLocation(final StringBuffer buf, final RefElement refElement) {
111 final HTMLComposerExtension extension = getLanguageExtension(refElement);
112 if (extension != null) {
113 extension.appendLocation(refElement, buf);
115 if (refElement instanceof RefFile){
116 buf.append(InspectionsBundle.message("inspection.export.results.file"));
118 appendElementReference(buf, refElement, false);
123 private HTMLComposerExtension getLanguageExtension(final RefElement refElement) {
124 final PsiElement element = refElement.getElement();
125 return element != null ? myLanguageExtensions.get(element.getLanguage()) : null;
128 private void appendShortName(final StringBuffer buf, RefElement refElement) {
129 final HTMLComposerExtension extension = getLanguageExtension(refElement);
130 if (extension != null) {
131 extension.appendShortName(refElement, buf);
133 refElement.accept(new RefVisitor() {
134 @Override public void visitFile(@NotNull RefFile file) {
135 final PsiFile psiFile = file.getElement();
136 if (psiFile != null) {
137 buf.append(B_OPENING);
138 buf.append(psiFile.getName());
139 buf.append(B_CLOSING);
146 protected void appendQualifiedName(StringBuffer buf, RefEntity refEntity) {
147 if (refEntity == null) return;
150 while (!(refEntity instanceof RefProject)) {
151 if (qName.length() > 0) qName = "." + qName;
154 if (refEntity instanceof RefElement) {
155 final HTMLComposerExtension extension = getLanguageExtension((RefElement)refEntity);
156 if (extension != null) {
157 name = extension.getQualifiedName(refEntity);
162 name = refEntity.getName();
165 qName = name + qName;
166 refEntity = refEntity.getOwner();
173 public void appendElementReference(final StringBuffer buf, RefElement refElement) {
174 appendElementReference(buf, refElement, true);
178 public void appendElementReference(final StringBuffer buf, RefElement refElement, String linkText, @NonNls String frameName) {
179 if (myExporter == null) {
180 final String url = ((RefElementImpl)refElement).getURL();
182 appendElementReference(buf, url, linkText, frameName);
186 appendElementReference(buf, myExporter.getURL(refElement), linkText, frameName);
191 public void appendElementReference(final StringBuffer buf, String url, String linkText, @NonNls String frameName) {
192 buf.append(A_HREF_OPENING);
194 if (frameName != null) {
195 @NonNls final String target = "\" target=\"";
197 buf.append(frameName);
201 buf.append(linkText);
202 buf.append(A_CLOSING);
205 protected void appendQuickFix(@NonNls final StringBuffer buf, String text, int index) {
206 if (myExporter == null) {
207 buf.append("<a HREF=\"file://bred.txt#invoke:").append(index);
215 public void appendElementReference(final StringBuffer buf, RefElement refElement, boolean isPackageIncluded) {
216 final HTMLComposerExtension extension = getLanguageExtension(refElement);
218 if (extension != null) {
219 extension.appendReferencePresentation(refElement, buf, isPackageIncluded);
220 } else if (refElement instanceof RefFile) {
221 buf.append(A_HREF_OPENING);
223 if (myExporter == null) {
224 buf.append(((RefElementImpl)refElement).getURL());
227 buf.append(myExporter.getURL(refElement));
231 String refElementName = refElement.getName();
232 final PsiElement element = refElement.getElement();
233 if (element != null) {
234 final VirtualFile virtualFile = PsiUtilCore.getVirtualFile(element);
235 if (virtualFile != null) {
236 refElementName = ProjectUtilCore.displayUrlRelativeToProject(virtualFile, virtualFile.getPresentableUrl(), element.getProject(),
240 buf.append(refElementName);
241 buf.append(A_CLOSING);
246 public String composeNumereables(int n, String statement, String singleEnding, String multipleEnding) {
247 final StringBuilder buf = new StringBuilder();
250 buf.append(statement);
252 if (n % 10 == 1 && n % 100 != 11) {
253 buf.append(singleEnding);
256 buf.append(multipleEnding);
258 return buf.toString();
262 public void appendElementInReferences(StringBuffer buf, RefElement refElement) {
263 if (refElement.getInReferences().size() > 0) {
264 appendHeading(buf, InspectionsBundle.message("inspection.export.results.used.from"));
266 for (RefElement refCaller : refElement.getInReferences()) {
267 appendListItem(buf, refCaller);
274 public void appendElementOutReferences(StringBuffer buf, RefElement refElement) {
275 if (refElement.getOutReferences().size() > 0) {
276 appendHeading(buf, InspectionsBundle.message("inspection.export.results.uses"));
278 for (RefElement refCallee : refElement.getOutReferences()) {
279 appendListItem(buf, refCallee);
286 public void appendListItem(StringBuffer buf, RefElement refElement) {
288 appendElementReference(buf, refElement, true);
289 appendAdditionalListItemInfo(buf, refElement);
293 protected void appendAdditionalListItemInfo(StringBuffer buf, RefElement refElement) {
294 // Default appends nothing.
297 protected void appendResolution(StringBuffer buf, RefEntity where, String[] quickFixes) {
298 if (myExporter != null) return;
299 if (where instanceof RefElement && !where.isValid()) return;
300 if (quickFixes != null) {
301 boolean listStarted = false;
302 for (int i = 0; i < quickFixes.length; i++) {
303 final String text = quickFixes[i];
304 if (text == null) continue;
306 appendHeading(buf, InspectionsBundle.message("inspection.problem.resolution"));
311 appendQuickFix(buf, text, i);
323 public void startList(@NonNls final StringBuffer buf) {
324 if (myListStackTop == -1) {
325 buf.append("<div class=\"problem-description\">");
329 myListStack[myListStackTop] = 0;
333 public void doneList(@NonNls StringBuffer buf) {
335 if (myListStack[myListStackTop] != 0) {
336 buf.append("<table cellpadding=\"0\" border=\"0\" cellspacing=\"0\"><tr><td> </td></tr></table>");
338 if (myListStackTop == 0) {
339 buf.append("</div>");
345 public void startListItem(@NonNls StringBuffer buf) {
346 myListStack[myListStackTop]++;
350 public static void doneListItem(@NonNls StringBuffer buf) {
355 public void appendNoProblems(StringBuffer buf) {
356 buf.append("<p class=\"problem-description-group\">");;
357 buf.append(InspectionsBundle.message("inspection.export.results.no.problems.found"));
362 public <T> T getExtension(final Key<T> key) {
363 return (T)myExtensions.get(key);