Add ability to output HTML report of differences found between two versions.
[cfb.git] / prod / net / jaekl / cfb / analyze / HtmlReport.java
1 package net.jaekl.cfb.analyze;
2
3 import java.io.File;
4 import java.io.FileOutputStream;
5 import java.io.IOException;
6 import java.io.PrintWriter;
7
8 import net.jaekl.cfb.CfbBundle;
9 import net.jaekl.cfb.store.Location;
10 import net.jaekl.cfb.xml.BugInstance;
11 import net.jaekl.cfb.xml.messages.BugPattern;
12 import net.jaekl.cfb.xml.messages.MessageCollection;
13
14 public class HtmlReport {
15         CfbBundle m_bundle;
16         MessageCollection m_msgColl;
17         
18         public HtmlReport(CfbBundle bundle, MessageCollection msgColl)
19         {
20                 m_bundle = bundle;
21                 m_msgColl = msgColl;
22         }
23         
24         public void write(File output, Delta delta) throws IOException
25         {
26                 try ( FileOutputStream fos = new FileOutputStream(output);
27                           PrintWriter pw = new PrintWriter(fos); )
28                 {
29                         write(pw, delta);
30                 }
31         }
32         
33         void write(PrintWriter pw, Delta delta) 
34         {
35                 startPage(pw, delta);
36         }
37         
38         void startPage(PrintWriter pw, Delta delta) 
39         {
40                 writeHeader(pw, delta);
41                 pw.println("  <BODY>");
42                 writeBody(pw, delta);
43                 pw.println("  </BODY>");
44                 pw.println("</HTML>");
45         }
46         
47         String trans(String key, Object... arguments) {
48                 return m_bundle.get(key, arguments);
49         }
50         
51         void writeBody(PrintWriter pw, Delta delta)
52         {
53                 writeSummary(pw, delta);
54                 writeBugs(pw, CfbBundle.NEW_BUGS,   delta.getNew());
55                 writeBugs(pw, CfbBundle.FIXED_BUGS, delta.getFixed());
56                 writeBugs(pw, CfbBundle.OLD_BUGS,   delta.getCommon());
57         }
58         
59         void writeBugLocations(PrintWriter pw, BugInstance bug)
60         {
61                 for (Location loc : bug.getLocations()) {
62                         StringBuffer sb = new StringBuffer();
63                         
64                         if (null != loc) {
65                                 if (null != loc.getClassName()) {
66                                         sb.append(loc.getClassName());
67                                 }
68                                 if ((null != loc.getMethodName()) && (loc.getMethodName().length() > 0)) {
69                                         sb.append(".").append(loc.getMethodName()).append("()");
70                                 }
71                                 int start = loc.getStart();
72                                 int end = loc.getEnd();
73                                 if (start > 0) {
74                                         sb.append(":").append("" + start);
75                                         if ((end > 0) && (end > start)) {
76                                                 sb.append("-").append("" + end);
77                                         }
78                                 }
79                                 
80                                 if (null != loc.getMethodRole()) {
81                                         sb.append(" (" + loc.getMethodRole() + ")");
82                                 }
83                         }
84                         
85                         pw.write("        <TR>");
86                         pw.write("          <TD COLSPAN=\"2\" CLASS=\"Loc\">" + sb.toString() + "</TD>");
87                         pw.write("        </TR>");                                      
88                 }
89         }
90         
91         void writeBugs(PrintWriter pw, String key, BugInstance[] bugs)
92         {
93                 if (null == bugs || bugs.length < 1) {
94                         return;
95                 }
96                 
97                 writeSectionHeading(pw, trans(key));
98                 
99                 for (BugInstance bug : bugs) {
100                         BugPattern pattern = m_msgColl.getPattern(bug.getType());
101                         
102                         pw.write("    <P>");
103                         pw.write("      <TABLE CLASS=\"bug\">");
104                         pw.write("        <TR>");
105                         pw.write("          <TD WIDTH=\"20%\">" + bug.getCategory() + "</TD>");
106                         pw.write("          <TD>" + bug.getType() + "</TD>");
107                         pw.write("        </TR>");
108                         writeBugLocations(pw, bug);
109                         pw.write("        <TR>");
110                         pw.write("          <TD COLSPAN=\"2\">" + pattern.getShort() + "</TD>");
111                         pw.write("        </TR>");
112                         pw.write("        <TR>");
113                         pw.write("          <TD COLSPAN=\"2\">" + pattern.getDetails() + "</TD>");
114                         pw.write("        </TR>");
115                         pw.write("      </TABLE>");
116                         pw.write("    </P>");
117                 }
118         }
119         
120         void writeHeader(PrintWriter pw, Delta delta)
121         {
122                 String title = trans(CfbBundle.CFB_REPORT);
123                 
124                 pw.println("<HTML>");
125                 pw.println("  <HEAD>");
126                 pw.println("    <META CHARSET=\"UTF-8\"/>");
127                 pw.println("    <TITLE>" + title + "</TITLE>");
128                 writeStyle(pw);
129                 pw.println("  </HEAD>");
130         }
131         
132         void writeSectionHeading(PrintWriter pw, String heading)
133         {
134                 pw.println("    <P CLASS=\"SectionHead\">");
135                 pw.println("      <TABLE WIDTH=\"100%\"><TR><TD>" + heading + "</TD></TR></TABLE>");
136                 pw.println("    </P>");
137         }
138         
139         void writeSummary(PrintWriter pw, Delta delta)
140         {
141                 final String SEP = ":&nbsp;&nbsp;";
142                 
143                 writeSectionHeading(pw, trans(CfbBundle.CFB_REPORT));
144                 pw.println("    <P>");
145                 pw.println("      <TABLE>");
146                 pw.println("        <TR>");
147                 pw.println("          <TD CLASS=\"CategoryName\">" + trans(CfbBundle.NEW_VERSION) + SEP + "</TD>");
148                 pw.println("          <TD CLASS=\"CategoryValue\">" + delta.getLater().constructVersionText(m_bundle) + "</TD>");
149                 pw.println("        </TR>");
150                 pw.println("        <TR>");
151                 pw.println("          <TD CLASS=\"CategoryName\">" + trans(CfbBundle.OLD_VERSION) + SEP + "</TD>");
152                 pw.println("          <TD CLASS=\"CategoryValue\">" + delta.getEarlier().constructVersionText(m_bundle) + "</TD>");
153                 pw.println("        </TR>");
154                 pw.println("        <TR><TD>&nbsp;</TD></TR>");
155                 pw.println("        <TR>");
156                 pw.println("          <TD CLASS=\"CategoryName\">" + trans(CfbBundle.NEW_BUGS) + SEP + "</TD>");
157                 pw.println("          <TD CLASS=\"CategoryValue\">" + trans(CfbBundle.NUM_BUGS, delta.getNumNew()) + "</TD>");
158                 pw.println("        </TR>");
159                 pw.println("        <TR>");
160                 pw.println("          <TD CLASS=\"CategoryName\">" + trans(CfbBundle.FIXED_BUGS) + SEP + "</TD>");
161                 pw.println("          <TD CLASS=\"CategoryValue\">" + trans(CfbBundle.NUM_BUGS, delta.getNumFixed()) + "</TD>");
162                 pw.println("        </TR>");
163                 pw.println("        <TR>");
164                 pw.println("          <TD CLASS=\"CategoryName\">" + trans(CfbBundle.OLD_BUGS) + SEP + "</TD>");
165                 pw.println("          <TD CLASS=\"CategoryValue\">" + trans(CfbBundle.NUM_BUGS_OLD, delta.getNumCommon()) + "</TD>");
166                 pw.println("        </TR>");
167                 pw.println("      </TABLE>");
168                 pw.println("    </P>");
169         }
170         
171         void writeStyle(PrintWriter pw)
172         {
173                 pw.println("    <STYLE>");
174                 pw.println("                   body { background-color: #F0F0FF; }");
175             pw.println("    .CategoryName  { text-align: right; }");
176             pw.println("    .CategoryValue { text-align: left; }");
177                 pw.println("    .Loc           { font-family: monospace; }");
178             pw.println("    .SectionHead   td { background-color: #0000FF; color: #FFFFFF; font-size: 1.25em; font-weight: bold; }");
179                 pw.println("    </STYLE>");
180         }
181 }