/*
* Sonar PDF Report (Maven plugin)
* Copyright (C) 2010 klicap - ingenieria del puzle
* dev@sonar.codehaus.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
*/
package org.sonar.report.pdf;
import java.awt.Color;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Iterator;
import java.util.Properties;
import org.sonar.report.pdf.entity.Measures;
import org.sonar.report.pdf.entity.Project;
import org.sonar.report.pdf.entity.exception.ReportException;
import com.lowagie.text.BadElementException;
import com.lowagie.text.ChapterAutoNumber;
import com.lowagie.text.Chunk;
import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.Element;
import com.lowagie.text.Font;
import com.lowagie.text.Image;
import com.lowagie.text.List;
import com.lowagie.text.ListItem;
import com.lowagie.text.Paragraph;
import com.lowagie.text.Phrase;
import com.lowagie.text.Rectangle;
import com.lowagie.text.Section;
import com.lowagie.text.pdf.PdfCell;
import com.lowagie.text.pdf.PdfPCell;
import com.lowagie.text.pdf.PdfPTable;
import com.lowagie.text.pdf.PdfWriter;
import java.net.URL;
/**
* Concrete PDFReporter. Implements printPdfBody method. This will be the way to extend PDFReport.
*/
public class DefaultPDFReporter extends PDFReporter {
private URL logo;
private String projectKey;
private String sonarUrl;
private Properties configProperties;
private Properties langProperties;
private final static int indentation = 18;
private final static int tablePaddingBottom = 5;
private Document document;
public DefaultPDFReporter(URL logo, String projectKey, String sonarUrl, Properties configProperties,
Properties langProperties) {
this.logo = logo;
this.projectKey = projectKey;
this.sonarUrl = sonarUrl;
this.configProperties = configProperties;
this.langProperties = langProperties;
reportType = "default";
}
@Override
protected void printPdfBody(Document document) throws DocumentException, IOException, org.dom4j.DocumentException,
ReportException {
this.document = document;
// Chapter 1
ChapterAutoNumber chapter1 = new ChapterAutoNumber(new Paragraph(getTextProperty("main.chapter1.title"),
Style.CHAPTER_FONT));
chapter1.add(new Paragraph(getTextProperty("main.chapter1.intro"), Style.NORMAL_FONT));
// Section 1.1
Section section11 = chapter1
.addSection(new Paragraph(getTextProperty("main.chapter1.subtitle1"), Style.TITLE_FONT));
Project project = super.getProject();
printDashboard(project, section11);
// Section 1.2
Section section12 = chapter1
.addSection(new Paragraph(getTextProperty("main.chapter1.subtitle2"), Style.TITLE_FONT));
printProjectInfo(project, section12);
document.add(chapter1);
// Subprojects Chapters (2, 3, 4, ...)
Iterator<Project> it = project.getSubprojects().iterator();
while (it.hasNext()) {
Project subproject = it.next();
ChapterAutoNumber subprojectChapter = new ChapterAutoNumber(new Paragraph(getTextProperty("general.module")
+ ": " + subproject.getName(), Style.TITLE_FONT));
Section sectionX1 = subprojectChapter.addSection(new Paragraph(getTextProperty("main.chapter2.subtitle2X1"),
Style.TITLE_FONT));
printDashboard(subproject, sectionX1);
Section sectionX2 = subprojectChapter.addSection(new Paragraph(getTextProperty("main.chapter2.subtitle2X2"),
Style.TITLE_FONT));
printProjectInfo(subproject, sectionX2);
document.add(subprojectChapter);
}
}
private void printDashboard(Project project, Section section) throws DocumentException {
PdfPTable dashboard = new PdfPTable(3);
dashboard.getDefaultCell().setBorderColor(Color.WHITE);
Font titleFont = new Font(Font.TIMES_ROMAN, 14, Font.BOLD, Color.BLACK);
Font dataFont = new Font(Font.TIMES_ROMAN, 14, Font.BOLD, Color.GRAY);
Font dataFont2 = new Font(Font.TIMES_ROMAN, 10, Font.BOLD, new Color(100, 150, 190));
PdfPTable linesOfCode = new PdfPTable(1);
linesOfCode.getDefaultCell().setBorderColor(Color.WHITE);
linesOfCode.addCell(new Phrase(getTextProperty("general.lines_of_code"), titleFont));
linesOfCode.addCell(new Phrase(project.getMeasure("ncss").getFormatValue(), dataFont));
linesOfCode.addCell(new Phrase(project.getMeasure("packages_count").getFormatValue() + " packages", dataFont2));
linesOfCode.addCell(new Phrase(project.getMeasure("classes_count").getFormatValue() + " classes", dataFont2));
linesOfCode.addCell(new Phrase(project.getMeasure("functions_count").getFormatValue() + " methods", dataFont2));
linesOfCode.addCell(new Phrase(project.getMeasure("duplicated_lines_ratio").getFormatValue() + " duplicated lines",
dataFont2));
PdfPTable comments = new PdfPTable(1);
comments.getDefaultCell().setBorderColor(Color.WHITE);
comments.addCell(new Phrase(getTextProperty("general.comments"), titleFont));
comments.addCell(new Phrase(project.getMeasure("comment_ratio").getFormatValue(), dataFont));
comments.addCell(new Phrase(project.getMeasure("comment_lines").getFormatValue() + " comment lines", dataFont2));
PdfPTable codeCoverage = new PdfPTable(1);
codeCoverage.getDefaultCell().setBorderColor(Color.WHITE);
codeCoverage.addCell(new Phrase(getTextProperty("general.test_count"), titleFont));
codeCoverage.addCell(new Phrase(project.getMeasure("test_count").getFormatValue(), dataFont));
codeCoverage.addCell(new Phrase(project.getMeasure("test_success_percentage").getFormatValue() + " success",
dataFont2));
codeCoverage.addCell(new Phrase(project.getMeasure("code_coverage").getFormatValue() + " coverage", dataFont2));
PdfPTable complexity = new PdfPTable(1);
complexity.getDefaultCell().setBorderColor(Color.WHITE);
complexity.addCell(new Phrase(getTextProperty("general.complexity"), titleFont));
complexity.addCell(new Phrase(project.getMeasure("ccn_function").getFormatValue(), dataFont));
complexity.addCell(new Phrase(project.getMeasure("ccn_class").getFormatValue() + " /class", dataFont2));
complexity.addCell(new Phrase(project.getMeasure("ccn").getFormatValue() + " decision points", dataFont2));
PdfPTable rulesCompliance = new PdfPTable(1);
rulesCompliance.getDefaultCell().setBorderColor(Color.WHITE);
rulesCompliance.addCell(new Phrase(getTextProperty("general.rules_compliance"), titleFont));
rulesCompliance.addCell(new Phrase(project.getMeasure("rules_compliance").getFormatValue(), dataFont));
PdfPTable violations = new PdfPTable(1);
violations.getDefaultCell().setBorderColor(Color.WHITE);
violations.addCell(new Phrase(getTextProperty("general.violations"), titleFont));
violations.addCell(new Phrase(project.getMeasure("rules_violations").getFormatValue(), dataFont));
dashboard.addCell(linesOfCode);
dashboard.addCell(comments);
dashboard.addCell(codeCoverage);
dashboard.addCell(complexity);
dashboard.addCell(rulesCompliance);
dashboard.addCell(violations);
dashboard.setSpacingBefore(8);
section.add(dashboard);
Image ccnDistGraph = getCCNDistribution(project);
if (ccnDistGraph != null) {
section.add(ccnDistGraph);
Paragraph imageFoot = new Paragraph(getTextProperty("metrics.ccn_classes_count_distribution"), Style.FOOT_FONT);
imageFoot.setAlignment(Paragraph.ALIGN_CENTER);
section.add(imageFoot);
}
}
private void printMeasures(Measures measures, Section section) throws org.dom4j.DocumentException, DocumentException {
PdfPTable versioningTable = new PdfPTable(2);
formatTable(versioningTable);
versioningTable.getDefaultCell().setColspan(2);
versioningTable.addCell(new Phrase(super.getTextProperty("general.versioning_information"), Style.TITLE_FONT));
versioningTable.addCell(measures.getVersion());
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd - HH:mm:ss");
versioningTable.addCell(df.format(measures.getDate()));
PdfPTable measuresTable = new PdfPTable(2);
formatTable(measuresTable);
Iterator<String> it = measures.getMeasuresKeys().iterator();
measuresTable.addCell(new Phrase(super.getTextProperty("general.metric"), Style.TITLE_FONT));
measuresTable.addCell(new Phrase(super.getTextProperty("general.value"), Style.TITLE_FONT));
boolean colorEnabled = true;
while (it.hasNext()) {
String measureKey = it.next();
if (colorEnabled) {
measuresTable.getDefaultCell().setGrayFill(0.9f);
colorEnabled = false;
} else {
measuresTable.getDefaultCell().setGrayFill(1);
colorEnabled = true;
}
if (!measureKey.equals("ccn_classes_count_distribution")
&& !measureKey.equals("ccn_classes_percent_distribution")) {
measuresTable.getDefaultCell().setHorizontalAlignment(PdfCell.ALIGN_LEFT);
measuresTable.addCell(super.getTextProperty("metrics." + measureKey));
measuresTable.getDefaultCell().setHorizontalAlignment(PdfCell.ALIGN_CENTER);
measuresTable.addCell(measures.getMeasure(measureKey).getFormatValue());
}
}
measuresTable.setHeaderRows(1);
section.add(versioningTable);
section.add(measuresTable);
}
private void formatTable(PdfPTable table) {
Rectangle page = document.getPageSize();
table.getDefaultCell().setVerticalAlignment(PdfCell.ALIGN_MIDDLE);
table.getDefaultCell().setPaddingBottom(tablePaddingBottom);
table.getDefaultCell().setHorizontalAlignment(PdfCell.ALIGN_CENTER);
table.setTotalWidth(page.getWidth() - document.leftMargin() - document.rightMargin());
table.setSpacingBefore(20);
}
private void printProjectInfo(Project project, Section section) throws DocumentException, org.dom4j.DocumentException {
List data = new List();
data.add(new ListItem(super.getTextProperty("general.name") + ": " + project.getName()));
data.add(new ListItem(super.getTextProperty("general.description") + ": " + project.getDescription()));
data.add(new ListItem(super.getTextProperty("general.modules") + ": "));
List sublist = new List();
if (project.getSubprojects().size() != 0) {
Iterator<Project> it = project.getSubprojects().iterator();
while (it.hasNext()) {
sublist.add(new ListItem(it.next().getName()));
}
} else {
sublist.add(new ListItem(super.getTextProperty("general.no_modules")));
}
sublist.setIndentationLeft(indentation);
data.add(sublist);
section.add(data);
printMeasures(project.getMeasures(), section);
}
@Override
protected URL getLogo() {
return this.logo;
}
@Override
protected String getProjectKey() {
return this.projectKey;
}
@Override
protected String getSonarUrl() {
return this.sonarUrl;
}
@Override
protected void printTocTitle(Toc tocDocument) throws DocumentException {
Paragraph tocTitle = new Paragraph(super.getTextProperty("main.table.of.contents"), Style.TOC_TITLE_FONT);
tocTitle.setAlignment(Element.ALIGN_CENTER);
tocDocument.getTocDocument().add(tocTitle);
tocDocument.getTocDocument().add(Chunk.NEWLINE);
}
@Override
protected void printFrontPage(Document frontPageDocument, PdfWriter frontPageWriter)
throws org.dom4j.DocumentException, ReportException {
try {
URL largeLogo;
if (super.getConfigProperty("front.page.logo").startsWith("http://")) {
largeLogo = new URL(super.getConfigProperty("front.page.logo"));
} else {
largeLogo = this.getClass().getClassLoader().getResource(super.getConfigProperty("front.page.logo"));
}
Image logoImage = Image.getInstance(largeLogo);
Rectangle pageSize = frontPageDocument.getPageSize();
float positionX = pageSize.getWidth() / 2f - logoImage.getWidth() / 2f;
logoImage.setAbsolutePosition(positionX, pageSize.getHeight() - logoImage.getHeight() - 100);
frontPageDocument.add(logoImage);
PdfPTable title = new PdfPTable(1);
title.getDefaultCell().setHorizontalAlignment(PdfPCell.ALIGN_CENTER);
title.getDefaultCell().setBorder(Rectangle.NO_BORDER);
String projectRow = super.getTextProperty("general.project") + ": " + super.getProject().getName();
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
String dateRow = df.format(super.getProject().getMeasures().getDate());
String descriptionRow = super.getProject().getDescription();
title.addCell(new Phrase(projectRow, Style.FRONTPAGE_FONT_1));
title.addCell(new Phrase(descriptionRow, Style.FRONTPAGE_FONT_2));
title.addCell(new Phrase(dateRow, Style.FRONTPAGE_FONT_3));
title.setTotalWidth(pageSize.getWidth() - frontPageDocument.leftMargin() - frontPageDocument.rightMargin());
title.writeSelectedRows(0, -1, frontPageDocument.leftMargin(),
pageSize.getHeight() - logoImage.getHeight() - 150, frontPageWriter.getDirectContent());
} catch (IOException e) {
e.printStackTrace();
} catch (BadElementException e) {
e.printStackTrace();
} catch (DocumentException e) {
e.printStackTrace();
}
}
@Override
protected Properties getLangProperties() {
return langProperties;
}
@Override
protected Properties getReportProperties() {
return configProperties;
}
}