Trac #152: expose tab width of html report in ant task
diff --git a/org.jacoco.ant.test/src/org/jacoco/ant/ReportTaskTest.xml b/org.jacoco.ant.test/src/org/jacoco/ant/ReportTaskTest.xml
index d1f66c9..20a5d33 100644
--- a/org.jacoco.ant.test/src/org/jacoco/ant/ReportTaskTest.xml
+++ b/org.jacoco.ant.test/src/org/jacoco/ant/ReportTaskTest.xml
@@ -170,7 +170,61 @@
 			<contains string="${testReportHtmlEncoding.content}" substring="encoding=&quot;UTF-16&quot;"/>

 		</au:assertTrue>

 	</target>

+

+	<target name="testReportHtmlDefaultTabWidth">

+		<jacoco:report>

+			<structure name="Test">

+				<classfiles>

+					<fileset dir="${org.jacoco.ant.reportTaskTest.classes.dir}" includes="**/*.class"/>

+				</classfiles>

+				<sourcefiles>

+					<fileset dir="${org.jacoco.ant.reportTaskTest.sources.dir}" includes="**/*.java" />

+				</sourcefiles>

+            </structure>

+			<html destdir="${temp.dir}"/>

+		</jacoco:report>

+		

+		<loadfile property="testReportHtmlTabWidth.content" srcfile="${temp.dir}/org.jacoco.ant/TestTarget.java.html"/>

+		<au:assertTrue message="Tab width not set in ${testReportHtmlTabWidth.content}">

+			<contains string="${testReportHtmlTabWidth.content}" substring="window['PR_TAB_WIDTH']=4"/>

+		</au:assertTrue>

+	</target>

 	

+	<target name="testReportHtmlTabWidth">

+		<jacoco:report>

+			<structure name="Test">

+				<classfiles>

+					<fileset dir="${org.jacoco.ant.reportTaskTest.classes.dir}" includes="**/*.class"/>

+				</classfiles>

+				<sourcefiles tabwidth="13">

+					<fileset dir="${org.jacoco.ant.reportTaskTest.sources.dir}" includes="**/*.java" />

+				</sourcefiles>

+            </structure>

+			<html destdir="${temp.dir}"/>

+		</jacoco:report>

+		

+		<loadfile property="testReportHtmlTabWidth.content" srcfile="${temp.dir}/org.jacoco.ant/TestTarget.java.html"/>

+		<au:assertTrue message="Tab width not set in ${testReportHtmlTabWidth.content}">

+			<contains string="${testReportHtmlTabWidth.content}" substring="window['PR_TAB_WIDTH']=13"/>

+		</au:assertTrue>

+	</target>

+	

+	<target name="testReportHtmlInvalidTabWidth">

+		<au:expectfailure expectedMessage="Tab width must be greater than 0">

+			<jacoco:report>

+				<structure name="Test">

+					<classfiles>

+						<fileset dir="${org.jacoco.ant.reportTaskTest.classes.dir}" includes="**/*.class"/>

+					</classfiles>

+					<sourcefiles tabwidth="0">

+						<fileset dir="${org.jacoco.ant.reportTaskTest.sources.dir}" includes="**/*.java" />

+					</sourcefiles>

+				</structure>

+				<html destdir="${temp.dir}"/>

+			</jacoco:report>

+		</au:expectfailure>

+	</target>

+			

 	<target name="testReportHtmlZipFile">

 		<jacoco:report>

 			<structure name="Test">

