1 /******************************************************************************* 2 * Copyright (c) 2009, 2018 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 *******************************************************************************/ 12 package org.jacoco.report.internal.html.page; 13 14 import java.io.IOException; 15 16 import org.jacoco.core.JaCoCo; 17 import org.jacoco.report.internal.ReportOutputFolder; 18 import org.jacoco.report.internal.html.HTMLDocument; 19 import org.jacoco.report.internal.html.HTMLElement; 20 import org.jacoco.report.internal.html.IHTMLReportContext; 21 import org.jacoco.report.internal.html.ILinkable; 22 import org.jacoco.report.internal.html.resources.Resources; 23 import org.jacoco.report.internal.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. Every report page is part of a 28 * hierarchy and has a parent page (except the root page). 29 */ 30 public abstract class ReportPage implements ILinkable { 31 32 private final ReportPage parent; 33 34 /** output folder for this node */ 35 protected final ReportOutputFolder folder; 36 37 /** context for this report */ 38 protected final IHTMLReportContext context; 39 40 /** 41 * Creates a new report page. 42 * 43 * @param parent 44 * optional hierarchical parent 45 * @param folder 46 * base folder to create this report in 47 * @param context 48 * settings context 49 */ ReportPage(final ReportPage parent, final ReportOutputFolder folder, final IHTMLReportContext context)50 protected ReportPage(final ReportPage parent, 51 final ReportOutputFolder folder, final IHTMLReportContext context) { 52 this.parent = parent; 53 this.context = context; 54 this.folder = folder; 55 } 56 57 /** 58 * Checks whether this is the root page of the report. 59 * 60 * @return <code>true</code> if this is the root page 61 */ isRootPage()62 protected final boolean isRootPage() { 63 return parent == null; 64 } 65 66 /** 67 * Renders this page's content and optionally additional pages. This method 68 * must be called at most once. 69 * 70 * @throws IOException 71 * if the page can't be written 72 */ render()73 public void render() throws IOException { 74 final HTMLDocument doc = new HTMLDocument( 75 folder.createFile(getFileName()), context.getOutputEncoding()); 76 doc.attr("lang", context.getLocale().getLanguage()); 77 head(doc.head()); 78 body(doc.body()); 79 doc.close(); 80 } 81 82 /** 83 * Creates the elements within the head element. 84 * 85 * @param head 86 * head tag of the page 87 * @throws IOException 88 * in case of IO problems with the report writer 89 */ head(final HTMLElement head)90 protected void head(final HTMLElement head) throws IOException { 91 head.meta("Content-Type", "text/html;charset=UTF-8"); 92 head.link("stylesheet", 93 context.getResources().getLink(folder, Resources.STYLESHEET), 94 "text/css"); 95 head.link("shortcut icon", 96 context.getResources().getLink(folder, "report.gif"), 97 "image/gif"); 98 head.title().text(getLinkLabel()); 99 } 100 body(final HTMLElement body)101 private void body(final HTMLElement body) throws IOException { 102 body.attr("onload", getOnload()); 103 final HTMLElement navigation = body.div(Styles.BREADCRUMB); 104 navigation.attr("id", "breadcrumb"); 105 infoLinks(navigation.span(Styles.INFO)); 106 breadcrumb(navigation, folder); 107 body.h1().text(getLinkLabel()); 108 content(body); 109 footer(body); 110 } 111 112 /** 113 * Returns the onload handler for this page. 114 * 115 * @return handler or <code>null</code> 116 */ getOnload()117 protected String getOnload() { 118 return null; 119 } 120 121 /** 122 * Inserts additional links on the top right corner. 123 * 124 * @param span 125 * parent element 126 * @throws IOException 127 * in case of IO problems with the report writer 128 */ infoLinks(final HTMLElement span)129 protected void infoLinks(final HTMLElement span) throws IOException { 130 span.a(context.getSessionsPage(), folder); 131 } 132 breadcrumb(final HTMLElement div, final ReportOutputFolder base)133 private void breadcrumb(final HTMLElement div, final ReportOutputFolder base) 134 throws IOException { 135 breadcrumbParent(parent, div, base); 136 div.span(getLinkStyle()).text(getLinkLabel()); 137 } 138 breadcrumbParent(final ReportPage page, final HTMLElement div, final ReportOutputFolder base)139 private static void breadcrumbParent(final ReportPage page, 140 final HTMLElement div, final ReportOutputFolder base) 141 throws IOException { 142 if (page != null) { 143 breadcrumbParent(page.parent, div, base); 144 div.a(page, base); 145 div.text(" > "); 146 } 147 } 148 footer(final HTMLElement body)149 private void footer(final HTMLElement body) throws IOException { 150 final HTMLElement footer = body.div(Styles.FOOTER); 151 final HTMLElement versioninfo = footer.span(Styles.RIGHT); 152 versioninfo.text("Created with "); 153 versioninfo.a(JaCoCo.HOMEURL).text("JaCoCo"); 154 versioninfo.text(" ").text(JaCoCo.VERSION); 155 footer.text(context.getFooterText()); 156 } 157 158 /** 159 * Specifies the local file name of this page. 160 * 161 * @return local file name 162 */ getFileName()163 protected abstract String getFileName(); 164 165 /** 166 * Creates the actual content of the page. 167 * 168 * @param body 169 * body tag of the page 170 * @throws IOException 171 * in case of IO problems with the report writer 172 */ content(final HTMLElement body)173 protected abstract void content(final HTMLElement body) throws IOException; 174 175 // === ILinkable === 176 getLink(final ReportOutputFolder base)177 public final String getLink(final ReportOutputFolder base) { 178 return folder.getLink(base, getFileName()); 179 } 180 181 } 182