/**
* ***************************************************************************
* Copyright (c) 2010 Qcadoo Limited
* Project: Qcadoo Framework
* Version: 1.4
*
* This file is part of Qcadoo.
*
* Qcadoo is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
* ***************************************************************************
*/
package com.qcadoo.report.internal;
import com.google.common.collect.Lists;
import com.lowagie.text.*;
import com.lowagie.text.pdf.PdfPCell;
import com.lowagie.text.pdf.PdfPTable;
import com.lowagie.text.pdf.draw.LineSeparator;
import com.qcadoo.localization.api.TranslationService;
import com.qcadoo.localization.api.utils.DateUtils;
import com.qcadoo.model.api.DataDefinitionService;
import com.qcadoo.model.api.Entity;
import com.qcadoo.report.api.ColorUtils;
import com.qcadoo.report.api.FontUtils;
import com.qcadoo.report.api.pdf.HeaderAlignment;
import com.qcadoo.report.api.pdf.PdfHelper;
import com.qcadoo.report.api.pdf.TableBorderEvent;
import com.qcadoo.security.api.SecurityService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.net.MalformedURLException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.List;
import static org.springframework.context.i18n.LocaleContextHolder.getLocale;
@Component
public final class PdfHelperImpl implements PdfHelper {
private static final Logger LOG = LoggerFactory.getLogger(PdfHelperImpl.class);
private static final Integer MINIMUM_ALLOWABLE_SIZE_COLUMN_IN_PIXEL = 63;
private static final String QCADOO_SECURITY = "qcadooSecurity";
private static final String USER = "user";
private static final String FIRST_NAME = "firstName";
private static final String LAST_NAME = "lastName";
private static final String USER_NAME = "userName";
@Autowired
private DataDefinitionService dataDefinitionService;
@Autowired
private TranslationService translationService;
@Autowired
private SecurityService securityService;
@Override
public void addDocumentHeader(final Document document, final String name, final String documenTitle,
final String documentAuthor, final Date date, final String username) throws DocumentException {
SimpleDateFormat df = new SimpleDateFormat(DateUtils.L_DATE_TIME_FORMAT, getLocale());
LineSeparator line = new LineSeparator(3, 100f, ColorUtils.getLineDarkColor(), Element.ALIGN_LEFT, 0);
document.add(Chunk.NEWLINE);
Paragraph title = new Paragraph(new Phrase(documenTitle, FontUtils.getDejavuBold17Light()));
title.add(new Phrase(" " + name, FontUtils.getDejavuBold17Dark()));
title.setSpacingAfter(7f);
document.add(title);
document.add(line);
PdfPTable userAndDate = new PdfPTable(2);
userAndDate.setWidthPercentage(100f);
userAndDate.setHorizontalAlignment(Element.ALIGN_LEFT);
userAndDate.getDefaultCell().setBorderWidth(0);
Paragraph userParagraph = new Paragraph(new Phrase(documentAuthor, FontUtils.getDejavuRegular9Light()));
userParagraph.add(new Phrase(" " + username, FontUtils.getDejavuRegular9Dark()));
Paragraph dateParagraph = new Paragraph(df.format(date), FontUtils.getDejavuRegular9Light());
userAndDate.addCell(userParagraph);
userAndDate.getDefaultCell().setHorizontalAlignment(Element.ALIGN_RIGHT);
userAndDate.addCell(dateParagraph);
userAndDate.setSpacingAfter(14f);
document.add(userAndDate);
}
@Override
public void addDocumentHeader(final Document document, final String name, final String documenTitle,
final String documentAuthor, final Date date) throws DocumentException {
SimpleDateFormat df = new SimpleDateFormat(DateUtils.L_DATE_TIME_FORMAT, getLocale());
LineSeparator line = new LineSeparator(2, 100f, ColorUtils.getLineDarkColor(), Element.ALIGN_LEFT, 0);
document.add(Chunk.NEWLINE);
Paragraph title = new Paragraph(new Phrase(documenTitle, FontUtils.getDejavuBold17Light()));
title.add(new Phrase(" " + name, FontUtils.getDejavuBold17Dark()));
title.setSpacingAfter(7f);
document.add(title);
document.add(line);
PdfPTable userAndDate = new PdfPTable(2);
userAndDate.setWidthPercentage(100f);
userAndDate.setHorizontalAlignment(Element.ALIGN_LEFT);
userAndDate.getDefaultCell().setBorderWidth(0);
Paragraph userParagraph = new Paragraph(new Phrase(documentAuthor, FontUtils.getDejavuRegular9Light()));
userParagraph.add(new Phrase(" " + getDocumentAuthor(), FontUtils.getDejavuRegular9Dark()));
Paragraph dateParagraph = new Paragraph(df.format(date), FontUtils.getDejavuRegular9Light());
userAndDate.addCell(userParagraph);
userAndDate.getDefaultCell().setHorizontalAlignment(Element.ALIGN_RIGHT);
userAndDate.addCell(dateParagraph);
userAndDate.setSpacingAfter(14f);
document.add(userAndDate);
}
@Override
public void addDocumentHeaderThin(final Document document, final String name, final String documentTitle,
final String documentAuthor, final Date date) throws DocumentException {
SimpleDateFormat df = new SimpleDateFormat(DateUtils.L_DATE_TIME_FORMAT, getLocale());
LineSeparator line = new LineSeparator(2, 100f, ColorUtils.getLineDarkColor(), Element.ALIGN_LEFT, 0);
Paragraph title = new Paragraph(new Phrase(documentTitle, FontUtils.getDejavuBold14Light()));
title.add(new Phrase(" " + name, FontUtils.getDejavuBold14Dark()));
title.setSpacingAfter(7f);
document.add(title);
document.add(line);
PdfPTable userAndDate = new PdfPTable(2);
userAndDate.setWidthPercentage(100f);
userAndDate.setHorizontalAlignment(Element.ALIGN_LEFT);
userAndDate.getDefaultCell().setBorderWidth(0);
Paragraph userParagraph = new Paragraph(new Phrase(documentAuthor, FontUtils.getDejavuRegular9Light()));
userParagraph.add(new Phrase(" " + getDocumentAuthor(), FontUtils.getDejavuRegular9Dark()));
Paragraph dateParagraph = new Paragraph(df.format(date), FontUtils.getDejavuRegular9Light());
userAndDate.addCell(userParagraph);
userAndDate.getDefaultCell().setHorizontalAlignment(Element.ALIGN_RIGHT);
userAndDate.addCell(dateParagraph);
userAndDate.setSpacingAfter(10f);
document.add(userAndDate);
}
@Override
public void addMetaData(final Document document) {
document.addSubject("Using iText");
document.addKeywords("Java, PDF, iText");
document.addAuthor("QCADOO");
document.addCreator("QCADOO");
}
@Override
public PdfPTable createPanelTable(final int column) {
PdfPTable mainData = new PdfPTable(column);
mainData.setWidthPercentage(100f);
mainData.getDefaultCell().setBorder(Rectangle.NO_BORDER);
mainData.getDefaultCell().setVerticalAlignment(Element.ALIGN_TOP);
mainData.getDefaultCell().setPadding(4.0f);
mainData.setTableEvent(new TableBorderEvent());
return mainData;
}
@Override
public PdfPTable createPanelTableWithSimpleFormat(final int column) {
PdfPTable pdfPTable = new PdfPTable(column);
pdfPTable.getDefaultCell().setBorder(Rectangle.NO_BORDER);
pdfPTable.getDefaultCell().setPadding(6.0f);
pdfPTable.getDefaultCell().setVerticalAlignment(PdfPCell.ALIGN_TOP);
return pdfPTable;
}
@Override
public void addTableCellAsTable(final PdfPTable table, final String label, final Object fieldValue, final Font headerFont,
final Font valueFont, final int columns) {
addTableCellAsTable(table, label, fieldValue, "-", headerFont, valueFont, columns);
}
@Override
public void addTableCellAsTable(final PdfPTable table, final String label, final Object fieldValue, final String nullValue,
final Font headerFont, final Font valueFont, final int columns) {
addTableCellAsTable(table, label, fieldValue, nullValue, headerFont, valueFont, columns, new int[]{});
}
private void addTableCellAsTable(final PdfPTable table, final String label, final Object fieldValue, final String nullValue,
final Font headerFont, final Font valueFont, final int columns, final int[] columnWidths) {
PdfPTable cellTable = new PdfPTable(columns);
if (columnWidths.length > 0) {
try {
cellTable.setWidths(columnWidths);
} catch (DocumentException e) {
LOG.error(e.getMessage(), e);
}
}
cellTable.getDefaultCell().setBorder(Rectangle.NO_BORDER);
cellTable.addCell(new Phrase(label, headerFont));
if (fieldValue == null) {
cellTable.addCell(new Phrase(nullValue, valueFont));
} else {
cellTable.addCell(new Phrase(fieldValue.toString(), valueFont));
}
table.addCell(cellTable);
}
@Override
public void addTableCellAsTwoColumnsTable(final PdfPTable table, final String label, final Object fieldValue) {
addTableCellAsTable(table, label, fieldValue, FontUtils.getDejavuBold7Dark(), FontUtils.getDejavuRegular9Dark(), 2);
}
@Override
public void addTableCellAsTwoColumnsTable(final PdfPTable table, final String label, final Object fieldValue, final int[] columnWidths) {
addTableCellAsTable(table, label, fieldValue, "-", FontUtils.getDejavuBold7Dark(), FontUtils.getDejavuRegular9Dark(), 2, columnWidths);
}
@Override
public void addTableCellAsOneColumnTable(final PdfPTable table, final String label, final Object fieldValue) {
addTableCellAsTable(table, label, fieldValue, FontUtils.getDejavuBold7Dark(), FontUtils.getDejavuRegular9Dark(), 1);
}
@Override
public void addImage(final Document document, final String fileName) {
try {
Image img = Image.getInstance(fileName);
if (img.getWidth() > 515 || img.getHeight() > 370) {
img.scaleToFit(515, 370);
}
document.add(img);
document.add(Chunk.NEWLINE);
} catch (BadElementException e) {
LOG.error(e.getMessage(), e);
} catch (MalformedURLException e) {
LOG.error(e.getMessage(), e);
} catch (IOException e) {
LOG.error(e.getMessage(), e);
} catch (DocumentException e) {
LOG.error(e.getMessage(), e);
}
}
@Override
public PdfPTable createTableWithHeader(int numOfColumns, List<String> header, boolean lastColumnAlignmentToLeft,
HeaderAlignment headerAlignment) {
PdfPTable table = new PdfPTable(numOfColumns);
return setTableProperties(header, lastColumnAlignmentToLeft, table, null);
}
@Override
public PdfPTable createTableWithHeader(final int numOfColumns, final List<String> header,
final boolean lastColumnAlignmentToLeft, final int[] columnWidths, final Map<String, HeaderAlignment> alignments) {
PdfPTable table = new PdfPTable(numOfColumns);
try {
table.setWidths(columnWidths);
} catch (DocumentException e) {
LOG.error(e.getMessage(), e);
}
return setTableProperties(header, lastColumnAlignmentToLeft, table, alignments);
}
@Override
public PdfPTable createTableWithHeader(final int numOfColumns, final List<String> header,
final boolean lastColumnAlignmentToLeft, final int[] columnWidths, final HeaderAlignment alignment) {
PdfPTable table = new PdfPTable(numOfColumns);
try {
table.setWidths(columnWidths);
} catch (DocumentException e) {
LOG.error(e.getMessage(), e);
}
return setTableProperties(header, lastColumnAlignmentToLeft, table, null);
}
@Override
public PdfPTable createTableWithHeader(final int numOfColumns, final List<String> header,
final boolean lastColumnAlignmentToLeft, final Map<String, HeaderAlignment> alignments) {
PdfPTable table = new PdfPTable(numOfColumns);
return setTableProperties(header, lastColumnAlignmentToLeft, table, alignments);
}
@Override
public PdfPTable createTableWithHeader(final int numOfColumns, final List<String> header,
final boolean lastColumnAlignmentToLeft, final int[] columnWidths) {
PdfPTable table = new PdfPTable(numOfColumns);
try {
table.setWidths(columnWidths);
} catch (DocumentException e) {
LOG.error(e.getMessage(), e);
}
return setTableProperties(header, lastColumnAlignmentToLeft, table, null);
}
@Override
public PdfPTable createTableWithHeader(final int numOfColumns, final List<String> header,
final boolean lastColumnAlignmentToLeft) {
PdfPTable table = new PdfPTable(numOfColumns);
return setTableProperties(header, lastColumnAlignmentToLeft, table, null);
}
@Override
public int getMaxSizeOfColumnsRows(final List<Integer> columnsListSize) {
int size = 0;
for (int columnSize : columnsListSize) {
if (columnSize > size) {
size = columnSize;
}
}
return size;
}
@Override
public PdfPTable addDynamicHeaderTableCell(final PdfPTable headerTable, final Map<String, Object> column, final Locale locale) {
if (column.keySet().size() != 0) {
Object key = column.keySet().iterator().next();
addTableCellAsOneColumnTable(headerTable, translationService.translate(key.toString(), locale), column.get(key));
column.remove(key);
}
return headerTable;
}
@Override
public PdfPTable addDynamicHeaderTableCellOneRow(final PdfPTable headerTable, final Map<String, Object> column,
final Locale locale) {
if (column.keySet().size() != 0) {
Object key = column.keySet().iterator().next();
addTableCellAsTwoColumnsTable(headerTable, translationService.translate(key.toString(), locale), column.get(key));
column.remove(key);
}
return headerTable;
}
private PdfPTable setTableProperties(final List<String> header, final boolean lastColumnAligmentToLeft,
final PdfPTable table, final Map<String, HeaderAlignment> alignments) {
table.setWidthPercentage(100f);
table.setHorizontalAlignment(Element.ALIGN_LEFT);
table.setSpacingBefore(7.0f);
// table.getDefaultCell().setBackgroundColor(ColorUtils.getBackgroundColor());
table.getDefaultCell().setBorderColor(ColorUtils.getLineDarkColor());
table.getDefaultCell().setBorderWidth(1.0f);
table.getDefaultCell().setVerticalAlignment(Element.ALIGN_MIDDLE);
table.getDefaultCell().setPadding(5.0f);
table.getDefaultCell().disableBorderSide(Rectangle.RIGHT);
if (alignments == null || alignments.isEmpty()) {
table.getDefaultCell().setHorizontalAlignment(Element.ALIGN_LEFT);
int i = 0;
for (String element : header) {
i++;
if (i == header.size()) {
table.getDefaultCell().enableBorderSide(Rectangle.RIGHT);
}
table.addCell(new Phrase(element, FontUtils.getDejavuBold7Dark()));
if (i == 1) {
table.getDefaultCell().disableBorderSide(Rectangle.LEFT);
}
}
} else {
int i = 0;
for (String element : header) {
i++;
HeaderAlignment alignment = alignments.get(element);
if (HeaderAlignment.LEFT.equals(alignment)) {
table.getDefaultCell().setHorizontalAlignment(Element.ALIGN_LEFT);
} else if (HeaderAlignment.RIGHT.equals(alignment)) {
table.getDefaultCell().setHorizontalAlignment(Element.ALIGN_RIGHT);
}
if (i == header.size()) {
table.getDefaultCell().enableBorderSide(Rectangle.RIGHT);
}
table.addCell(new Phrase(element, FontUtils.getDejavuBold7Dark()));
if (i == 1) {
table.getDefaultCell().disableBorderSide(Rectangle.LEFT);
}
}
}
table.getDefaultCell().setHorizontalAlignment(Element.ALIGN_LEFT);
table.getDefaultCell().setBackgroundColor(null);
table.getDefaultCell().disableBorderSide(Rectangle.RIGHT);
table.getDefaultCell().setBorderColor(ColorUtils.getLineLightColor());
return table;
}
@Override
public int[] getReportColumnWidths(Integer availableWidth, Map<String, Integer> fixedColumns, List<String> allColumns) {
int[] reportColumnWidths = new int[allColumns.size()];
Integer remainedAvailableWidth = availableWidth;
Map<Integer, Integer> columnWithFixedWidth = new HashMap<Integer, Integer>();
int i = 0;
for (String entryColumn : allColumns) {
for (Map.Entry<String, Integer> entryFixedColumn : fixedColumns.entrySet()) {
if (entryColumn.toLowerCase().contains(entryFixedColumn.getKey().toLowerCase())) {
remainedAvailableWidth = remainedAvailableWidth - entryFixedColumn.getValue();
columnWithFixedWidth.put(i, entryFixedColumn.getValue());
}
}
i++;
}
Integer columnWithoutFixedWidth = allColumns.size() - columnWithFixedWidth.size();
if (allColumns.size() == columnWithFixedWidth.size() && remainedAvailableWidth >= 0) {
for (Map.Entry<Integer, Integer> entry : columnWithFixedWidth.entrySet()) {
reportColumnWidths[entry.getKey()] = entry.getValue();
}
} else if (remainedAvailableWidth >= 0
&& remainedAvailableWidth > columnWithoutFixedWidth * MINIMUM_ALLOWABLE_SIZE_COLUMN_IN_PIXEL) {
Integer columnSize = remainedAvailableWidth / columnWithoutFixedWidth;
Arrays.fill(reportColumnWidths, columnSize);
for (Map.Entry<Integer, Integer> entry : columnWithFixedWidth.entrySet()) {
reportColumnWidths[entry.getKey()] = entry.getValue();
}
} else {
Arrays.fill(reportColumnWidths, MINIMUM_ALLOWABLE_SIZE_COLUMN_IN_PIXEL);
for (Map.Entry<Integer, Integer> entry : columnWithFixedWidth.entrySet()) {
reportColumnWidths[entry.getKey()] = entry.getValue();
}
int sumColumnWidths = getSumColumnWidths(reportColumnWidths);
for (int k = 0; k < reportColumnWidths.length; k++) {
reportColumnWidths[k] = getScaledColumnWidth(sumColumnWidths, reportColumnWidths[k], availableWidth);
}
}
return reportColumnWidths;
}
private int getSumColumnWidths(final int[] reportColumnWidths) {
int sumColumnsWidth = 0;
for (int k = 0; k < reportColumnWidths.length; k++) {
sumColumnsWidth += reportColumnWidths[k];
}
return sumColumnsWidth;
}
private int getScaledColumnWidth(final int sumColumnWidths, final int columnWidth, int availableWidth) {
int scaledColumnWidth = (columnWidth * 100) / sumColumnWidths;
return (scaledColumnWidth * availableWidth) / 100;
}
@Override
public String getDocumentAuthor() {
Entity user = dataDefinitionService.get(QCADOO_SECURITY, USER).get(securityService.getCurrentUserId());
String firstName = user.getStringField(FIRST_NAME);
String lastName = user.getStringField(LAST_NAME);
String userName = user.getStringField(USER_NAME);
String documentAuthor = "";
if (!StringUtils.isEmpty(firstName)) {
documentAuthor += firstName;
}
if (!StringUtils.isEmpty(lastName)) {
if (StringUtils.isEmpty(documentAuthor)) {
documentAuthor += lastName;
} else {
documentAuthor += " " + lastName;
}
}
if (StringUtils.isEmpty(documentAuthor)) {
documentAuthor = userName;
} else {
documentAuthor += " (" + userName + ")";
}
return documentAuthor;
}
@Override
public boolean validateReportColumnWidths(Integer availableWidth, Map<String, Integer> fixedColumns, List<String> allColumns) {
Integer remainedAvailableWidth = availableWidth;
for (String entryColumn : allColumns) {
for (Map.Entry<String, Integer> entryFixedColumn : fixedColumns.entrySet()) {
if (entryColumn.toLowerCase().contains(entryFixedColumn.getKey().toLowerCase())) {
remainedAvailableWidth = remainedAvailableWidth - entryFixedColumn.getValue();
}
}
}
if (remainedAvailableWidth >= 0) {
return true;
}
return false;
}
}