diff --git a/org.jacoco.ant/src/org/jacoco/ant/ReportTask.java b/org.jacoco.ant/src/org/jacoco/ant/ReportTask.java
index 1012582..221b0ab 100644
--- a/org.jacoco.ant/src/org/jacoco/ant/ReportTask.java
+++ b/org.jacoco.ant/src/org/jacoco/ant/ReportTask.java
@@ -64,7 +64,9 @@
 	 */

 	public static class SourceFilesElement extends Union {

 

-		String encoding;

+		String encoding = null;

+

+		int tabWidth = 4;

 

 		/**

 		 * Defines the optional source file encoding. If not set the platform

@@ -77,6 +79,19 @@
 			this.encoding = encoding;

 		}

 

+		/**

+		 * Sets the tab stop width for the source pages. Default value is 4.

+		 * 

+		 * @param tabWidth

+		 *            number of characters per tab stop

+		 */

+		public void setTabwidth(final int tabWidth) {

+			if (tabWidth <= 0) {

+				throw new BuildException("Tab width must be greater than 0");

+			}

+			this.tabWidth = tabWidth;

+		}

+

 	}

 

 	/**

@@ -475,8 +490,11 @@
 

 		private final Map<String, Resource> resources = new HashMap<String, Resource>();

 

+		private final int tabWidth;

+

 		SourceFileCollection(final SourceFilesElement sourceFiles) {

 			encoding = sourceFiles.encoding;

+			tabWidth = sourceFiles.tabWidth;

 			for (final Iterator<?> i = sourceFiles.iterator(); i.hasNext();) {

 				final Resource r = (Resource) i.next();

 				resources.put(r.getName().replace(File.separatorChar, '/'), r);

@@ -501,6 +519,10 @@
 			}

 		}

 

+		public int getTabWidth() {

+			return tabWidth;

+		}

+

 		public boolean isEmpty() {

 			return resources.isEmpty();

 		}

diff --git a/org.jacoco.doc/docroot/doc/ant.html b/org.jacoco.doc/docroot/doc/ant.html
index f028b5f..068477f 100644
--- a/org.jacoco.doc/docroot/doc/ant.html
+++ b/org.jacoco.doc/docroot/doc/ant.html
@@ -462,14 +462,37 @@
     ear etc.) or folders containing class files. Archives and folders are

     searched recursively for class files.</li>

   <li><code>sourcefiles</code>: Optional container element for Ant resources and

-    resource collections that specify corresponding source files. The element

-    has an optional attribute <code>encoding</code> to specify the character

-    encoding of the source files. If no encoding is given, the platform default

-    is used. If source files are specified, some report formats include

-    highlighted source code.</li>

+    resource collections that specify corresponding source files. If source

+    files are specified, some report formats include highlighted source code.</li>

 </ul>

 

 <p>

+  The <code>sourcefiles</code> element has these optional attributes:

+</p>

+

+<table class="coverage">

+  <thead>

+    <tr>

+      <td>Attribute</td>

+      <td>Description</td>

+      <td>Default</td>

+    </tr>

+  </thead>

+  <tbody>

+    <tr>

+      <td><code>encoding</code></td>

+      <td>Character encoding of the source files.</td>

+      <td>Platform default encoding</td>

+    </tr>

+    <tr>

+      <td><code>tabwidth</code></td>

+      <td>Number of whitespace characters that represent a tab character.</td>

+      <td>4 characters</td>

+    </tr>

+  </tbody>

+</table>

+

+<p>

   Note that the <code>classfiles</code> and <code>sourcefiles</code> elements

   accept any

   <a href="http://ant.apache.org/manual/Types/resources.html#collection">Ant

diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html
index 13088c0..aa8f835 100644
--- a/org.jacoco.doc/docroot/doc/changes.html
+++ b/org.jacoco.doc/docroot/doc/changes.html
@@ -18,6 +18,21 @@
 

 <h1>Change History</h1>

 

+<h2>Trunk Build @qualified.bundle.version@ (@build.date@)</h2>

+

+<h3>New Features</h3>

+<ul>

+  <li>For HTML reports the tab width can be specified on the

+      <code>sourcefiles</code> attribute of the <code>report</code> Ant task

+     (Track #152).</li>

+</ul>

+

+<h3>API Changes</h3>

+<ul>

+  <li>New method <code>getTabWidth()</code> in callback interface 

+      <code>ISourceFileLocator.getTabWidth()</code> (Trac #152).</li>

+</ul>

+

 <h2>Release 0.5.1 (2011/03/21)</h2>

 

 <h3>New Features</h3>

diff --git a/org.jacoco.examples/src/org/jacoco/examples/ReportGenerator.java b/org.jacoco.examples/src/org/jacoco/examples/ReportGenerator.java
index 43c11d0..d4f2531 100644
--- a/org.jacoco.examples/src/org/jacoco/examples/ReportGenerator.java
+++ b/org.jacoco.examples/src/org/jacoco/examples/ReportGenerator.java
@@ -97,7 +97,7 @@
 		// Populate the report structure with the bundle coverage information.

 		// Call visitGroup if you need groups in your report.

 		visitor.visitBundle(bundleCoverage, new DirectorySourceFileLocator(

-				sourceDirectory, "utf-8"));

+				sourceDirectory, "utf-8", 4));

 

 		// Signal end of structure information to allow report to write all

 		// information out

diff --git a/org.jacoco.report.test/src/org/jacoco/report/DirectorySourceFileLocatorTest.java b/org.jacoco.report.test/src/org/jacoco/report/DirectorySourceFileLocatorTest.java
index 235eb87..c9c6495 100644
--- a/org.jacoco.report.test/src/org/jacoco/report/DirectorySourceFileLocatorTest.java
+++ b/org.jacoco.report.test/src/org/jacoco/report/DirectorySourceFileLocatorTest.java
@@ -11,6 +11,7 @@
  *******************************************************************************/
 package org.jacoco.report;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.fail;
 
