08ad4e7b40c0b268f3675ac671e81f0b924a4805
[idea/community.git] / platform / lang-impl / src / com / intellij / codeInspection / ex / HTMLComposerImpl.java
1 /*
2  * Copyright 2000-2009 JetBrains s.r.o.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 /*
18  * Created by IntelliJ IDEA.
19  * User: max
20  * Date: Dec 22, 2001
21  * Time: 4:54:17 PM
22  * To change template for new interface use 
23  * Code Style | Class Templates options (Tools | IDE Options).
24  */
25 package com.intellij.codeInspection.ex;
26
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.util.Key;
37 import com.intellij.psi.PsiElement;
38 import com.intellij.psi.PsiFile;
39 import org.jetbrains.annotations.NonNls;
40 import org.jetbrains.annotations.Nullable;
41
42 import java.net.URL;
43 import java.util.HashMap;
44 import java.util.Map;
45
46 /**
47  * @author max
48  */
49 public abstract class HTMLComposerImpl extends HTMLComposer {
50   protected HTMLExporter myExporter;
51   private final int[] myListStack;
52   private int myListStackTop;
53   private final Map<Key, HTMLComposerExtension> myExtensions = new HashMap<Key, HTMLComposerExtension>();
54   private final Map<Language, HTMLComposerExtension> myLanguageExtensions = new HashMap<Language, HTMLComposerExtension>();
55   @NonNls protected static final String BR = "<br>";
56   @NonNls protected static final String NBSP = "&nbsp;";
57   @NonNls protected static final String CODE_CLOSING = "</code>";
58   @NonNls protected static final String CODE_OPENING = "<code>";
59   @NonNls protected static final String FONT_CLOSING = "</font>";
60   @NonNls protected static final String B_OPENING = "<b>";
61   @NonNls protected static final String B_CLOSING = "</b>";
62   @NonNls protected static final String FONT_OPENING = "<font style=\"font-family:verdana;";
63   @NonNls protected static final String CLOSE_TAG = "\">";
64   @NonNls protected static final String A_HREF_OPENING = "<a HREF=\"";
65   @NonNls protected static final String A_CLOSING = "</a>";
66
67   protected HTMLComposerImpl() {
68     myListStack = new int[5];
69     myListStackTop = -1;
70     for (InspectionExtensionsFactory factory : Extensions.getExtensions(InspectionExtensionsFactory.EP_NAME)) {
71       final HTMLComposerExtension extension = factory.createHTMLComposerExtension(this);
72       if (extension != null) {
73         myExtensions.put(extension.getID(), extension);
74         myLanguageExtensions.put(extension.getLanguage(), extension);
75       }
76     }
77   }
78
79   public abstract void compose(StringBuffer buf, RefEntity refEntity);
80
81   public void compose(StringBuffer buf, RefEntity refElement, CommonProblemDescriptor descriptor) {}
82
83   public void composeWithExporter(StringBuffer buf, RefEntity refEntity, HTMLExporter exporter) {
84     myExporter = exporter;
85     compose(buf, refEntity);
86     myExporter = null;
87   }
88
89   protected void genPageHeader(final StringBuffer buf, RefEntity refEntity) {
90     if (refEntity instanceof RefElement) {
91       RefElement refElement = (RefElement)refEntity;
92
93       appendHeading(buf, InspectionsBundle.message("inspection.offline.view.tool.display.name.title"));
94       buf.append(BR);
95       appendAfterHeaderIndention(buf);
96
97       appendShortName(buf, refElement);
98       buf.append(BR).append(BR);
99
100       appendHeading(buf, InspectionsBundle.message("inspection.export.results.capitalized.location"));
101       buf.append(BR);
102       appendAfterHeaderIndention(buf);
103       appendLocation(buf, refElement);
104       buf.append(BR).append(BR);
105     }
106   }
107
108   private void appendLocation(final StringBuffer buf, final RefElement refElement) {
109     buf.append(FONT_OPENING);
110     buf.append(CLOSE_TAG);
111     final HTMLComposerExtension extension = getLanguageExtension(refElement);
112     if (extension != null) {
113       extension.appendLocation(refElement, buf);
114     }
115     if (refElement instanceof RefFile){
116       buf.append(InspectionsBundle.message("inspection.export.results.file"));
117       buf.append(NBSP);
118       appendElementReference(buf, refElement, false);
119     }
120     buf.append(FONT_CLOSING);
121   }
122
123   @Nullable
124   private HTMLComposerExtension getLanguageExtension(final RefElement refElement) {
125     final PsiElement element = refElement.getElement();
126     return element != null ? myLanguageExtensions.get(element.getLanguage()) : null;
127   }
128
129   private void appendShortName(final StringBuffer buf, RefElement refElement) {
130     final HTMLComposerExtension extension = getLanguageExtension(refElement);
131     if (extension != null) {
132       extension.appendShortName(refElement, buf);
133     }
134     refElement.accept(new RefVisitor() {
135       @Override public void visitFile(RefFile file) {
136         final PsiFile psiFile = file.getElement();
137         buf.append(B_OPENING);
138         buf.append(psiFile.getName());
139         buf.append(B_CLOSING);
140       }
141     });
142   }
143
144   protected void appendQualifiedName(StringBuffer buf, RefEntity refEntity) {
145     if (refEntity == null) return;
146     String qName = "";
147
148     while (!(refEntity instanceof RefProject)) {
149       if (qName.length() > 0) qName = "." + qName;
150
151       String name = refEntity.getName();
152       if (refEntity instanceof RefElement) {
153         final HTMLComposerExtension extension = getLanguageExtension((RefElement)refEntity);
154         if (extension != null) {
155           name = extension.getQualifiedName(refEntity);
156         }
157       }
158
159       qName = name + qName;
160       refEntity = refEntity.getOwner();
161     }
162
163     buf.append(qName);
164   }
165
166   public void appendElementReference(final StringBuffer buf, RefElement refElement) {
167     appendElementReference(buf, refElement, true);
168   }
169
170   public void appendElementReference(final StringBuffer buf, RefElement refElement, String linkText, @NonNls String frameName) {    
171     if (myExporter == null) {
172       final URL url = ((RefElementImpl)refElement).getURL();
173       if (url != null) {
174         appendElementReference(buf, url.toString(), linkText, frameName);
175       }
176     }
177     else {
178       appendElementReference(buf, myExporter.getURL(refElement), linkText, frameName);
179     }
180   }
181
182   public void appendElementReference(final StringBuffer buf, String url, String linkText, @NonNls String frameName) {
183     buf.append(A_HREF_OPENING);
184     buf.append(url);
185     if (frameName != null) {
186       @NonNls final String target = "\" target=\"";
187       buf.append(target);
188       buf.append(frameName);
189     }
190
191     buf.append("\">");
192     buf.append(linkText);
193     buf.append(A_CLOSING);
194   }
195
196   protected void appendQuickFix(@NonNls final StringBuffer buf, String text, int index) {
197     if (myExporter == null) {
198       buf.append(FONT_OPENING);
199       buf.append(CLOSE_TAG);
200       buf.append("<a HREF=\"file://bred.txt#invoke:").append(index);
201       buf.append("\">");
202       buf.append(text);
203       buf.append("</a></font>");
204     }
205   }
206
207   public void appendElementReference(final StringBuffer buf, RefElement refElement, boolean isPackageIncluded) {
208     final HTMLComposerExtension extension = getLanguageExtension(refElement);
209     
210     if (extension != null) {
211       extension.appendReferencePresentation(refElement, buf, isPackageIncluded);
212     } else if (refElement instanceof RefFile) {
213       buf.append(HTMLComposerImpl.A_HREF_OPENING);
214
215       if (myExporter == null) {
216         buf.append(((RefElementImpl)refElement).getURL());
217       }
218       else {
219         buf.append(myExporter.getURL(refElement));
220       }
221
222       buf.append("\">");
223       buf.append(refElement.getName());
224       buf.append(HTMLComposerImpl.A_CLOSING);
225     }
226   }
227
228   public String composeNumereables(int n, String statement, String singleEnding, String multipleEnding) {
229     final StringBuffer buf = new StringBuffer();
230     buf.append(n);
231     buf.append(' ');
232     buf.append(statement);
233
234     if (n % 10 == 1 && n % 100 != 11) {
235       buf.append(singleEnding);
236     }
237     else {
238       buf.append(multipleEnding);
239     }
240     return buf.toString();
241   }
242
243   public void appendElementInReferences(StringBuffer buf, RefElement refElement) {
244     if (refElement.getInReferences().size() > 0) {
245       appendHeading(buf, InspectionsBundle.message("inspection.export.results.used.from"));
246       startList(buf);
247       for (RefElement refCaller : refElement.getInReferences()) {
248         appendListItem(buf, refCaller);
249       }
250       doneList(buf);
251     }
252   }
253
254   public void appendElementOutReferences(StringBuffer buf, RefElement refElement) {
255     if (refElement.getOutReferences().size() > 0) {
256       buf.append(BR);
257       appendHeading(buf, InspectionsBundle.message("inspection.export.results.uses"));
258       startList(buf);
259       for (RefElement refCallee : refElement.getOutReferences()) {
260         appendListItem(buf, refCallee);
261       }
262       doneList(buf);
263     }
264   }
265
266   public void appendListItem(StringBuffer buf, RefElement refElement) {
267     startListItem(buf);
268     buf.append(FONT_OPENING);
269     buf.append(CLOSE_TAG);
270     appendElementReference(buf, refElement, true);
271     appendAdditionalListItemInfo(buf, refElement);
272     buf.append(FONT_CLOSING);
273     doneListItem(buf);
274   }
275
276   protected void appendAdditionalListItemInfo(StringBuffer buf, RefElement refElement) {
277     // Default appends nothing.
278   }
279
280   protected void appendResolution(StringBuffer buf, InspectionTool tool, RefEntity where) {
281     if (myExporter != null) return;
282     if (where instanceof RefElement && !where.isValid()) return;
283     QuickFixAction[] quickFixes = tool.getQuickFixes(new RefEntity[] {where});
284     if (quickFixes != null) {
285       boolean listStarted = false;
286       for (int i = 0; i < quickFixes.length; i++) {
287         QuickFixAction quickFix = quickFixes[i];
288         final String text = quickFix.getText(where);
289         if (text == null) continue;
290         if (!listStarted) {
291           appendHeading(buf, InspectionsBundle.message("inspection.problem.resolution"));
292           startList(buf);
293           listStarted = true;
294         }
295         startListItem(buf);
296         appendQuickFix(buf, text, i);
297         doneListItem(buf);
298       }
299
300       if (listStarted) {
301         doneList(buf);
302       }
303     }
304   }
305
306   public void startList(@NonNls final StringBuffer buf) {
307     buf.append("<ul>");
308     myListStackTop++;
309     myListStack[myListStackTop] = 0;
310   }
311
312   public void doneList(@NonNls StringBuffer buf) {
313     buf.append("</ul>");
314     if (myListStack[myListStackTop] != 0) {
315       buf.append("<table cellpadding=\"0\" border=\"0\" cellspacing=\"0\"><tr><td>&nbsp;</td></tr></table>");
316     }
317     myListStackTop--;
318   }
319
320   public void startListItem(@NonNls StringBuffer buf) {
321     myListStack[myListStackTop]++;
322     buf.append("<li>");
323   }
324
325   public static void doneListItem(@NonNls StringBuffer buf) {
326     buf.append("</li>");
327   }
328
329   public void appendNoProblems(StringBuffer buf) {
330     buf.append(BR);
331     appendAfterHeaderIndention(buf);
332     buf.append(B_OPENING);
333     buf.append(InspectionsBundle.message("inspection.export.results.no.problems.found"));
334     buf.append(B_CLOSING).append(BR);
335   }
336
337   public <T> T getExtension(final Key<T> key) {
338     return (T)myExtensions.get(key);
339   }
340 }