Trac #93: Add session information to HTML report.
diff --git a/org.jacoco.doc/buildhook.xml b/org.jacoco.doc/buildhook.xml
index bd86172..1f8ae1f 100644
--- a/org.jacoco.doc/buildhook.xml
+++ b/org.jacoco.doc/buildhook.xml
@@ -120,7 +120,7 @@
 			<link href="http://asm.ow2.org/asm31/javadoc/user" offline="true" packagelistloc="${source.bundle.dir}/javadoc/asm"/>

 			<bottom>

 				&lt;div class="footer"&gt;

-					&lt;div class="versioninfo"&gt;&lt;a href="${jacoco.home.url}"&gt;JaCoCo&lt;/a&gt; ${qualified.bundle.version}&lt;/div&gt;

+					&lt;span class="right"&gt;&lt;a href="${jacoco.home.url}"&gt;JaCoCo&lt;/a&gt; ${qualified.bundle.version}&lt;/span&gt;

 					Copyright &#169; ${copyright.years} Mountainminds GmbH &amp; Co. KG and Contributors

 				&lt;/div>

 			</bottom>

diff --git a/org.jacoco.doc/docroot/doc/.resources/doc.css b/org.jacoco.doc/docroot/doc/.resources/doc.css
index a24d982..99b76be 100644
--- a/org.jacoco.doc/docroot/doc/.resources/doc.css
+++ b/org.jacoco.doc/docroot/doc/.resources/doc.css
@@ -10,7 +10,7 @@
 

 .breadcrumb {

   border:#d6d3ce 1px solid;

-  padding:2px 2px 2px 2px;

+  padding:2px 4px 2px 4px;

 }

 

 .footer {

@@ -21,10 +21,8 @@
   color:#a0a0a0;

 }

 