@@ -31,7 +32,12 @@
 
 	@Before
 	public void setup() {
-		locator = new DirectorySourceFileLocator(new File("./src"), "UTF-8");
+		locator = new DirectorySourceFileLocator(new File("./src"), "UTF-8", 4);
+	}
+
+	@Test
+	public void testGetTabWidth() throws IOException {
+		assertEquals(4, locator.getTabWidth());
 	}
 
 	@Test
diff --git a/org.jacoco.report.test/src/org/jacoco/report/ReportStructureTestDriver.java b/org.jacoco.report.test/src/org/jacoco/report/ReportStructureTestDriver.java
index ba7dc32..7369eec 100644
--- a/org.jacoco.report.test/src/org/jacoco/report/ReportStructureTestDriver.java
+++ b/org.jacoco.report.test/src/org/jacoco/report/ReportStructureTestDriver.java
@@ -47,6 +47,10 @@
 				throws IOException {
 			return null;
 		}
+
+		public int getTabWidth() {
+			return 4;
+		}
 	};
 
 	private final IMethodCoverage methodCoverage;
diff --git a/org.jacoco.report.test/src/org/jacoco/report/internal/html/page/SourceFilePageTest.java b/org.jacoco.report.test/src/org/jacoco/report/internal/html/page/SourceFilePageTest.java
index a0dac84..70674c2 100644
--- a/org.jacoco.report.test/src/org/jacoco/report/internal/html/page/SourceFilePageTest.java
+++ b/org.jacoco.report.test/src/org/jacoco/report/internal/html/page/SourceFilePageTest.java
@@ -44,7 +44,7 @@
 	public void testContents() throws Exception {
 		final SourceFileCoverageImpl node = new SourceFileCoverageImpl(
 				"SourceFilePageTest.java", "org/jacoco/report/internal/html");
-		final SourceFilePage page = new SourceFilePage(node, sourceReader,
+		final SourceFilePage page = new SourceFilePage(node, sourceReader, 4,
 				null, rootFolder, context);
 		page.render();
 
diff --git a/org.jacoco.report/src/org/jacoco/report/DirectorySourceFileLocator.java b/org.jacoco.report/src/org/jacoco/report/DirectorySourceFileLocator.java
index 0427759..b1b8117 100644
--- a/org.jacoco.report/src/org/jacoco/report/DirectorySourceFileLocator.java
+++ b/org.jacoco.report/src/org/jacoco/report/DirectorySourceFileLocator.java
@@ -27,6 +27,8 @@
 

 	private final String encoding;

 

+	private final int tabWidth;

+

 	/**

 	 * Creates a new locator that searches for source files in the given

 	 * directory.

@@ -35,11 +37,15 @@
 	 *            directory to search for source file

 	 * @param encoding

 	 *            encoding of the source files

+	 * @param tabWidth

+	 *            tab width in source files as number of blanks

+	 * 

 	 */

 	public DirectorySourceFileLocator(final File directory,

-			final String encoding) {

+			final String encoding, final int tabWidth) {

 		this.directory = directory;

 		this.encoding = encoding;

+		this.tabWidth = tabWidth;

 	}

 

 	public Reader getSourceFile(final String packageName, final String fileName)

@@ -52,4 +58,8 @@
 		return null;

 	}

 

+	public int getTabWidth() {

+		return tabWidth;

+	}

+

 }

