package org.sigmah.server.servlet.exporter; /* * #%L * Sigmah * %% * Copyright (C) 2010 - 2016 URD * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU 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 General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program. If not, see * <http://www.gnu.org/licenses/gpl-3.0.html>. * #L% */ import java.io.IOException; import java.io.OutputStream; import java.io.StringReader; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; import javax.persistence.EntityManager; import javax.servlet.http.HttpServletRequest; import org.sigmah.client.page.RequestParameter; import org.sigmah.server.domain.report.ProjectReport; import org.sigmah.server.domain.report.ProjectReportVersion; import org.sigmah.server.handler.GetProjectReportHandler; import org.sigmah.server.servlet.base.ServletExecutionContext; import org.sigmah.server.servlet.exporter.base.Exporter; import org.sigmah.shared.dto.report.ProjectReportContent; import org.sigmah.shared.dto.report.ProjectReportDTO; import org.sigmah.shared.dto.report.ProjectReportSectionDTO; import org.sigmah.shared.dto.report.RichTextElementDTO; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.inject.Injector; import com.lowagie.text.Chapter; import com.lowagie.text.Document; import com.lowagie.text.DocumentException; import com.lowagie.text.Element; import com.lowagie.text.Font; import com.lowagie.text.Paragraph; import com.lowagie.text.Section; import com.lowagie.text.TextElementArray; import com.lowagie.text.html.HtmlTags; import com.lowagie.text.html.simpleparser.HTMLWorker; import com.lowagie.text.html.simpleparser.StyleSheet; import com.lowagie.text.rtf.RtfWriter2; import com.lowagie.text.rtf.field.RtfTableOfContents; /** * Export project reports as RTF files. * * @author Raphaƫl Calabro (rcalabro@ideia.fr) (v1.3) */ public class ProjectReportExporter extends Exporter { /** * Logger. */ private final static Logger LOG = LoggerFactory.getLogger(ProjectReportExporter.class); private ProjectReport report; public ProjectReportExporter(final Injector injector, final HttpServletRequest req, ServletExecutionContext context) throws Exception { super(injector, req, context); } @Override public String getFileName() { final SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss"); try { loadReport(); } catch (Exception e) { LOG.debug("The project report cannot be found.", e); } final String name; if (report != null) name = report.getName(); else name = "report"; return name + '_' + format.format(new Date()) + getExtention(); } /** * Loads the project report from the database. * * @throws Exception * If the ID parameter is missing or if the report cannot be found. */ private void loadReport() throws Exception { if (report == null) { final String idAsString = requireParameter(RequestParameter.ID); final Integer id; try { id = Integer.parseInt(idAsString); } catch (NumberFormatException e) { LOG.error("[export] The id '" + idAsString + "' is invalid.", e); throw new Exception("The id '" + idAsString + "' is invalid.", e); } report = injector.getInstance(EntityManager.class).find(ProjectReport.class, id); } } @Override public void export(OutputStream output) throws Exception { loadReport(); // Label displayed instead of the Table of Contents during the export. final String tocLabel = localize("projectReportTableOfContents"); if (report != null) { final ProjectReportVersion version = report.getCurrentVersion(); final ProjectReportDTO reportDTO = GetProjectReportHandler.toDTO(report, version); // Generating the RTF try { final Document document = new Document(); final RtfWriter2 writer = RtfWriter2.getInstance(document, output); writer.setAutogenerateTOCEntries(true); document.open(); // Title final Paragraph titleParagraph = new Paragraph(report.getName()); titleParagraph.getFont().setSize(24); titleParagraph.getFont().setStyle(Font.BOLD); document.add(titleParagraph); document.add(new Paragraph()); // Empty paragraph // Table of contents final Paragraph tocParagraph = new Paragraph(); final RtfTableOfContents toc = new RtfTableOfContents(tocLabel); tocParagraph.add(toc); document.add(tocParagraph); // Sections final List<ProjectReportSectionDTO> sections = reportDTO.getSections(); final StringBuilder prefix = new StringBuilder(); for (int index = 0; index < sections.size(); index++) { final ProjectReportSectionDTO section = sections.get(index); prefix.append(index + 1).append('.'); addSection(section, prefix, index + 1, document); prefix.setLength(0); } document.close(); } catch (DocumentException ex) { LOG.error("An error occured while generating the RTF.", ex); } catch (IOException e) { LOG.debug("An error occured while converting HTML to RTF."); } } else { final String idAsString = requireParameter(RequestParameter.ID); LOG.error("[export] No project report is identified by '" + idAsString + "'."); throw new Exception("[export] No project report is identified by '" + idAsString + "'."); } } /** * Adds the given section to the RTF document. * * @param section * Section to add. * @param prefix * Current index (for example: 3.1.1). * @param index * Local index. * @param parent * Parent element. * @throws DocumentException */ private void addSection(ProjectReportSectionDTO section, StringBuilder prefix, int index, Object parent) throws DocumentException, IOException { // Adding the title to the document final TextElementArray thisSection; if (parent instanceof Document) { // Style final Paragraph paragraph = new Paragraph(section.getName()); paragraph.getFont().setSize(16); paragraph.getFont().setStyle(Font.BOLD); // New chapter final Chapter chapter = new Chapter(paragraph, index); thisSection = chapter; } else if (parent instanceof Chapter) { // Style final Paragraph paragraph = new Paragraph(section.getName()); paragraph.getFont().setSize(14); paragraph.getFont().setStyle(Font.BOLD); // New section final Section chapterSection = ((Chapter) parent).addSection(paragraph); thisSection = chapterSection; } else if (parent instanceof TextElementArray) { // Style final Paragraph paragraph = new Paragraph(prefix.toString() + ' ' + section.getName()); paragraph.getFont().setSize(12); paragraph.getFont().setStyle(Font.BOLD); // New paragraph ((TextElementArray) parent).add(paragraph); thisSection = (TextElementArray) parent; } else thisSection = null; // Adding the content of this section int subIndex = 1; final int prefixLength = prefix.length(); final StyleSheet stylesheet = new StyleSheet(); stylesheet.loadTagStyle(HtmlTags.PARAGRAPH, "margin", "0"); stylesheet.loadTagStyle(HtmlTags.PARAGRAPH, "padding", "0"); stylesheet.loadTagStyle(HtmlTags.DIV, "margin", "0"); stylesheet.loadTagStyle(HtmlTags.DIV, "padding", "0"); for (final ProjectReportContent child : section.getChildren()) { if (child instanceof ProjectReportSectionDTO) { prefix.append(index).append('.'); addSection((ProjectReportSectionDTO) child, prefix, subIndex, thisSection); subIndex++; prefix.setLength(prefixLength); } else if (child instanceof RichTextElementDTO) { final String value = ((RichTextElementDTO) child).getText(); if (value != null && !"".equals(value)) { // HTML parsing. @SuppressWarnings("unchecked") final List<Element> elements = HTMLWorker.parseToList(new StringReader(value), stylesheet); for (final Element element : elements) thisSection.add(element); } } } // Adding the chapter to the document if (thisSection instanceof Chapter && parent instanceof Document) ((Document) parent).add(thisSection); } }