Table.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 *******************************************************************************/
12package org.jacoco.report.html.table;
13
14import java.io.IOException;
15import java.util.ArrayList;
16import java.util.Collections;
17import java.util.Comparator;
18import java.util.List;
19
20import org.jacoco.core.analysis.ICoverageNode;
21import org.jacoco.report.ReportOutputFolder;
22import org.jacoco.report.html.HTMLElement;
23import org.jacoco.report.html.resources.Resources;
24import org.jacoco.report.html.resources.Styles;
25
26/**
27 * Renderer for a table of {@link ITableItem}s.
28 *
29 * @author Marc R. Hoffmann
30 * @version 0.4.1.20101007204400
31 */
32public class Table {
33
34 private final List<Column> columns;
35
36 private Comparator<ITableItem> defaultComparator;
37
38 /**
39 * Create a new table without any columns yet.
40 */
41 public Table() {
42 this.columns = new ArrayList<Table.Column>();
43 }
44
45 /**
46 * Adds a new column with the given properties to the table.
47 *
48 * @param header
49 * column header caption
50 * @param style
51 * optional CSS style class name for the td-Elements of this
52 * column
53 * @param renderer
54 * callback for column rendering
55 * @param defaultSorting
56 * If <code>true</code>, this column is the default sorting
57 * column. Only one column can be selected for default sorting.
58 *
59 */
60 public void add(final String header, final String style,
61 final IColumnRenderer renderer, final boolean defaultSorting) {
62 columns.add(new Column(columns.size(), header, style, renderer,
63 defaultSorting));
64 if (defaultSorting) {
65 if (defaultComparator != null) {
66 throw new IllegalStateException(
67 "Default sorting only allowed for one column.");
68 }
69 this.defaultComparator = renderer.getComparator();
70 }
71 }
72
73 /**
74 * Renders a table for the given icon
75 *
76 * @param parent
77 * parent element in which the table is created
78 * @param items
79 * items that will make the table rows
80 * @param total
81 * the summary of all coverage data items in the table static
82 * resources that might be referenced
83 * @param resources
84 * static resources that might be referenced
85 * @param base
86 * base folder of the table
87 * @throws IOException
88 * in case of IO problems with the element output
89 */
90 public void render(final HTMLElement parent,
91 final List<? extends ITableItem> items, final ICoverageNode total,
92 final Resources resources, final ReportOutputFolder base)
93 throws IOException {
94 final List<? extends ITableItem> sortedItems = sort(items);
95 final HTMLElement table = parent.table(Styles.COVERAGETABLE);
96 table.attr("id", "coveragetable");
97 header(table, sortedItems, total, resources, base);
98 footer(table, total, resources, base);
99 body(table, sortedItems, resources, base);
100 }
101
102 private void header(final HTMLElement table,
103 final List<? extends ITableItem> items, final ICoverageNode total,
104 final Resources resources, final ReportOutputFolder base)
105 throws IOException {
106 final HTMLElement tr = table.thead().tr();
107 for (final Column c : columns) {
108 c.init(tr, items, total);
109 }
110 }
111
112 private void footer(final HTMLElement table, final ICoverageNode total,
113 final Resources resources, final ReportOutputFolder base)
114 throws IOException {
115 final HTMLElement tr = table.tfoot().tr();
116 for (final Column c : columns) {
117 c.footer(tr, total, resources, base);
118 }
119 }
120
121 private void body(final HTMLElement table,
122 final List<? extends ITableItem> items, final Resources resources,
123 final ReportOutputFolder base) throws IOException {
124 final HTMLElement tbody = table.tbody();
125 int idx = 0;
126 for (final ITableItem item : items) {
127 final HTMLElement tr = tbody.tr();
128 for (final Column c : columns) {
129 c.body(tr, idx, item, resources, base);
130 }
131 idx++;
132 }
133 }
134
135 private List<? extends ITableItem> sort(
136 final List<? extends ITableItem> items) {
137 if (defaultComparator != null) {
138 final ArrayList<ITableItem> result = new ArrayList<ITableItem>(
139 items);
140 Collections.sort(result, defaultComparator);
141 return result;
142 }
143 return items;
144 }
145
146 private static class Column {
147
148 private final char idprefix;
149 private final String header;
150 private final IColumnRenderer renderer;
151 private final SortIndex<ITableItem> index;
152 private final String style, headerStyle;
153
154 private boolean visible;
155
156 Column(final int idx, final String header, final String style,
157 final IColumnRenderer renderer, final boolean defaultSorting) {
158 this.idprefix = (char) ('a' + idx);
159 this.header = header;
160 this.renderer = renderer;
161 index = new SortIndex<ITableItem>(renderer.getComparator());
162 this.style = style;
163 this.headerStyle = Styles.combine(defaultSorting ? Styles.DOWN
164 : null, Styles.SORTABLE, style);
165 }
166
167 void init(final HTMLElement tr, final List<? extends ITableItem> items,
168 final ICoverageNode total) throws IOException {
169 visible = renderer.init(items, total);
170 if (visible) {
171 if (index != null) {
172 index.init(items);
173 }
174 final HTMLElement td = tr.td(headerStyle);
175 td.attr("id", String.valueOf(idprefix));
176 if (index != null) {
177 td.attr("onclick", "toggleSort(this)");
178 }
179 td.text(header);
180 }
181 }
182
183 void footer(final HTMLElement tr, final ICoverageNode total,
184 final Resources resources, final ReportOutputFolder base)
185 throws IOException {
186 if (visible) {
187 renderer.footer(tr.td(style), total, resources, base);
188 }
189 }
190
191 void body(final HTMLElement tr, final int idx, final ITableItem item,
192 final Resources resources, final ReportOutputFolder base)
193 throws IOException {
194 if (visible) {
195 final HTMLElement td = tr.td(style);
196 if (index != null) {
197 td.attr("id",
198 idprefix + String.valueOf(index.getPosition(idx)));
199 }
200 renderer.item(td, item, resources, base);
201 }
202 }
203
204 }
205
206}