diff --git a/org.jacoco.report/src/org/jacoco/report/ISourceFileLocator.java b/org.jacoco.report/src/org/jacoco/report/ISourceFileLocator.java
index 7fb81e8..28d087b 100644
--- a/org.jacoco.report/src/org/jacoco/report/ISourceFileLocator.java
+++ b/org.jacoco.report/src/org/jacoco/report/ISourceFileLocator.java
@@ -34,4 +34,11 @@
 	public Reader getSourceFile(String packageName, String fileName)

 			throws IOException;

 

+	/**

+	 * Returns number of blank characters that represent a tab in source code.

+	 * 

+	 * @return tab width as number of blanks

+	 */

+	public int getTabWidth();

+

 }

diff --git a/org.jacoco.report/src/org/jacoco/report/internal/html/IHTMLReportContext.java b/org.jacoco.report/src/org/jacoco/report/internal/html/IHTMLReportContext.java
index a1a5691..4437997 100644
--- a/org.jacoco.report/src/org/jacoco/report/internal/html/IHTMLReportContext.java
+++ b/org.jacoco.report/src/org/jacoco/report/internal/html/IHTMLReportContext.java
@@ -79,11 +79,4 @@
 	 */

 	public Locale getLocale();

 

-	/**

-	 * Returns number of blank characters that represent a tab in source code.

-	 * 

-	 * @return tab width as number of blanks

-	 */

-	public int getTabWidth();

-

 }
\ No newline at end of file
diff --git a/org.jacoco.report/src/org/jacoco/report/internal/html/page/PackagePage.java b/org.jacoco.report/src/org/jacoco/report/internal/html/page/PackagePage.java
index 18e11cf..15716d6 100644
--- a/org.jacoco.report/src/org/jacoco/report/internal/html/page/PackagePage.java
+++ b/org.jacoco.report/src/org/jacoco/report/internal/html/page/PackagePage.java
@@ -64,7 +64,7 @@
 					.getSourceFile(packagename, sourcename);

 			if (reader != null) {

 				final SourceFilePage sourcePage = new SourceFilePage(s, reader,

-						this, folder, context);

+						locator.getTabWidth(), this, folder, context);

 				sourcePage.render();

 				sourceFiles.put(sourcename, sourcePage);

 			}

diff --git a/org.jacoco.report/src/org/jacoco/report/internal/html/page/SourceFilePage.java b/org.jacoco.report/src/org/jacoco/report/internal/html/page/SourceFilePage.java
index d70fd91..5fd86da 100644
--- a/org.jacoco.report/src/org/jacoco/report/internal/html/page/SourceFilePage.java
+++ b/org.jacoco.report/src/org/jacoco/report/internal/html/page/SourceFilePage.java
@@ -30,20 +30,25 @@
 

 	private final Reader sourceReader;

 

+	private final int tabWidth;

+

 	/**

 	 * Creates a new page with given information.

 	 * 

 	 * @param sourceFileNode

 	 * @param sourceReader

+	 * @param tabWidth

 	 * @param parent

 	 * @param folder

 	 * @param context

 	 */

 	public SourceFilePage(final ISourceFileCoverage sourceFileNode,

-			final Reader sourceReader, final ReportPage parent,

-			final ReportOutputFolder folder, final IHTMLReportContext context) {

+			final Reader sourceReader, final int tabWidth,

+			final ReportPage parent, final ReportOutputFolder folder,

+			final IHTMLReportContext context) {

 		super(sourceFileNode, parent, folder, context);

 		this.sourceReader = sourceReader;

+		this.tabWidth = tabWidth;

 	}

 

 	@Override

@@ -69,7 +74,7 @@
 	@Override

 	protected String getOnload() {

 		return format("window['PR_TAB_WIDTH']=%d;prettyPrint()",

-				Integer.valueOf(context.getTabWidth()));

+				Integer.valueOf(tabWidth));

 	}

 

 	@Override