-.footer div.versioninfo {

-  width:30%;

+.right {

   float:right;

-  text-align:right;

 }

 

 .footer a {

diff --git a/org.jacoco.doc/docroot/doc/agent.html b/org.jacoco.doc/docroot/doc/agent.html
index 2a604ce..6a81a17 100644
--- a/org.jacoco.doc/docroot/doc/agent.html
+++ b/org.jacoco.doc/docroot/doc/agent.html
@@ -118,7 +118,7 @@
 

 </div>

 <div class="footer">

-  <div class="versioninfo"><a href="@jacoco.home.url@">JaCoCo</a> @qualified.bundle.version@</div>

+  <span class="right"><a href="@jacoco.home.url@">JaCoCo</a> @qualified.bundle.version@</span>

   <a href="license.html">Copyright</a> &copy; @copyright.years@ Mountainminds GmbH &amp; Co. KG and Contributors

 </div>

 

diff --git a/org.jacoco.doc/docroot/doc/ant.html b/org.jacoco.doc/docroot/doc/ant.html
index 888099f..b0e5c58 100644
--- a/org.jacoco.doc/docroot/doc/ant.html
+++ b/org.jacoco.doc/docroot/doc/ant.html
@@ -488,7 +488,7 @@
 

 </div>

 <div class="footer">

-  <div class="versioninfo"><a href="@jacoco.home.url@">JaCoCo</a> @qualified.bundle.version@</div>

+  <span class="right"><a href="@jacoco.home.url@">JaCoCo</a> @qualified.bundle.version@</span>

   <a href="license.html">Copyright</a> &copy; @copyright.years@ Mountainminds GmbH &amp; Co. KG and Contributors

 </div>

 

diff --git a/org.jacoco.doc/docroot/doc/api.html b/org.jacoco.doc/docroot/doc/api.html
index 63ef3da..8693e85 100644
--- a/org.jacoco.doc/docroot/doc/api.html
+++ b/org.jacoco.doc/docroot/doc/api.html
@@ -55,10 +55,9 @@
 </table>

 

 

-

 </div>

 <div class="footer">

-  <div class="versioninfo"><a href="@jacoco.home.url@">JaCoCo</a> @qualified.bundle.version@</div>

+  <span class="right"><a href="@jacoco.home.url@">JaCoCo</a> @qualified.bundle.version@</span>

   <a href="license.html">Copyright</a> &copy; @copyright.years@ Mountainminds GmbH &amp; Co. KG and Contributors

 </div>

 

diff --git a/org.jacoco.doc/docroot/doc/build.html b/org.jacoco.doc/docroot/doc/build.html
index 2467ea5..498dbb1 100644
--- a/org.jacoco.doc/docroot/doc/build.html
+++ b/org.jacoco.doc/docroot/doc/build.html
@@ -264,7 +264,7 @@
 

 </div>

 <div class="footer">

-  <div class="versioninfo"><a href="@jacoco.home.url@">JaCoCo</a> @qualified.bundle.version@</div>

+  <span class="right"><a href="@jacoco.home.url@">JaCoCo</a> @qualified.bundle.version@</span>

   <a href="license.html">Copyright</a> &copy; @copyright.years@ Mountainminds GmbH &amp; Co. KG and Contributors

 </div>

 

diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html
index 1436986..df0e3ee 100644
--- a/org.jacoco.doc/docroot/doc/changes.html
+++ b/org.jacoco.doc/docroot/doc/changes.html
@@ -24,6 +24,7 @@
   <li>Execution data now includes session information: an arbitrary identifier,

       the start time and dump time (Trac #88).</li>

   <li>Added session information to XML report (Trac #92).</li>

+  <li>Added session information to HTML report (Trac #93).</li>

 </ul>

 

 <h3>API Changes</h3>

@@ -134,7 +135,7 @@
 

 </div>

 <div class="footer">

-  <div class="versioninfo"><a href="@jacoco.home.url@">JaCoCo</a> @qualified.bundle.version@</div>

+  <span class="right"><a href="@jacoco.home.url@">JaCoCo</a> @qualified.bundle.version@</span>

   <a href="license.html">Copyright</a> &copy; @copyright.years@ Mountainminds GmbH &amp; Co. KG and Contributors

 </div>

 

diff --git a/org.jacoco.doc/docroot/doc/conventions.html b/org.jacoco.doc/docroot/doc/conventions.html
index 4f983c8..d2dd190 100644
--- a/org.jacoco.doc/docroot/doc/conventions.html
+++ b/org.jacoco.doc/docroot/doc/conventions.html
@@ -130,7 +130,7 @@
 

 </div>

 <div class="footer">

-  <div class="versioninfo"><a href="@jacoco.home.url@">JaCoCo</a> @qualified.bundle.version@</div>

+  <span class="right"><a href="@jacoco.home.url@">JaCoCo</a> @qualified.bundle.version@</span>

   <a href="license.html">Copyright</a> &copy; @copyright.years@ Mountainminds GmbH &amp; Co. KG and Contributors

 </div>

 

diff --git a/org.jacoco.doc/docroot/doc/counters.html b/org.jacoco.doc/docroot/doc/counters.html
index 90aee40..016d461 100644
--- a/org.jacoco.doc/docroot/doc/counters.html
+++ b/org.jacoco.doc/docroot/doc/counters.html
@@ -123,7 +123,7 @@
 

 </div> 

 <div class="footer">

-  <div class="versioninfo"><a href="@jacoco.home.url@">JaCoCo</a> @qualified.bundle.version@</div>

+  <span class="right"><a href="@jacoco.home.url@">JaCoCo</a> @qualified.bundle.version@</span>

   <a href="license.html">Copyright</a> &copy; @copyright.years@ Mountainminds GmbH &amp; Co. KG and Contributors

 </div>

 

diff --git a/org.jacoco.doc/docroot/doc/empty.html b/org.jacoco.doc/docroot/doc/empty.html
index 14b5b4d..40a8795 100644
--- a/org.jacoco.doc/docroot/doc/empty.html
+++ b/org.jacoco.doc/docroot/doc/empty.html
@@ -22,7 +22,7 @@
 

 </div>

 <div class="footer">

-  <div class="versioninfo"><a href="@jacoco.home.url@">JaCoCo</a> @qualified.bundle.version@</div>

+  <span class="right"><a href="@jacoco.home.url@">JaCoCo</a> @qualified.bundle.version@</span>

   <a href="license.html">Copyright</a> &copy; @copyright.years@ Mountainminds GmbH &amp; Co. KG and Contributors

 </div>

 

diff --git a/org.jacoco.doc/docroot/doc/environment.html b/org.jacoco.doc/docroot/doc/environment.html
index cfc9ff3..47e07c5 100644
--- a/org.jacoco.doc/docroot/doc/environment.html
+++ b/org.jacoco.doc/docroot/doc/environment.html
@@ -91,7 +91,7 @@
 

 </div>

 <div class="footer">

-  <div class="versioninfo"><a href="@jacoco.home.url@">JaCoCo</a> @qualified.bundle.version@</div>

+  <span class="right"><a href="@jacoco.home.url@">JaCoCo</a> @qualified.bundle.version@</span>

   <a href="license.html">Copyright</a> &copy; @copyright.years@ Mountainminds GmbH &amp; Co. KG and Contributors

 </div>

 

diff --git a/org.jacoco.doc/docroot/doc/epl-v10.html b/org.jacoco.doc/docroot/doc/epl-v10.html
index c2ba263..7db918b 100644
--- a/org.jacoco.doc/docroot/doc/epl-v10.html
+++ b/org.jacoco.doc/docroot/doc/epl-v10.html
@@ -253,7 +253,7 @@
 
 </div>
 <div class="footer">
-  <div class="versioninfo"><a href="@jacoco.home.url@">JaCoCo</a> @qualified.bundle.version@</div>
+  <span class="right"><a href="@jacoco.home.url@">JaCoCo</a> @qualified.bundle.version@</span>
   <a href="license.html">Copyright</a> &copy; @copyright.years@ Mountainminds GmbH &amp; Co. KG and Contributors
 </div>
 
diff --git a/org.jacoco.doc/docroot/doc/implementation.html b/org.jacoco.doc/docroot/doc/implementation.html
index 345c4c0..6abe05a 100644
--- a/org.jacoco.doc/docroot/doc/implementation.html
+++ b/org.jacoco.doc/docroot/doc/implementation.html
@@ -334,7 +334,7 @@
 

 </div>

 <div class="footer">

-  <div class="versioninfo"><a href="@jacoco.home.url@">JaCoCo</a> @qualified.bundle.version@</div>

+  <span class="right"><a href="@jacoco.home.url@">JaCoCo</a> @qualified.bundle.version@</span>

   <a href="license.html">Copyright</a> &copy; @copyright.years@ Mountainminds GmbH &amp; Co. KG and Contributors

 </div>

 

diff --git a/org.jacoco.doc/docroot/doc/index.html b/org.jacoco.doc/docroot/doc/index.html
index fcca976..ad63e50 100644
--- a/org.jacoco.doc/docroot/doc/index.html
+++ b/org.jacoco.doc/docroot/doc/index.html
@@ -76,7 +76,7 @@
 

 </div>

 <div class="footer">

-  <div class="versioninfo"><a href="@jacoco.home.url@">JaCoCo</a> @qualified.bundle.version@</div>

+  <span class="right"><a href="@jacoco.home.url@">JaCoCo</a> @qualified.bundle.version@</span>

   <a href="license.html">Copyright</a> &copy; @copyright.years@ Mountainminds GmbH &amp; Co. KG and Contributors

 </div>

 

diff --git a/org.jacoco.doc/docroot/doc/license.html b/org.jacoco.doc/docroot/doc/license.html
index 7af2ae6..ecf5e94 100644
--- a/org.jacoco.doc/docroot/doc/license.html
+++ b/org.jacoco.doc/docroot/doc/license.html
@@ -502,7 +502,7 @@
 

 </div>

 <div class="footer">

-  <div class="versioninfo"><a href="@jacoco.home.url@">JaCoCo</a> @qualified.bundle.version@</div>

+  <span class="right"><a href="@jacoco.home.url@">JaCoCo</a> @qualified.bundle.version@</span>

   <a href="license.html">Copyright</a> &copy; @copyright.years@ Mountainminds GmbH &amp; Co. KG and Contributors

 </div>

 

diff --git a/org.jacoco.doc/docroot/doc/mission.html b/org.jacoco.doc/docroot/doc/mission.html
index 3f56653..de15dc9 100644
--- a/org.jacoco.doc/docroot/doc/mission.html
+++ b/org.jacoco.doc/docroot/doc/mission.html
@@ -82,7 +82,7 @@
 

 </div>

 <div class="footer">

-  <div class="versioninfo"><a href="@jacoco.home.url@">JaCoCo</a> @qualified.bundle.version@</div>

+  <span class="right"><a href="@jacoco.home.url@">JaCoCo</a> @qualified.bundle.version@</span>

   <a href="license.html">Copyright</a> &copy; @copyright.years@ Mountainminds GmbH &amp; Co. KG and Contributors

 </div>

 

diff --git a/org.jacoco.doc/docroot/doc/support.html b/org.jacoco.doc/docroot/doc/support.html
index b2ae864..633a80c 100644
--- a/org.jacoco.doc/docroot/doc/support.html
+++ b/org.jacoco.doc/docroot/doc/support.html
@@ -30,7 +30,7 @@
 

 </div>

 <div class="footer">

-  <div class="versioninfo"><a href="@jacoco.home.url@">JaCoCo</a> @qualified.bundle.version@</div>

+  <span class="right"><a href="@jacoco.home.url@">JaCoCo</a> @qualified.bundle.version@</span>

   <a href="license.html">Copyright</a> &copy; @copyright.years@ Mountainminds GmbH &amp; Co. KG and Contributors

 </div>

 

diff --git a/org.jacoco.doc/docroot/doc/team.html b/org.jacoco.doc/docroot/doc/team.html
index 6b5c2fb..12a07f6 100644
--- a/org.jacoco.doc/docroot/doc/team.html
+++ b/org.jacoco.doc/docroot/doc/team.html
@@ -36,7 +36,7 @@
 

 </div>

 <div class="footer">

-  <div class="versioninfo"><a href="@jacoco.home.url@">JaCoCo</a> @qualified.bundle.version@</div>

+  <span class="right"><a href="@jacoco.home.url@">JaCoCo</a> @qualified.bundle.version@</span>

   <a href="license.html">Copyright</a> &copy; @copyright.years@ Mountainminds GmbH &amp; Co. KG and Contributors

 </div>

 

diff --git a/org.jacoco.doc/docroot/index.html b/org.jacoco.doc/docroot/index.html
index 79f0351..9efb8ce 100644
--- a/org.jacoco.doc/docroot/index.html
+++ b/org.jacoco.doc/docroot/index.html
@@ -110,7 +110,7 @@
 

 </div>

 <div class="footer">

-  <div class="versioninfo"><a href="@jacoco.home.url@">JaCoCo</a> @qualified.bundle.version@</div>

+  <span class="right"><a href="@jacoco.home.url@">JaCoCo</a> @qualified.bundle.version@</span>

   <a href="doc/license.html">Copyright</a> &copy; @copyright.years@ Mountainminds GmbH &amp; Co. KG and Contributors

 </div>

 

diff --git a/org.jacoco.doc/javadoc/stylesheet.css b/org.jacoco.doc/javadoc/stylesheet.css
index ef85b26..896f4a9 100644
--- a/org.jacoco.doc/javadoc/stylesheet.css
+++ b/org.jacoco.doc/javadoc/stylesheet.css
@@ -60,7 +60,7 @@
 	color:#a0a0a0;

 }

 

-.footer div.versioninfo {

+.right {

 	width:30%;

 	float:right;

 	text-align:right;

diff --git a/org.jacoco.doc/junitstyle/junit-noframes.xsl b/org.jacoco.doc/junitstyle/junit-noframes.xsl
index bceefb8..307f6a7 100644
--- a/org.jacoco.doc/junitstyle/junit-noframes.xsl
+++ b/org.jacoco.doc/junitstyle/junit-noframes.xsl
@@ -68,7 +68,7 @@
             

             </div>

 			<div class="footer">

-				<div class="versioninfo"><a href="{$jacoco.home.url}">JaCoCo</a>&#160;<xsl:value-of select="$qualified.bundle.version"/></div>

+				<span class="right"><a href="{$jacoco.home.url}">JaCoCo</a>&#160;<xsl:value-of select="$qualified.bundle.version"/></span>

 				<a href="../doc/license.html">Copyright</a> &#169; <xsl:value-of select="$copyright.years"/> Mountainminds GmbH &amp; Co. KG and Contributors

 			</div>

         </body>

diff --git a/org.jacoco.report.test/src/org/jacoco/report/MemoryMultiReportOutput.java b/org.jacoco.report.test/src/org/jacoco/report/MemoryMultiReportOutput.java
index 3ed137f..fac56a6 100644
--- a/org.jacoco.report.test/src/org/jacoco/report/MemoryMultiReportOutput.java
+++ b/org.jacoco.report.test/src/org/jacoco/report/MemoryMultiReportOutput.java
@@ -52,7 +52,8 @@
 	}

 

 	public void assertFile(String path) {

-		assertNotNull("Missing " + path, files.get(path));

+		assertNotNull(String.format("Missing file %s. Actual files are %s.",

+				path, files.keySet()), files.get(path));

 	}

 

 	public void assertSingleFile(String path) {

diff --git a/org.jacoco.report.test/src/org/jacoco/report/html/HTMLElementTest.java b/org.jacoco.report.test/src/org/jacoco/report/html/HTMLElementTest.java
index 297acec..1f01a34 100644
--- a/org.jacoco.report.test/src/org/jacoco/report/html/HTMLElementTest.java
+++ b/org.jacoco.report.test/src/org/jacoco/report/html/HTMLElementTest.java
@@ -75,6 +75,13 @@
 	}

 

 	@Test

+	public void testP() throws IOException {

+		root.p();

+		root.close();

+		assertEquals("<root><p/></root>", buffer.toString());

+	}

+

+	@Test

 	public void testSpan1() throws IOException {

 		root.span("abc");

 		root.close();

diff --git a/org.jacoco.report.test/src/org/jacoco/report/html/NodePageTest.java b/org.jacoco.report.test/src/org/jacoco/report/html/NodePageTest.java
new file mode 100644
index 0000000..c14522a
--- /dev/null
+++ b/org.jacoco.report.test/src/org/jacoco/report/html/NodePageTest.java
@@ -0,0 +1,131 @@
+/*******************************************************************************

+ * Copyright (c) 2009, 2010 Mountainminds GmbH & Co. KG and Contributors

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * which accompanies this distribution, and is available at

+ * http://www.eclipse.org/legal/epl-v10.html

+ *

+ * Contributors:

+ *    Marc R. Hoffmann - initial API and implementation

+ *    

+ * $Id: $

+ *******************************************************************************/

+package org.jacoco.report.html;

+

+import static org.junit.Assert.assertSame;

+

+import java.io.IOException;

+

+import org.jacoco.core.analysis.CoverageNodeImpl;

+import org.jacoco.core.analysis.ICoverageNode;

+import org.jacoco.core.analysis.ICoverageNode.ElementType;

+import org.jacoco.report.ILanguageNames;

+import org.jacoco.report.IReportVisitor;

+import org.jacoco.report.MemoryMultiReportOutput;

+import org.jacoco.report.ReportOutputFolder;

+import org.jacoco.report.html.resources.Resources;

+import org.junit.After;

+import org.junit.Before;

+import org.junit.Test;

+

+/**

+ * Unit tests for {@link ReportPage}.

+ * 

+ * @author Marc R. Hoffmann

+ * @version $Revision: $

+ */

+public class NodePageTest {

+

+	private MemoryMultiReportOutput output;

+

+	private ReportOutputFolder root;

+

+	private IHTMLReportContext context;

+

+	private CoverageNodeImpl node;

+

+	private NodePage page;

+

+	private class TestNodePage extends NodePage {

+

+		protected TestNodePage(ICoverageNode node) {

+			super(node, null, root, NodePageTest.this.context);

+		}

+

+		@Override

+		protected void content(HTMLElement body) throws IOException {

+		}

+

+		@Override

+		protected String getFileName() {

+			return "index.html";

+		}

+

+		public IReportVisitor visitChild(ICoverageNode node) {

+			throw new UnsupportedOperationException();

+		}

+

+	}

+

+	@Before

+	public void setup() {

+		output = new MemoryMultiReportOutput();

+		root = new ReportOutputFolder(output);

+		final Resources resources = new Resources(root);

+		context = new IHTMLReportContext() {

+

+			public ILanguageNames getLanguageNames() {

+				throw new AssertionError("Unexpected method call.");

+			}

+

+			public Resources getResources() {

+				return resources;

+			}

+

+			public CoverageTable getTable(ElementType type) {

+				throw new AssertionError("Unexpected method call.");

+			}

+

+			public String getFooterText() {

+				return "CustomFooter";

+			}

+

+			public String getInfoPageLink(ReportOutputFolder base) {

+				return "info.html";

+			}

+

+			public String getOutputEncoding() {

+				return "UTF-8";

+			}

+		};

+		node = new CoverageNodeImpl(ElementType.GROUP, "Test", false);

+		page = new TestNodePage(node);

+	}

+

+	@After

+	public void teardown() {

+		output.assertAllClosed();

+	}

+

+	@Test

+	public void testGetNode() throws IOException {

+		assertSame(node, page.getNode());

+	}

+

+	@Test

+	public void testGetLabel() throws IOException {

+		assertSame("Test", page.getLabel());

+	}

+

+	@Test

+	public void testGetElementStyle() throws IOException {

+		assertSame("el_group", page.getElementStyle());

+	}

+

+	@Test

+	public void testVisitEnd() throws IOException {

+		page.visitEnd(null);

+		output.assertSingleFile("index.html");

+	}

+

+}

diff --git a/org.jacoco.report.test/src/org/jacoco/report/html/ReportPageTest.java b/org.jacoco.report.test/src/org/jacoco/report/html/ReportPageTest.java
index 03dde47..e1b96cb 100644
--- a/org.jacoco.report.test/src/org/jacoco/report/html/ReportPageTest.java
+++ b/org.jacoco.report.test/src/org/jacoco/report/html/ReportPageTest.java
@@ -16,12 +16,8 @@
 

 import java.io.IOException;

 

-import org.jacoco.core.analysis.CoverageNodeImpl;

-import org.jacoco.core.analysis.ICoverageNode;

 import org.jacoco.core.analysis.ICoverageNode.ElementType;

 import org.jacoco.report.ILanguageNames;

-import org.jacoco.report.IReportVisitor;

-import org.jacoco.report.ISourceFileLocator;

 import org.jacoco.report.MemoryMultiReportOutput;

 import org.jacoco.report.ReportOutputFolder;

 import org.jacoco.report.html.resources.Resources;

@@ -44,34 +40,37 @@
 

 	private IHTMLReportContext context;

 

-	private CoverageNodeImpl node;

-

 	private ReportPage page;

 

 	private class TestReportPage extends ReportPage {

 

-		protected TestReportPage(ICoverageNode node, ReportPage parent) {

-			super(node, parent, root, ReportPageTest.this.context);

+		private final String label;

+		private final String style;

+

+		protected TestReportPage(String label, String style, ReportPage parent) {

+			super(parent, root, ReportPageTest.this.context);

+			this.label = label;

+			this.style = style;

 		}

 

 		@Override

-		protected void content(HTMLElement body,

-				ISourceFileLocator sourceFileLocator) throws IOException {

+		protected void content(HTMLElement body) throws IOException {

 			body.div("testcontent").text("Hello Test");

 		}

 

 		@Override

 		protected String getFileName() {

-			return getNode().getName() + ".html";

-		}

-

-		public IReportVisitor visitChild(ICoverageNode node) {

-			throw new UnsupportedOperationException();

+			return label + ".html";

 		}

 

 		@Override

-		protected ReportOutputFolder getFolder(ReportOutputFolder base) {

-			return base;

+		protected String getLabel() {

+			return label;

+		}

+

+		@Override

+		protected String getElementStyle() {

+			return style;

 		}

 

 	}

@@ -99,14 +98,16 @@
 				return "CustomFooter";

 			}

 

+			public String getInfoPageLink(ReportOutputFolder base) {

+				return "info.html";

+			}

+

 			public String getOutputEncoding() {

 				return "UTF-8";

 			}

 		};

-		ReportPage parent = new TestReportPage(new CoverageNodeImpl(

-				ElementType.SESSION, "Session", false), null);

-		node = new CoverageNodeImpl(ElementType.GROUP, "Test", false);

-		page = new TestReportPage(node, parent);

+		ReportPage parent = new TestReportPage("Session", "el_session", null);

+		page = new TestReportPage("Test", "el_group", parent);

 	}

 

 	@After

@@ -115,21 +116,14 @@
 	}

 

 	@Test

-	public void testGetNode() throws IOException {

-		page.visitEnd(null);

-		assertEquals(node.getElementType(), page.getNode().getElementType());

-		assertEquals(node.getName(), page.getNode().getName());

-	}

-

-	@Test

-	public void testLink() throws IOException {

+	public void testGetLink() throws IOException {

 		ReportOutputFolder base = root.subFolder("here");

 		assertEquals("../Test.html", page.getLink(base));

 	}

 

 	@Test

 	public void testPageContent() throws Exception {

-		page.visitEnd(null);

+		page.renderDocument();

 		final HTMLSupport support = new HTMLSupport();

 		final Document doc = support.parse(output.getFile("Test.html"));

 

@@ -145,9 +139,9 @@
 		assertEquals("el_session", support.findStr(doc,

 				"/html/body/div[@class='breadcrumb']/a[1]/@class"));

 		assertEquals("Test", support.findStr(doc,

-				"/html/body/div[@class='breadcrumb']/span[1]/text()"));

+				"/html/body/div[@class='breadcrumb']/span[2]/text()"));

 		assertEquals("el_group", support.findStr(doc,

-				"/html/body/div[@class='breadcrumb']/span[1]/@class"));

+				"/html/body/div[@class='breadcrumb']/span[2]/@class"));

 

 		// Header

 		assertEquals("Test", support.findStr(doc, "/html/body/h1/text()"));

diff --git a/org.jacoco.report.test/src/org/jacoco/report/html/resources/ResourcesTest.java b/org.jacoco.report.test/src/org/jacoco/report/html/resources/ResourcesTest.java
index f248324..fcd31b3 100644
--- a/org.jacoco.report.test/src/org/jacoco/report/html/resources/ResourcesTest.java
+++ b/org.jacoco.report.test/src/org/jacoco/report/html/resources/ResourcesTest.java
@@ -55,6 +55,8 @@
 	public void testCopyResources() throws IOException {

 		resources.copyResources();

 		output.assertFile(".resources/report.css");

+		output.assertFile(".resources/prettify.css");

+		output.assertFile(".resources/prettify.js");

 		output.assertFile(".resources/session.gif");

 		output.assertFile(".resources/group.gif");

 		output.assertFile(".resources/bundle.gif");

@@ -62,6 +64,7 @@
 		output.assertFile(".resources/source.gif");

 		output.assertFile(".resources/class.gif");

 		output.assertFile(".resources/method.gif");

+		output.assertFile(".resources/sessions.gif");

 		output.assertFile(".resources/greenbar.gif");

 		output.assertFile(".resources/redbar.gif");

 	}

diff --git a/org.jacoco.report/src/org/jacoco/report/html/ClassPage.java b/org.jacoco.report/src/org/jacoco/report/html/ClassPage.java
index 2268fcb..0241e23 100644
--- a/org.jacoco.report/src/org/jacoco/report/html/ClassPage.java
+++ b/org.jacoco.report/src/org/jacoco/report/html/ClassPage.java
@@ -21,7 +21,6 @@
 import org.jacoco.core.analysis.ICoverageNode;

 import org.jacoco.core.analysis.MethodCoverage;

 import org.jacoco.report.IReportVisitor;

-import org.jacoco.report.ISourceFileLocator;

 import org.jacoco.report.ReportOutputFolder;

 

 /**

@@ -31,7 +30,7 @@
  * @author Marc R. Hoffmann

  * @version $Revision: $

  */

-public class ClassPage extends ReportPage {

+public class ClassPage extends NodePage {

 

 	private class MethodItem implements ICoverageTableItem {

 

@@ -78,14 +77,14 @@
 	 * @param classNode

 	 * @param parent

 	 * @param sourceFiles

-	 * @param outputFolder

+	 * @param folder

 	 * @param context

 	 */

 	public ClassPage(final ClassCoverage classNode, final ReportPage parent,

 			final Map<String, SourceFilePage> sourceFiles,

-			final ReportOutputFolder outputFolder,

+			final ReportOutputFolder folder,

 			final IHTMLReportContext context) {

-		super(classNode, parent, outputFolder, context);

+		super(classNode, parent, folder, context);

 		this.sourceFiles = sourceFiles;

 		this.label = context.getLanguageNames().getClassName(

 				classNode.getName(), classNode.getSignature(),

@@ -99,10 +98,9 @@
 	}

 

 	@Override

-	protected void content(final HTMLElement body,

-			final ISourceFileLocator sourceFileLocator) throws IOException {

+	protected void content(final HTMLElement body) throws IOException {

 		context.getTable(getNode().getElementType()).render(body, methods,

-				getNode(), context.getResources(), outputFolder);

+				getNode(), context.getResources(), folder);

 	}

 

 	@Override

@@ -118,9 +116,4 @@
 		return label;

 	}

 

-	@Override

-	protected ReportOutputFolder getFolder(final ReportOutputFolder base) {

-		return base;

-	}

-

 }

diff --git a/org.jacoco.report/src/org/jacoco/report/html/GroupPage.java b/org.jacoco.report/src/org/jacoco/report/html/GroupPage.java
index b6d71db..22b6f4c 100644
--- a/org.jacoco.report/src/org/jacoco/report/html/GroupPage.java
+++ b/org.jacoco.report/src/org/jacoco/report/html/GroupPage.java
@@ -28,32 +28,33 @@
  * @author Marc R. Hoffmann

  * @version $Revision: $

  */

-public class GroupPage extends ReportPage {

+public class GroupPage extends NodePage {

 

-	private final List<ReportPage> children = new ArrayList<ReportPage>();

+	private final List<NodePage> children = new ArrayList<NodePage>();

 

 	/**

 	 * Creates a new visitor in the given context.

 	 * 

 	 * @param node

 	 * @param parent

-	 * @param outputFolder

+	 * @param folder

 	 * @param context

 	 */

 	public GroupPage(final ICoverageNode node, final ReportPage parent,

-			final ReportOutputFolder outputFolder,

-			final IHTMLReportContext context) {

-		super(node, parent, outputFolder, context);

+			final ReportOutputFolder folder, final IHTMLReportContext context) {

+		super(node, parent, folder, context);

 	}

 

 	public IReportVisitor visitChild(final ICoverageNode node) {

-		ReportPage child;

+		final NodePage child;

 		switch (node.getElementType()) {

 		case PACKAGE:

-			child = new PackagePage(node, this, outputFolder, context);

+			child = new PackagePage(node, this, folder.subFolder(node.getName()

+					.replace('/', '.')), context);

 			break;

 		default:

-			child = new GroupPage(node, this, outputFolder, context);

+			child = new GroupPage(node, this, folder.subFolder(node.getName()),

+					context);

 			break;

 		}

 		children.add(child);

@@ -69,10 +70,9 @@
 	}

 

 	@Override

-	protected void content(final HTMLElement body,

-			final ISourceFileLocator sourceFileLocator) throws IOException {

+	protected void content(final HTMLElement body) throws IOException {

 		context.getTable(getNode().getElementType()).render(body, children,

-				getNode(), context.getResources(), outputFolder);

+				getNode(), context.getResources(), folder);

 	}

 

 	@Override

@@ -80,9 +80,4 @@
 		return "index.html";

 	}

 

-	@Override

-	protected ReportOutputFolder getFolder(final ReportOutputFolder base) {

-		return base.subFolder(getLabel());

-	}

-

 }

diff --git a/org.jacoco.report/src/org/jacoco/report/html/HTMLElement.java b/org.jacoco.report/src/org/jacoco/report/html/HTMLElement.java
index d0f247b..6fea42c 100644
--- a/org.jacoco.report/src/org/jacoco/report/html/HTMLElement.java
+++ b/org.jacoco.report/src/org/jacoco/report/html/HTMLElement.java
@@ -109,6 +109,17 @@
 	}

 

 	/**

+	 * Creates a 'p' element.

+	 * 

+	 * @return 'p' element

+	 * @throws IOException

+	 *             in case of problems with the writer

+	 */

+	public HTMLElement p() throws IOException {

+		return element("p");

+	}

+

+	/**

 	 * Creates a 'span' element.

 	 * 

 	 * @param classattr

diff --git a/org.jacoco.report/src/org/jacoco/report/html/HTMLFormatter.java b/org.jacoco.report/src/org/jacoco/report/html/HTMLFormatter.java
index 0a57951..127be50 100644
--- a/org.jacoco.report/src/org/jacoco/report/html/HTMLFormatter.java
+++ b/org.jacoco.report/src/org/jacoco/report/html/HTMLFormatter.java
@@ -48,6 +48,8 @@
 

 	private Resources resources;

 

+	private SessionsPage infoPage;

+

 	/**

 	 * The default sorting which is absolute not covered instructions and

 	 * absolute total instructions as the second criterion.

@@ -144,6 +146,10 @@
 		return footerText;

 	}

 

+	public String getInfoPageLink(final ReportOutputFolder base) {

+		return infoPage.getLink(base);

+	}

+

 	public String getOutputEncoding() {

 		return outputEncoding;

 	}

@@ -158,14 +164,10 @@
 		final ReportOutputFolder root = new ReportOutputFolder(output);

 		resources = new Resources(root);

 		resources.copyResources();

-		return new GroupPage(session, null, root, this) {

-

-			@Override

-			protected ReportOutputFolder getFolder(final ReportOutputFolder base) {

-				return base;

-			}

-

-		};

+		final GroupPage rootpage = new GroupPage(session, null, root, this);

+		infoPage = new SessionsPage(sessionInfos, rootpage, root, this);

+		infoPage.renderDocument();

+		return rootpage;

 	}

 

 }

diff --git a/org.jacoco.report/src/org/jacoco/report/html/IHTMLReportContext.java b/org.jacoco.report/src/org/jacoco/report/html/IHTMLReportContext.java
index edb2cf5..1522c14 100644
--- a/org.jacoco.report/src/org/jacoco/report/html/IHTMLReportContext.java
+++ b/org.jacoco.report/src/org/jacoco/report/html/IHTMLReportContext.java
@@ -14,6 +14,7 @@
 

 import org.jacoco.core.analysis.ICoverageNode.ElementType;

 import org.jacoco.report.ILanguageNames;

+import org.jacoco.report.ReportOutputFolder;

 import org.jacoco.report.html.resources.Resources;

 

 /**

@@ -55,6 +56,15 @@
 	public String getFooterText();

 

 	/**

+	 * Returns a relative link to the info page seen from the given folder.

+	 * 

+	 * @param base

+	 *            folder where the info page is linked from

+	 * @return relative link to the info page

+	 */

+	public String getInfoPageLink(final ReportOutputFolder base);

+

+	/**

 	 * Returns the encoding of the generated HTML documents.

 	 * 

 	 * @return encoding for generated HTML documents

diff --git a/org.jacoco.report/src/org/jacoco/report/html/NodePage.java b/org.jacoco.report/src/org/jacoco/report/html/NodePage.java
new file mode 100644
index 0000000..8c4b33c
--- /dev/null
+++ b/org.jacoco.report/src/org/jacoco/report/html/NodePage.java
@@ -0,0 +1,74 @@
+/*******************************************************************************

+ * Copyright (c) 2009, 2010 Mountainminds GmbH & Co. KG and Contributors

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * which accompanies this distribution, and is available at

+ * http://www.eclipse.org/legal/epl-v10.html

+ *

+ * Contributors:

+ *    Marc R. Hoffmann - initial API and implementation

+ *    

+ * $Id: $

+ *******************************************************************************/

+package org.jacoco.report.html;

+

+import java.io.IOException;

+

+import org.jacoco.core.analysis.ICoverageNode;

+import org.jacoco.report.IReportVisitor;

+import org.jacoco.report.ISourceFileLocator;

+import org.jacoco.report.ReportOutputFolder;

+import org.jacoco.report.html.resources.Resources;

+

+/**

+ * Report page that represents a coverage node.

+ * 

+ * @author Marc R. Hoffmann

+ * @version $Revision: $

+ */

+public abstract class NodePage extends ReportPage implements IReportVisitor,

+		ICoverageTableItem {

+

+	private ICoverageNode node;

+

+	/**

+	 * Creates a new node page.

+	 * 

+	 * @param node

+	 *            corresponding node

+	 * @param parent

+	 *            optional hierarchical parent

+	 * @param folder

+	 *            base folder to create this report in

+	 * @param context

+	 *            settings context

+	 */

+	protected NodePage(final ICoverageNode node, final ReportPage parent,

+			final ReportOutputFolder folder, final IHTMLReportContext context) {

+		super(parent, folder, context);

+		this.node = node;

+	}

+

+	@Override

+	protected String getElementStyle() {

+		return Resources.getElementStyle(node.getElementType());

+	}

+

+	public void visitEnd(final ISourceFileLocator sourceFileLocator)

+			throws IOException {

+		renderDocument();

+		this.node = node.getPlainCopy();

+	}

+

+	// === ICoverageTableItem ===

+

+	@Override

+	public String getLabel() {

+		return node.getName();

+	}

+

+	public ICoverageNode getNode() {

+		return node;

+	}

+

+}

diff --git a/org.jacoco.report/src/org/jacoco/report/html/PackagePage.java b/org.jacoco.report/src/org/jacoco/report/html/PackagePage.java
index f2f54d5..6a75aa1 100644
--- a/org.jacoco.report/src/org/jacoco/report/html/PackagePage.java
+++ b/org.jacoco.report/src/org/jacoco/report/html/PackagePage.java
@@ -33,7 +33,7 @@
  * @author Marc R. Hoffmann

  * @version $Revision: $

  */

-public class PackagePage extends ReportPage {

+public class PackagePage extends NodePage {

 

 	private final List<ClassPage> classes = new ArrayList<ClassPage>();

 

@@ -44,13 +44,12 @@
 	 * 

 	 * @param node

 	 * @param parent

-	 * @param outputFolder

+	 * @param folder

 	 * @param context

 	 */

 	public PackagePage(final ICoverageNode node, final ReportPage parent,

-			final ReportOutputFolder outputFolder,

-			final IHTMLReportContext context) {

-		super(node, parent, outputFolder, context);

+			final ReportOutputFolder folder, final IHTMLReportContext context) {

+		super(node, parent, folder, context);

 	}

 

 	public IReportVisitor visitChild(final ICoverageNode node) {

@@ -58,12 +57,12 @@
 		switch (type) {

 		case SOURCEFILE:

 			final SourceFilePage sourcePage = new SourceFilePage(

-					(SourceFileCoverage) node, this, outputFolder, context);

+					(SourceFileCoverage) node, this, folder, context);

 			sourceFiles.put(node.getName(), sourcePage);

 			return sourcePage;

 		case CLASS:

 			final ClassPage classPage = new ClassPage((ClassCoverage) node,

-					this, sourceFiles, outputFolder, context);

+					this, sourceFiles, folder, context);

 			classes.add(classPage);

 			return classPage;

 		}

@@ -80,10 +79,9 @@
 	}

 

 	@Override

-	protected void content(final HTMLElement body,

-			final ISourceFileLocator sourceFileLocator) throws IOException {

+	protected void content(final HTMLElement body) throws IOException {

 		context.getTable(getNode().getElementType()).render(body, classes,

-				getNode(), context.getResources(), outputFolder);

+				getNode(), context.getResources(), folder);

 	}

 

 	@Override

@@ -96,9 +94,4 @@
 		return context.getLanguageNames().getPackageName(getNode().getName());

 	}

 

-	@Override

-	protected ReportOutputFolder getFolder(final ReportOutputFolder base) {

-		return base.subFolder(getLabel());

-	}

-

 }

diff --git a/org.jacoco.report/src/org/jacoco/report/html/ReportPage.java b/org.jacoco.report/src/org/jacoco/report/html/ReportPage.java
index 35bac4b..ed29c02 100644
--- a/org.jacoco.report/src/org/jacoco/report/html/ReportPage.java
+++ b/org.jacoco.report/src/org/jacoco/report/html/ReportPage.java
@@ -15,65 +15,67 @@
 import java.io.IOException;

 

 import org.jacoco.core.JaCoCo;

-import org.jacoco.core.analysis.ICoverageNode;

-import org.jacoco.report.IReportVisitor;

-import org.jacoco.report.ISourceFileLocator;

 import org.jacoco.report.ReportOutputFolder;

 import org.jacoco.report.html.resources.Resources;

 import org.jacoco.report.html.resources.Styles;

 

 /**

  * Base class for HTML page generators. It renders the page skeleton with the

- * breadcrumb, the title and the footer.

+ * breadcrumb, the title and the footer. Every report page is part of a

+ * hierarchy and has a parent page (except the root page).

  * 

  * @author Marc R. Hoffmann

  * @version $Revision: $

  */

-public abstract class ReportPage implements IReportVisitor, ICoverageTableItem {

+public abstract class ReportPage {

 

 	private final ReportPage parent;

 

 	/** output folder for this node */

-	protected final ReportOutputFolder outputFolder;

+	protected final ReportOutputFolder folder;

 

 	/** context for this report */

 	protected final IHTMLReportContext context;

 

-	private ICoverageNode node;

-

 	/**

 	 * Creates a new report page.

 	 * 

-	 * @param node

-	 *            corresponding node

 	 * @param parent

 	 *            optional hierarchical parent

-	 * @param baseFolder

-	 *            base folder to create this report page relative to

+	 * @param folder

+	 *            base folder to create this report in

 	 * @param context

 	 *            settings context

 	 */

-	protected ReportPage(final ICoverageNode node, final ReportPage parent,

-			final ReportOutputFolder baseFolder,

-			final IHTMLReportContext context) {

-		this.node = node;

+	protected ReportPage(final ReportPage parent,

+			final ReportOutputFolder folder, final IHTMLReportContext context) {

 		this.parent = parent;

 		this.context = context;

-		this.outputFolder = getFolder(baseFolder);

+		this.folder = folder;

 	}

 

-	public void visitEnd(final ISourceFileLocator sourceFileLocator)

-			throws IOException {

-		renderDocument(sourceFileLocator);

-		this.node = node.getPlainCopy();

+	/**

+	 * Returns a relative link to this page that works from the given base

+	 * folder.

+	 * 

+	 * @param base

+	 *            folder where the link should be inserted

+	 * @return relative link

+	 */

+	public final String getLink(final ReportOutputFolder base) {

+		return folder.getLink(base, getFileName());

 	}

 

-	private void renderDocument(final ISourceFileLocator sourceFileLocator)

-			throws IOException {

-		final HTMLDocument doc = new HTMLDocument(outputFolder

+	/**

+	 * Renders the page content. This method must be called at most once.

+	 * 

+	 * @throws IOException

+	 */

+	public final void renderDocument() throws IOException {

+		final HTMLDocument doc = new HTMLDocument(folder

 				.createFile(getFileName()), context.getOutputEncoding());

 		head(doc.head());

-		body(doc.body(), sourceFileLocator);

+		body(doc.body());

 		doc.close();

 	}

 

@@ -87,9 +89,9 @@
 	 */

 	protected void head(final HTMLElement head) throws IOException {

 		head.meta("Content-Type", "text/html;charset=UTF-8");

-		head.link("stylesheet", context.getResources().getLink(outputFolder,

+		head.link("stylesheet", context.getResources().getLink(folder,

 				Resources.STYLESHEET), "text/css");

-		head.link("shortcut icon", context.getResources().getLink(outputFolder,

+		head.link("shortcut icon", context.getResources().getLink(folder,

 				"session.gif"), "image/gif");

 		head.title().text(getLabel());

 	}

@@ -99,58 +101,43 @@
 	 * 

 	 * @param body

 	 *            enclosing body element

-	 * @param sourceFileLocator

-	 *            locator for source file content in this context

 	 * @throws IOException

 	 *             in case of IO problems with the report writer

 	 */

-	protected void body(final HTMLElement body,

-			final ISourceFileLocator sourceFileLocator) throws IOException {

-		breadcrumb(body.div(Styles.BREADCRUMB), outputFolder, this);

+	protected void body(final HTMLElement body) throws IOException {

+		final HTMLElement navigation = body.div(Styles.BREADCRUMB);

+		infoLinks(navigation.span(Styles.RIGHT));

+		breadcrumb(navigation, folder);

 		body.h1().text(getLabel());

-		content(body, sourceFileLocator);

+		content(body);

 		footer(body);

 	}

 

-	private void breadcrumb(final HTMLElement body,

-			final ReportOutputFolder base, final ReportPage current)

+	private void infoLinks(final HTMLElement span) throws IOException {

+		span.a(context.getInfoPageLink(folder), Styles.EL_SESSIONS).text(

+				"Sessions");

+	}

+

+	private void breadcrumb(final HTMLElement div, final ReportOutputFolder base)

 			throws IOException {

-		if (parent != null) {

-			parent.breadcrumb(body, base, current);

-			body.text(" > ");

-		}

-		final String style = Resources.getElementStyle(node.getElementType());

-		if (this == current) {

-			body.span(style).text(getLabel());

-		} else {

-			body.a(getLink(base), style).text(getLabel());

+		breadcrumbParent(parent, div, base);

+		div.span(getElementStyle()).text(getLabel());

+	}

+

+	private static void breadcrumbParent(final ReportPage page,

+			final HTMLElement div, final ReportOutputFolder base)

+			throws IOException {

+		if (page != null) {

+			breadcrumbParent(page.parent, div, base);

+			final String style = page.getElementStyle();

+			div.a(page.getLink(base), style).text(page.getLabel());

+			div.text(" > ");

 		}

 	}

 

-	/**

-	 * Creates the actual content of the page.

-	 * 

-	 * @param body

-	 *            body tag of the page

-	 * @param sourceFileLocator

-	 *            locator for source file content in this context

-	 * @throws IOException

-	 *             in case of IO problems with the report writer

-	 */

-	protected abstract void content(final HTMLElement body,

-			final ISourceFileLocator sourceFileLocator) throws IOException;

-

-	/**

-	 * Renders the page footer.

-	 * 

-	 * @param body

-	 *            enclosing body element

-	 * @throws IOException

-	 *             in case of IO problems with the report writer

-	 */

-	protected void footer(final HTMLElement body) throws IOException {

+	private void footer(final HTMLElement body) throws IOException {

 		final HTMLElement footer = body.div(Styles.FOOTER);

-		final HTMLElement versioninfo = footer.div(Styles.VERSIONINFO);

+		final HTMLElement versioninfo = footer.span(Styles.RIGHT);

 		versioninfo.text("Created with ");

 		versioninfo.a(JaCoCo.HOMEURL).text("JaCoCo");

 		versioninfo.text(" ").text(JaCoCo.VERSION);

@@ -165,27 +152,28 @@
 	protected abstract String getFileName();

 

 	/**

-	 * Creates the output folder relative to the given base for this report

-	 * page. The method may decide to simply return the base folder itself.

+	 * Returns the display label used for the element represented on this page.

 	 * 

-	 * @param base

-	 *            base folder

-	 * @return folder to create this page in

+	 * @return display label

 	 */

-	protected abstract ReportOutputFolder getFolder(ReportOutputFolder base);

+	protected abstract String getLabel();

 

-	// === ICoverageTableItem ===

+	/**

+	 * The CSS style class that might be associated with this element when it is

+	 * displayed in the header or in tables.

+	 * 

+	 * @return CSS style class for this element

+	 */

+	protected abstract String getElementStyle();

 

-	public String getLabel() {

-		return node.getName();

-	}

-

-	public ICoverageNode getNode() {

-		return node;

-	}

-

-	public final String getLink(final ReportOutputFolder base) {

-		return outputFolder.getLink(base, getFileName());

-	}

+	/**

+	 * Creates the actual content of the page.

+	 * 

+	 * @param body

+	 *            body tag of the page

+	 * @throws IOException

+	 *             in case of IO problems with the report writer

+	 */

+	protected abstract void content(final HTMLElement body) throws IOException;

 

 }

diff --git a/org.jacoco.report/src/org/jacoco/report/html/SessionsPage.java b/org.jacoco.report/src/org/jacoco/report/html/SessionsPage.java
new file mode 100644
index 0000000..4925a60
--- /dev/null
+++ b/org.jacoco.report/src/org/jacoco/report/html/SessionsPage.java
@@ -0,0 +1,93 @@
+/*******************************************************************************

+ * Copyright (c) 2009, 2010 Mountainminds GmbH & Co. KG and Contributors

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * which accompanies this distribution, and is available at

+ * http://www.eclipse.org/legal/epl-v10.html

+ *

+ * Contributors:

+ *    Marc R. Hoffmann - initial API and implementation

+ *    

+ * $Id: $

+ *******************************************************************************/

+package org.jacoco.report.html;

+

+import java.io.IOException;

+import java.text.DateFormat;

+import java.util.Date;

+import java.util.List;

+

+import org.jacoco.core.data.SessionInfo;

+import org.jacoco.report.ReportOutputFolder;

+import org.jacoco.report.html.resources.Styles;

+

+/**

+ * Page to display information about sessions covered by this report.

+ * 

+ * @author Marc R. Hoffmann

+ * @version $Revision: $

+ */

+public class SessionsPage extends ReportPage {

+

+	private static final String MSG_SESSIONS = "This coverage report is based "

+			+ "on execution data from the following sessions:";

+

+	private final List<SessionInfo> sessionInfos;

+

+	private final DateFormat dateFormat = DateFormat.getDateTimeInstance();

+

+	/**

+	 * Creates a new page page to display session information.

+	 * 

+	 * @param sessionInfos

+	 * @param parent

+	 * @param folder

+	 * @param context

+	 */

+	public SessionsPage(final List<SessionInfo> sessionInfos,

+			final ReportPage parent, final ReportOutputFolder folder,

+			final IHTMLReportContext context) {

+		super(parent, folder, context);

+		this.sessionInfos = sessionInfos;

+	}

+

+	@Override

+	protected void content(final HTMLElement body) throws IOException {

+		body.p().text(MSG_SESSIONS);

+		final HTMLElement table = body.table(Styles.COVERAGETABLE);

+		tableheader(table.thead());

+		tablebody(table.tbody());

+	}

+

+	private void tableheader(final HTMLElement thead) throws IOException {

+		final HTMLElement tr = thead.tr();

+		tr.td().text("Session");

+		tr.td().text("Start Time");

+		tr.td().text("Dump Time");

+	}

+

+	private void tablebody(final HTMLElement tbody) throws IOException {

+		for (final SessionInfo i : sessionInfos) {

+			final HTMLElement tr = tbody.tr();

+			tr.td().text(i.getId());

+			tr.td().text(dateFormat.format(new Date(i.getStartTimeStamp())));

+			tr.td().text(dateFormat.format(new Date(i.getDumpTimeStamp())));

+		}

+	}

+

+	@Override

+	protected String getElementStyle() {

+		return Styles.EL_SESSIONS;

+	}

+

+	@Override

+	protected String getFileName() {

+		return ".sessions.html";

+	}

+

+	@Override

+	protected String getLabel() {

+		return "Sessions";

+	}

+

+}

diff --git a/org.jacoco.report/src/org/jacoco/report/html/SourceFilePage.java b/org.jacoco.report/src/org/jacoco/report/html/SourceFilePage.java
index a761b55..f00260a 100644
--- a/org.jacoco.report/src/org/jacoco/report/html/SourceFilePage.java
+++ b/org.jacoco.report/src/org/jacoco/report/html/SourceFilePage.java
@@ -30,7 +30,7 @@
  * @author Marc R. Hoffmann

  * @version $Revision: $

  */

-public class SourceFilePage extends ReportPage {

+public class SourceFilePage extends NodePage {

 

 	private Reader sourceReader;

 

@@ -43,13 +43,13 @@
 	 * 

 	 * @param sourceFileNode

 	 * @param parent

-	 * @param outputFolder

+	 * @param folder

 	 * @param context

 	 */

 	public SourceFilePage(final SourceFileCoverage sourceFileNode,

-			final ReportPage parent, final ReportOutputFolder outputFolder,

+			final ReportPage parent, final ReportOutputFolder folder,

 			final IHTMLReportContext context) {

-		super(sourceFileNode, parent, outputFolder, context);

+		super(sourceFileNode, parent, folder, context);

 		packageName = sourceFileNode.getPackageName();

 		lines = sourceFileNode.getLines();

 	}

@@ -69,8 +69,7 @@
 	}

 

 	@Override

-	protected void content(final HTMLElement body,

-			final ISourceFileLocator sourceFileLocator) throws IOException {

+	protected void content(final HTMLElement body) throws IOException {

 		new SourceHighlighter().render(body, lines, sourceReader);

 		sourceReader.close();

 	}

@@ -78,17 +77,16 @@
 	@Override

 	protected void head(final HTMLElement head) throws IOException {

 		super.head(head);

-		head.link("stylesheet", context.getResources().getLink(outputFolder,

+		head.link("stylesheet", context.getResources().getLink(folder,

 				Resources.PRETTIFY_STYLESHEET), "text/css");

 		head.script("text/javascript", context.getResources().getLink(

-				outputFolder, Resources.PRETTIFY_SCRIPT));

+				folder, Resources.PRETTIFY_SCRIPT));

 	}

 

 	@Override

-	protected void body(final HTMLElement body,

-			final ISourceFileLocator sourceFileLocator) throws IOException {

+	protected void body(final HTMLElement body) throws IOException {

 		body.attr("onload", "prettyPrint()");

-		super.body(body, sourceFileLocator);

+		super.body(body);

 	}

 

 	@Override

@@ -96,11 +94,6 @@
 		return getNode().getName() + ".html";

 	}

 

-	@Override

-	protected ReportOutputFolder getFolder(final ReportOutputFolder base) {

-		return base;

-	}

-

 	/**

 	 * Checks whether this page has actually been rendered. This might not be

 	 * the case if no source file has been found.

diff --git a/org.jacoco.report/src/org/jacoco/report/html/resources/Resources.java b/org.jacoco.report/src/org/jacoco/report/html/resources/Resources.java
index b7c2e4f..a3f04b8 100644
--- a/org.jacoco.report/src/org/jacoco/report/html/resources/Resources.java
+++ b/org.jacoco.report/src/org/jacoco/report/html/resources/Resources.java
@@ -110,6 +110,7 @@
 		copyResource("source.gif");

 		copyResource("class.gif");

 		copyResource("method.gif");

+		copyResource("sessions.gif");

 		copyResource(REDBAR);

 		copyResource(GREENBAR);

 		copyResource(PRETTIFY_STYLESHEET);

diff --git a/org.jacoco.report/src/org/jacoco/report/html/resources/Styles.java b/org.jacoco.report/src/org/jacoco/report/html/resources/Styles.java
index c91399b..ca4a042 100644
--- a/org.jacoco.report/src/org/jacoco/report/html/resources/Styles.java
+++ b/org.jacoco.report/src/org/jacoco/report/html/resources/Styles.java
@@ -26,8 +26,11 @@
 	/** Footer */

 	public static final String FOOTER = "footer";

 

-	/** Version Info in Footer */

-	public static final String VERSIONINFO = "versioninfo";

+	/** Test block aligned to the right */

+	public static final String RIGHT = "right";

+

+	/** Info element */

+	public static final String EL_SESSIONS = "el_sessions";

 

 	/** Coverage table */

 	public static final String COVERAGETABLE = "coverage";

diff --git a/org.jacoco.report/src/org/jacoco/report/html/resources/class.gif b/org.jacoco.report/src/org/jacoco/report/html/resources/class.gif
index e4c2a83..eb348fb 100644
--- a/org.jacoco.report/src/org/jacoco/report/html/resources/class.gif
+++ b/org.jacoco.report/src/org/jacoco/report/html/resources/class.gif
Binary files differ
diff --git a/org.jacoco.report/src/org/jacoco/report/html/resources/report.css b/org.jacoco.report/src/org/jacoco/report/html/resources/report.css
index 7a495e6..33fbbcb 100644
--- a/org.jacoco.report/src/org/jacoco/report/html/resources/report.css
+++ b/org.jacoco.report/src/org/jacoco/report/html/resources/report.css
@@ -10,7 +10,7 @@
 

 .breadcrumb {

   border:#d6d3ce 1px solid;

-  padding:2px 2px 2px 2px;

+  padding:2px 4px 2px 4px;

 }

 

 

@@ -63,6 +63,12 @@
   background-repeat:no-repeat;

 }

 

+.el_sessions {

+  padding-left:18px;

+  background-image:url(sessions.gif);

+  background-position:left center;

+  background-repeat:no-repeat;

+}

 

 pre.source {

   border:#d6d3ce 1px solid;

@@ -163,13 +169,11 @@
   color:#a0a0a0;

 }

 

-.footer div.versioninfo {

-  width:40%;

-  float:right;

-  text-align:right;

-}

-

 .footer a {

   color:#a0a0a0;

 }

 

+.right {

+  float:right;

+}

+

diff --git a/org.jacoco.report/src/org/jacoco/report/html/resources/sessions.gif b/org.jacoco.report/src/org/jacoco/report/html/resources/sessions.gif
new file mode 100644
index 0000000..0151bad
--- /dev/null
+++ b/org.jacoco.report/src/org/jacoco/report/html/resources/sessions.gif
Binary files differ