ReportPage.java
1/*******************************************************************************
2 * Copyright (c) 2009, 2010 Mountainminds GmbH & Co. KG and Contributors
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 * Marc R. Hoffmann - initial API and implementation
10 *
11 * $Id: $
12 *******************************************************************************/
13package org.jacoco.report.html;
14
15import java.io.IOException;
16
17import org.jacoco.core.JaCoCo;
18import org.jacoco.core.analysis.ICoverageNode;
19import org.jacoco.report.IReportVisitor;
20import org.jacoco.report.ISourceFileLocator;
21import org.jacoco.report.ReportOutputFolder;
22import org.jacoco.report.html.resources.Resources;
23import org.jacoco.report.html.resources.Styles;
24
25/**
26 * Base class for HTML page generators. It renders the page skeleton with the
27 * breadcrumb, the title and the footer.
28 *
29 * @author Marc R. Hoffmann
30 * @version $Revision: $
31 */
32public abstract class ReportPage implements IReportVisitor, ICoverageTableItem {
33
34 private final ReportPage parent;
35
36 /** output folder for this node */
37 protected final ReportOutputFolder outputFolder;
38
39 /** context for this report */
40 protected final IHTMLReportContext context;
41
42 private ICoverageNode node;
43
44 /**
45 * Creates a new report page.
46 *
47 * @param node
48 * corresponding node
49 * @param parent
50 * optional hierarchical parent
51 * @param baseFolder
52 * base folder to create this report page relative to
53 * @param context
54 * settings context
55 */
56 protected ReportPage(final ICoverageNode node, final ReportPage parent,
57 final ReportOutputFolder baseFolder,
58 final IHTMLReportContext context) {
59 this.node = node;
60 this.parent = parent;
61 this.context = context;
62 this.outputFolder = getFolder(baseFolder);
63 }
64
65 public void visitEnd(final ISourceFileLocator sourceFileLocator)
66 throws IOException {
67 renderDocument(sourceFileLocator);
68 this.node = node.getPlainCopy();
69 }
70
71 private void renderDocument(final ISourceFileLocator sourceFileLocator)
72 throws IOException {
73 final HTMLDocument doc = new HTMLDocument(outputFolder
74 .createFile(getFileName()), context.getOutputEncoding());
75 head(doc.head());
76 body(doc.body(), sourceFileLocator);
77 doc.close();
78 }
79
80 /**
81 * Fills the content of the 'head' element.
82 *
83 * @param head
84 * enclosing head element
85 * @throws IOException
86 * in case of IO problems with the report writer
87 */
88 protected void head(final HTMLElement head) throws IOException {
89 head.meta("Content-Type", "text/html;charset=UTF-8");
90 head.link("stylesheet", context.getResources().getLink(outputFolder,
91 Resources.STYLESHEET), "text/css");
92 head.link("shortcut icon", context.getResources().getLink(outputFolder,
93 "session.gif"), "image/gif");
94 head.title().text(getLabel());
95 }
96
97 /**
98 * Renders the content of the body element.
99 *
100 * @param body
101 * enclosing body element
102 * @param sourceFileLocator
103 * locator for source file content in this context
104 * @throws IOException
105 * in case of IO problems with the report writer
106 */
107 protected void body(final HTMLElement body,
108 final ISourceFileLocator sourceFileLocator) throws IOException {
109 breadcrumb(body.div(Styles.BREADCRUMB), outputFolder, this);
110 body.h1().text(getLabel());
111 content(body, sourceFileLocator);
112 footer(body);
113 }
114
115 private void breadcrumb(final HTMLElement body,
116 final ReportOutputFolder base, final ReportPage current)
117 throws IOException {
118 if (parent != null) {
119 parent.breadcrumb(body, base, current);
120 body.text(" > ");
121 }
122 final String style = Resources.getElementStyle(node.getElementType());
123 if (this == current) {
124 body.span(style).text(getLabel());
125 } else {
126 body.a(getLink(base), style).text(getLabel());
127 }
128 }
129
130 /**
131 * Creates the actual content of the page.
132 *
133 * @param body
134 * body tag of the page
135 * @param sourceFileLocator
136 * locator for source file content in this context
137 * @throws IOException
138 * in case of IO problems with the report writer
139 */
140 protected abstract void content(final HTMLElement body,
141 final ISourceFileLocator sourceFileLocator) throws IOException;
142
143 /**
144 * Renders the page footer.
145 *
146 * @param body
147 * enclosing body element
148 * @throws IOException
149 * in case of IO problems with the report writer
150 */
151 protected void footer(final HTMLElement body) throws IOException {
152 final HTMLElement footer = body.div(Styles.FOOTER);
153 final HTMLElement versioninfo = footer.div(Styles.VERSIONINFO);
154 versioninfo.text("Created with ");
155 versioninfo.a(JaCoCo.HOMEURL).text("JaCoCo");
156 versioninfo.text(" ").text(JaCoCo.VERSION);
157 footer.text(context.getFooterText());
158 }
159
160 /**
161 * Specifies the local file name of this page.
162 *
163 * @return local file name
164 */
165 protected abstract String getFileName();
166
167 /**
168 * Creates the output folder relative to the given base for this report
169 * page. The method may decide to simply return the base folder itself.
170 *
171 * @param base
172 * base folder
173 * @return folder to create this page in
174 */
175 protected abstract ReportOutputFolder getFolder(ReportOutputFolder base);
176
177 // === ICoverageTableItem ===
178
179 public String getLabel() {
180 return node.getName();
181 }
182
183 public ICoverageNode getNode() {
184 return node;
185 }
186
187 public final String getLink(final ReportOutputFolder base) {
188 return outputFolder.getLink(base, getFileName());
189 }
190
191}