/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ro.nextreports.engine.exporter;
import java.awt.Color;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import ro.nextreports.engine.ReleaseInfoAdapter;
import ro.nextreports.engine.Report;
import ro.nextreports.engine.ReportLayout;
import ro.nextreports.engine.band.Band;
import ro.nextreports.engine.band.BandElement;
import ro.nextreports.engine.band.ExpressionBandElement;
import ro.nextreports.engine.band.Hyperlink;
import ro.nextreports.engine.band.HyperlinkBandElement;
import ro.nextreports.engine.band.ImageBandElement;
import ro.nextreports.engine.band.ImageColumnBandElement;
import ro.nextreports.engine.band.Padding;
import ro.nextreports.engine.band.PaperSize;
import ro.nextreports.engine.band.ReportBandElement;
import ro.nextreports.engine.band.VariableBandElement;
import ro.nextreports.engine.exporter.util.StyleFormatConstants;
import ro.nextreports.engine.exporter.util.variable.PageNoVariable;
import ro.nextreports.engine.exporter.util.variable.Variable;
import ro.nextreports.engine.exporter.util.variable.VariableFactory;
import ro.nextreports.engine.queryexec.QueryException;
import ro.nextreports.engine.util.PrefixSuffix;
import ro.nextreports.engine.util.StringUtil;
import com.lowagie.text.BadElementException;
import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.Element;
import com.lowagie.text.Font;
import com.lowagie.text.FontFactory;
import com.lowagie.text.FontFactoryImp;
import com.lowagie.text.HeaderFooter;
import com.lowagie.text.Phrase;
import com.lowagie.text.Rectangle;
import com.lowagie.text.Table;
import com.lowagie.text.PageSize;
import com.lowagie.text.Image;
import com.lowagie.text.Anchor;
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.RtfPageNumber;
import com.lowagie.text.rtf.headerfooter.RtfHeaderFooter;
import com.lowagie.text.rtf.headerfooter.RtfHeaderFooterGroup;
import com.lowagie.text.rtf.table.RtfBorder;
import com.lowagie.text.rtf.table.RtfBorderGroup;
import com.lowagie.text.rtf.table.RtfCell;
/**
* Created by IntelliJ IDEA. User: mihai.panaitescu Date: 24-Feb-2009 Time:
* 11:46:10
*/
public class RtfExporter extends ResultExporter {
public RtfExporter(ExporterBean bean) {
super(bean);
}
protected void initExport() throws QueryException {
if (!bean.isSubreport()) {
Padding margins = bean.getReportLayout().getPagePadding();
Rectangle rectangle;
if (ReportLayout.CUSTOM.equals(bean.getReportLayout().getPageFormat())) {
PaperSize customSize = bean.getReportLayout().getPaperSize();
rectangle = new Rectangle(customSize.getWidthPoints(), customSize.getHeightPoints());
} else {
rectangle = PageSize.getRectangle(getPageFormat());
}
document = new Document(rectangle, getPoints(margins.getLeft()),
getPoints(margins.getRight()), getPoints(margins.getTop()), getPoints(margins.getBottom()));
if (bean.getReportLayout().getOrientation() == LANDSCAPE) {
document.setPageSize(rectangle.rotate());
}
RtfWriter2 writer2 = RtfWriter2.getInstance(document, getOut());
}
try {
if (!bean.isSubreport()) {
buildHeader();
buildFooter();
addMetaData();
document.open();
}
table = buildRtfTable(PRINT_DOCUMENT);
} catch (DocumentException e) {
e.printStackTrace();
throw new QueryException(e);
}
}
// Metadata methods must be called after establishing the document writer
// and prior
// to opening the document
private void addMetaData() {
document.addTitle(getDocumentTitle());
document.addAuthor(ReleaseInfoAdapter.getCompany());
document.addCreator("NextReports " + ReleaseInfoAdapter.getVersionNumber());
document.addSubject("Created by NextReports Designer" + ReleaseInfoAdapter.getVersionNumber());
document.addCreationDate();
document.addKeywords(ReleaseInfoAdapter.getHome());
}
protected void finishExport() {
if (!bean.isSubreport()) {
try {
if (table != null) {
document.add(table);
}
} catch (DocumentException e) {
e.printStackTrace();
} finally {
table = null;
document.close();
}
}
}
protected void close() {
if (!bean.isSubreport()) {
document.close();
}
}
protected void flush() {
}
protected void flushNow() {
}
protected Set<CellElement> getIgnoredCells(Band band) {
return getIgnoredCellElements(band);
}
protected void exportCell(String bandName, BandElement bandElement, Object value, int gridRow, int row, int column, int cols,
int rowSpan, int colSpan, boolean isImage) {
if (!bean.isSubreport()) {
if (ReportLayout.PAGE_HEADER_BAND_NAME.equals(bandName)) {
header.addCell(renderRtfCell(bandElement, value, gridRow, column, rowSpan, colSpan, isImage));
} else if (ReportLayout.PAGE_FOOTER_BAND_NAME.equals(bandName)) {
footer.addCell(renderRtfCell(bandElement, value, gridRow, column, rowSpan, colSpan, isImage));
} else {
table.addCell(renderRtfCell(bandElement, value, gridRow, column, rowSpan, colSpan, isImage));
}
} else {
table.addCell(renderRtfCell(bandElement, value, gridRow, column, rowSpan, colSpan, isImage));
}
}
protected void afterRowExport() {
}
protected String getNullElement() {
return "";
}
private int fragmentsize = 15000;
private Document document;
private Table table;
private Table header;
private Table footer;
private RtfCell renderRtfCell(BandElement bandElement, Object value, int gridRow, int gridColumn, int rowSpan, int colSpan,
boolean image) {
Map<String, Object> style = buildCellStyleMap(bandElement, value, gridRow, gridColumn, colSpan);
String stringValue;
FontFactoryImp fact = new FontFactoryImp();
Font fnt;
if (bandElement != null) {
String fontName = (String) style.get(StyleFormatConstants.FONT_NAME_KEY);
int size = ((Float) style.get(StyleFormatConstants.FONT_SIZE)).intValue();
fnt = getFont(fontName, size);
} else {
fnt = getFont(10);
}
RtfCell cell = null;
boolean specialCell = false;
if (image) {
try {
if (value == null) {
cell = new RtfCell(new Phrase(IMAGE_NOT_FOUND));
} else {
ImageBandElement ibe = (ImageBandElement) bandElement;
byte[] imageBytes = getImage((String) value, ibe.getWidth(), ibe.getHeight());
cell = new RtfCell(Image.getInstance(imageBytes));
}
} catch (Exception e) {
cell = new RtfCell(IMAGE_NOT_LOADED);
}
specialCell = true;
} else if (bandElement instanceof HyperlinkBandElement) {
Hyperlink hyperlink = ((HyperlinkBandElement) bandElement).getHyperlink();
Anchor anchor = new Anchor(hyperlink.getText(), fnt);
anchor.setReference(hyperlink.getUrl());
Phrase ph = new Phrase();
ph.add(anchor);
try {
cell = new RtfCell(ph);
} catch (BadElementException e) {
e.printStackTrace();
cell = new RtfCell(hyperlink.getText());
}
specialCell = true;
} else if (bandElement instanceof ReportBandElement) {
Report report = ((ReportBandElement)bandElement).getReport();
ExporterBean eb = null;
try {
eb = getSubreportExporterBean(report);
RtfExporter subExporter = new RtfExporter(eb);
subExporter.export();
Table innerTable = subExporter.getTable();
cell = new RtfCell(innerTable);
} catch (Exception e) {
cell = new RtfCell();
e.printStackTrace();
} finally {
if ((eb != null) && (eb.getResult() != null)) {
eb.getResult().close();
}
}
specialCell = true;
} else if (bandElement instanceof VariableBandElement) {
VariableBandElement vbe = (VariableBandElement) bandElement;
Variable var = VariableFactory.getVariable(vbe.getVariable());
if (var instanceof PageNoVariable) {
cell = new RtfCell();
cell.add(new RtfPageNumber());
cell.setBorderWidth(0);
specialCell = true;
}
} else if (bandElement instanceof ExpressionBandElement) {
// special case pageNo inside an expression
// bandName is not important here (it is used for groupRow
// computation)
PrefixSuffix pf = interpretPageNo(bandElement);
if (pf != null) {
updateFont(fnt, style);
cell = new RtfCell();
if (!"".equals(pf.getPrefix())) {
cell.add(new Phrase(pf.getPrefix(), fnt));
}
cell.add(new RtfPageNumber(fnt));
if (!"".equals(pf.getSuffix())) {
cell.add(new Phrase(pf.getSuffix(), fnt));
}
specialCell = true;
}
} else if (bandElement instanceof ImageColumnBandElement){
try {
String v = StringUtil.getValueAsString(value, null);
if(StringUtil.BLOB.equals(v)) {
cell = new RtfCell(new Phrase(StringUtil.BLOB));
} else {
ImageColumnBandElement icbe = (ImageColumnBandElement) bandElement;
byte[] imageD = StringUtil.decodeImage(v);
byte[] imageBytes = getImage(imageD, icbe.getWidth(), icbe.getHeight());
cell = new RtfCell(Image.getInstance(imageBytes));
}
} catch (Exception e) {
cell = new RtfCell(IMAGE_NOT_LOADED);
}
specialCell = true;
}
if (!specialCell) {
if (style.containsKey(StyleFormatConstants.PATTERN)) {
stringValue = StringUtil.getValueAsString(value, (String) style.get(StyleFormatConstants.PATTERN), getReportLanguage());
} else {
stringValue = StringUtil.getValueAsString(value, null, getReportLanguage());
}
if (stringValue == null) {
stringValue = "";
}
Phrase ph;
if (stringValue.startsWith("<html>")) {
StringReader reader = new StringReader(stringValue);
List<Element> elems = new ArrayList<Element>();
try {
elems = HTMLWorker.parseToList(reader, new StyleSheet());
ph = new Phrase();
for (int i = 0; i < elems.size(); i++) {
Element elem = (Element) elems.get(i);
ph.add(elem);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
ph = new Phrase(stringValue, fnt);
}
} else {
ph = new Phrase(stringValue, fnt);
}
try {
cell = new RtfCell(ph);
} catch (BadElementException e) {
e.printStackTrace();
cell = new RtfCell(stringValue);
}
}
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
if (colSpan > 1) {
cell.setColspan(colSpan);
}
if (rowSpan > 1) {
cell.setRowspan(rowSpan);
}
setCellStyle(fnt, style, cell);
return cell;
}
private void updateFont(Font fnt, Map<String, Object> style) {
if (style != null) {
if (style.containsKey(StyleFormatConstants.FONT_FAMILY_KEY)) {
String val = (String) style.get(StyleFormatConstants.FONT_FAMILY_KEY);
fnt.setFamily(val);
}
if (style.containsKey(StyleFormatConstants.FONT_SIZE)) {
Float val = (Float) style.get(StyleFormatConstants.FONT_SIZE);
fnt.setSize(val);
}
if (style.containsKey(StyleFormatConstants.FONT_COLOR)) {
Color val = (Color) style.get(StyleFormatConstants.FONT_COLOR);
fnt.setColor(val);
}
if (style.containsKey(StyleFormatConstants.FONT_STYLE_KEY)) {
if (StyleFormatConstants.FONT_STYLE_NORMAL.equals(style.get(StyleFormatConstants.FONT_STYLE_KEY))) {
fnt.setStyle(com.lowagie.text.Font.NORMAL);
}
if (StyleFormatConstants.FONT_STYLE_BOLD.equals(style.get(StyleFormatConstants.FONT_STYLE_KEY))) {
fnt.setStyle(com.lowagie.text.Font.BOLD);
}
if (StyleFormatConstants.FONT_STYLE_ITALIC.equals(style.get(StyleFormatConstants.FONT_STYLE_KEY))) {
fnt.setStyle(com.lowagie.text.Font.ITALIC);
}
if (StyleFormatConstants.FONT_STYLE_BOLDITALIC.equals(style.get(StyleFormatConstants.FONT_STYLE_KEY))) {
fnt.setStyle(com.lowagie.text.Font.BOLDITALIC);
}
}
}
}
private void setCellStyle(Font fnt, Map<String, Object> style, RtfCell cell) {
if (style != null) {
updateFont(fnt, style);
if (style.containsKey(StyleFormatConstants.BACKGROUND_COLOR)) {
Color val = (Color) style.get(StyleFormatConstants.BACKGROUND_COLOR);
cell.setBackgroundColor(val);
}
if (style.containsKey(StyleFormatConstants.HORIZONTAL_ALIGN_KEY)) {
if (StyleFormatConstants.HORIZONTAL_ALIGN_LEFT.equals(style.get(StyleFormatConstants.HORIZONTAL_ALIGN_KEY))) {
cell.setHorizontalAlignment(Element.ALIGN_LEFT);
}
if (StyleFormatConstants.HORIZONTAL_ALIGN_RIGHT.equals(style.get(StyleFormatConstants.HORIZONTAL_ALIGN_KEY))) {
cell.setHorizontalAlignment(Element.ALIGN_RIGHT);
}
if (StyleFormatConstants.HORIZONTAL_ALIGN_CENTER.equals(style.get(StyleFormatConstants.HORIZONTAL_ALIGN_KEY))) {
cell.setHorizontalAlignment(Element.ALIGN_CENTER);
}
}
if (style.containsKey(StyleFormatConstants.VERTICAL_ALIGN_KEY)) {
if (StyleFormatConstants.VERTICAL_ALIGN_TOP.equals(style.get(StyleFormatConstants.VERTICAL_ALIGN_KEY))) {
cell.setVerticalAlignment(Element.ALIGN_TOP);
}
if (StyleFormatConstants.VERTICAL_ALIGN_MIDDLE.equals(style.get(StyleFormatConstants.VERTICAL_ALIGN_KEY))) {
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
}
if (StyleFormatConstants.VERTICAL_ALIGN_BOTTOM.equals(style.get(StyleFormatConstants.VERTICAL_ALIGN_KEY))) {
cell.setVerticalAlignment(Element.ALIGN_BOTTOM);
}
}
// if (style.containsKey(StyleFormatConstants.PADDING_LEFT)) {
// Float val = (Float) style.get(StyleFormatConstants.PADDING_LEFT);
// cell.setPaddingLeft(val);
// }
// if (style.containsKey(StyleFormatConstants.PADDING_RIGHT)) {
// Float val = (Float)
// style.get(StyleFormatConstants.PADDING_RIGHT);
// cell.setPaddingRight(val);
// }
// if (style.containsKey(StyleFormatConstants.PADDING_TOP)) {
// Float val = (Float) style.get(StyleFormatConstants.PADDING_TOP);
// cell.setPaddingTop(val);
// }
// if (style.containsKey(StyleFormatConstants.PADDING_BOTTOM)) {
// Float val = (Float)
// style.get(StyleFormatConstants.PADDING_BOTTOM);
// cell.setPaddingBottom(val);
// }
cell.setBorderWidth(0);
Float val = Float.valueOf(1);
RtfBorderGroup bg = new RtfBorderGroup();
if (style.containsKey(StyleFormatConstants.BORDER_LEFT)) {
val = (Float) style.get(StyleFormatConstants.BORDER_LEFT);
Color color = (Color) style.get(StyleFormatConstants.BORDER_LEFT_COLOR);
bg.addBorder(Rectangle.LEFT, RtfBorder.BORDER_SINGLE, val, color);
}
if (style.containsKey(StyleFormatConstants.BORDER_RIGHT)) {
val = (Float) style.get(StyleFormatConstants.BORDER_RIGHT);
Color color = (Color) style.get(StyleFormatConstants.BORDER_RIGHT_COLOR);
bg.addBorder(Rectangle.RIGHT, RtfBorder.BORDER_SINGLE, val, color);
}
if (style.containsKey(StyleFormatConstants.BORDER_TOP)) {
val = (Float) style.get(StyleFormatConstants.BORDER_TOP);
Color color = (Color) style.get(StyleFormatConstants.BORDER_TOP_COLOR);
bg.addBorder(Rectangle.TOP, RtfBorder.BORDER_SINGLE, val, color);
}
if (style.containsKey(StyleFormatConstants.BORDER_BOTTOM)) {
val = (Float) style.get(StyleFormatConstants.BORDER_BOTTOM);
Color color = (Color) style.get(StyleFormatConstants.BORDER_BOTTOM_COLOR);
bg.addBorder(Rectangle.BOTTOM, RtfBorder.BORDER_SINGLE, val, color);
}
cell.setBorders(bg);
// cell.setNoWrap(true);
// if (bandElement != null) {
// if (bandElement.isWrapText()) {
// cell.setNoWrap(false);
// }
// }
}
}
private Font getFont(String fontName, int size) {
return FontFactory.getFont(fontName, size);
}
private Font getFont(int size) {
return FontFactory.getFont(FontFactory.TIMES, size);
}
// type : PRINT_DOCUMENT, PRINT_PAGE_HEADER, PRINT_PAGE_FOOTER
private Table buildRtfTable(int type) throws DocumentException {
List<Band> bands = new ArrayList<Band>();
if (type == 1) {
bands.add(getReportLayout().getPageHeaderBand());
} else if (type == 2) {
bands.add(getReportLayout().getPageFooterBand());
} else {
bands = getReportLayout().getDocumentBands();
}
int totalRows = 0;
int totalColumns = 0;
for (Band band : bands) {
totalRows += band.getRowCount();
int cols = band.getColumnCount();
if (cols > totalColumns) {
totalColumns = cols;
}
}
// no page header or no page footer
if (totalColumns == 0) {
return null;
}
Table datatable = new Table(totalColumns);
int[] headerwidths = new int[totalColumns]; // %
int size = 100 / totalColumns;
int totalWidth = 0;
for (int i = 0; i < totalColumns; i++) {
if (bean.getReportLayout().isUseSize()) {
headerwidths[i] = bean.getReportLayout().getColumnsWidth().get(i);
} else {
headerwidths[i] = size;
}
totalWidth += headerwidths[i];
}
if (bean.getReportLayout().isUseSize()) {
float pixels = A4_PORTRAIT_PIXELS;
if (bean.getReportLayout().getOrientation() == LANDSCAPE) {
pixels = A4_LANDSCAPE_PIXELS;
}
float percentage = totalWidth * 100 / pixels;
// do not allow to go outside an A4 frame
if (percentage > 100) {
percentage = 100;
}
if (!ReportLayout.CUSTOM.equals(bean.getReportLayout().getPageFormat())) {
datatable.setWidth(percentage);
}
datatable.setWidths(headerwidths);
} else {
datatable.setWidth(100);
}
datatable.setPadding(2);
if (type == PRINT_DOCUMENT) {
writeHeader(datatable);
}
return datatable;
}
private void writeHeader(Table datatable) {
if (bean.getReportLayout().isHeaderOnEveryPage()) {
int headerNo = bean.getReportLayout().getHeaderBand().getRowCount();
if (headerNo > 0) {
datatable.setLastHeaderRow(headerNo);
}
}
}
private void buildHeader() throws DocumentException, QueryException {
header = buildRtfTable(PRINT_PAGE_HEADER);
if (header == null) {
return;
}
printPageHeaderBand();
HeaderFooter hf = new RtfHeaderFooter(header);
document.setHeader(hf);
}
private void buildFooter() throws DocumentException, QueryException {
footer = buildRtfTable(PRINT_PAGE_FOOTER);
if (footer == null) {
return;
}
printPageFooterBand();
RtfHeaderFooterGroup footerGroup = new RtfHeaderFooterGroup();
RtfHeaderFooter hf = new RtfHeaderFooter(footer);
footerGroup.setHeaderFooter(hf, RtfHeaderFooter.DISPLAY_ALL_PAGES);
document.setFooter(footerGroup);
}
protected void newPage() {
if (!bean.isSubreport()) {
try {
document.add(table);
document.newPage();
table.deleteAllRows();
if (bean.getReportLayout().isHeaderOnEveryPage()) {
try {
printHeaderBand();
} catch (QueryException e) {
e.printStackTrace();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
private String getPageFormat() {
String format = bean.getReportLayout().getPageFormat();
// not supported by RTF
if (ReportLayout.A0.equals(format) || ReportLayout.A1.equals(format)) {
format = ReportLayout.A2;
}
return format;
}
public Table getTable() {
return table;
}
}