1b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler/* 2b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler * Copyright (C) 2015 The Android Open Source Project 3b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler * 4b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler * Licensed under the Apache License, Version 2.0 (the "License"); 5b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler * you may not use this file except in compliance with the License. 6b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler * You may obtain a copy of the License at 7b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler * 8b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler * http://www.apache.org/licenses/LICENSE-2.0 9b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler * 10b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler * Unless required by applicable law or agreed to in writing, software 11b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler * distributed under the License is distributed on an "AS IS" BASIS, 12b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler * See the License for the specific language governing permissions and 14b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler * limitations under the License. 15b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler */ 16b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler 17b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhlerpackage com.android.ahat; 18b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler 19b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhlerimport java.io.PrintStream; 20b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhlerimport java.net.URI; 21b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhlerimport java.util.List; 22b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler 23b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler/** 24b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler * An Html implementation of Doc. 25b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler */ 26b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhlerpublic class HtmlDoc implements Doc { 27b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler private PrintStream ps; 28b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler private Column[] mCurrentTableColumns; 29b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler 30b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler /** 31b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler * Create an HtmlDoc that writes to the given print stream. 32b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler * @param title - The main page title. 33b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler * @param style - A URI link to a stylesheet to link to. 34b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler */ 35b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler public HtmlDoc(PrintStream ps, DocString title, URI style) { 36b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler this.ps = ps; 37b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler 38b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler ps.println("<!DOCTYPE html>"); 39b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler ps.println("<html>"); 40b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler ps.println("<head>"); 41b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler ps.format("<title>%s</title>\n", title.html()); 42b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler ps.format("<link rel=\"stylesheet\" type=\"text/css\" href=\"%s\">\n", 43b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler style.toASCIIString()); 44b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler ps.println("</head>"); 45b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler ps.println("<body>"); 46b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler } 47b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler 48b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler @Override 49b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler public void title(String format, Object... args) { 50b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler ps.print("<h1>"); 51b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler ps.print(DocString.text(String.format(format, args)).html()); 52b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler ps.println("</h1>"); 53b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler } 54b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler 55b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler @Override 56b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler public void menu(DocString string) { 57b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler ps.format("<div class=\"menu\">%s</div>", string.html()); 58b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler } 59b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler 60b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler @Override 61b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler public void section(String title) { 62b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler ps.print("<h2>"); 63b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler ps.print(DocString.text(title).html()); 64b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler ps.println(":</h2>"); 65b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler } 66b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler 67b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler @Override 68b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler public void println(DocString string) { 69b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler ps.print(string.html()); 70b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler ps.println("<br />"); 71b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler } 72b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler 73b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler @Override 74b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler public void big(DocString str) { 75b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler ps.print("<h2>"); 76b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler ps.print(str.html()); 77b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler ps.println("</h2>"); 78b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler } 79b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler 80b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler @Override 81b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler public void table(Column... columns) { 82b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler if (columns.length == 0) { 83b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler throw new IllegalArgumentException("No columns specified"); 84b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler } 85b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler 86b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler mCurrentTableColumns = columns; 87b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler ps.println("<table>"); 88b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler for (int i = 0; i < columns.length - 1; i++) { 89b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler ps.format("<th>%s</th>", columns[i].heading.html()); 90b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler } 91b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler 92b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler // Align the last header to the left so it's easier to see if the last 93b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler // column is very wide. 94b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler ps.format("<th align=\"left\">%s</th>", columns[columns.length - 1].heading.html()); 95b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler } 96b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler 97b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler @Override 98b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler public void table(DocString description, List<Column> subcols, List<Column> cols) { 99b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler mCurrentTableColumns = new Column[subcols.size() + cols.size()]; 100b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler int j = 0; 101b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler for (Column col : subcols) { 102b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler mCurrentTableColumns[j] = col; 103b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler j++; 104b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler } 105b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler for (Column col : cols) { 106b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler mCurrentTableColumns[j] = col; 107b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler j++; 108b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler } 109b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler 110b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler ps.println("<table>"); 111b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler ps.format("<tr><th colspan=\"%d\">%s</th>", subcols.size(), description.html()); 112b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler for (int i = 0; i < cols.size() - 1; i++) { 113b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler ps.format("<th rowspan=\"2\">%s</th>", cols.get(i).heading.html()); 114b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler } 115b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler if (!cols.isEmpty()) { 116b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler // Align the last column header to the left so it can still be seen if 117b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler // the last column is very wide. 118b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler ps.format("<th align=\"left\" rowspan=\"2\">%s</th>", 119b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler cols.get(cols.size() - 1).heading.html()); 120b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler } 121b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler ps.println("</tr>"); 122b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler 123b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler ps.print("<tr>"); 124b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler for (Column subcol : subcols) { 125b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler ps.format("<th>%s</th>", subcol.heading.html()); 126b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler } 127b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler ps.println("</tr>"); 128b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler } 129b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler 130b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler @Override 131b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler public void row(DocString... values) { 132b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler if (mCurrentTableColumns == null) { 133b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler throw new IllegalStateException("table method must be called before row"); 134b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler } 135b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler 136b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler if (mCurrentTableColumns.length != values.length) { 137b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler throw new IllegalArgumentException(String.format( 138b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler "Wrong number of row values. Expected %d, but got %d", 139b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler mCurrentTableColumns.length, values.length)); 140b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler } 141b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler 142b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler ps.print("<tr>"); 143b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler for (int i = 0; i < values.length; i++) { 144b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler ps.print("<td"); 145b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler if (mCurrentTableColumns[i].align == Column.Align.RIGHT) { 146b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler ps.print(" align=\"right\""); 147b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler } 148b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler ps.format(">%s</td>", values[i].html()); 149b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler } 150b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler ps.println("</tr>"); 151b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler } 152b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler 153b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler @Override 154b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler public void descriptions() { 155b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler ps.println("<table>"); 156b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler } 157b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler 158b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler @Override 159b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler public void description(DocString key, DocString value) { 160b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler ps.format("<tr><th align=\"left\">%s:</th><td>%s</td></tr>", key.html(), value.html()); 161b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler } 162b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler 163b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler @Override 164b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler public void end() { 165b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler ps.println("</table>"); 166b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler mCurrentTableColumns = null; 167b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler } 168b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler 169b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler @Override 170b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler public void close() { 171b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler ps.println("</body>"); 172b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler ps.println("</html>"); 173b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler ps.close(); 174b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler } 175b730b78dac047c6d8ead93ad77605bcb7414f5ceRichard Uhler} 176