001: /**
002: * ===========================================
003: * JFreeReport : a free Java reporting library
004: * ===========================================
005: *
006: * Project Info: http://reporting.pentaho.org/
007: *
008: * (C) Copyright 2001-2007, by Object Refinery Ltd, Pentaho Corporation and Contributors.
009: *
010: * This library is free software; you can redistribute it and/or modify it under the terms
011: * of the GNU Lesser General Public License as published by the Free Software Foundation;
012: * either version 2.1 of the License, or (at your option) any later version.
013: *
014: * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
015: * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
016: * See the GNU Lesser General Public License for more details.
017: *
018: * You should have received a copy of the GNU Lesser General Public License along with this
019: * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
020: * Boston, MA 02111-1307, USA.
021: *
022: * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
023: * in the United States and other countries.]
024: *
025: * ------------
026: * RTFPrinter.java
027: * ------------
028: * (C) Copyright 2001-2007, by Object Refinery Ltd, Pentaho Corporation and Contributors.
029: */package org.jfree.report.modules.output.table.rtf.helper;
030:
031: import java.awt.Color;
032: import java.io.IOException;
033: import java.io.InputStream;
034: import java.io.OutputStream;
035:
036: import com.lowagie.text.Document;
037: import com.lowagie.text.DocumentException;
038: import com.lowagie.text.Rectangle;
039: import com.lowagie.text.Table;
040: import com.lowagie.text.Cell;
041: import com.lowagie.text.rtf.RtfWriter2;
042: import com.lowagie.text.rtf.table.RtfBorder;
043: import com.lowagie.text.rtf.table.RtfBorderGroup;
044: import com.lowagie.text.rtf.table.RtfCell;
045: import org.jfree.fonts.itext.BaseFontSupport;
046: import org.jfree.report.InvalidReportStateException;
047: import org.jfree.report.JFreeReportInfo;
048: import org.jfree.report.ElementAlignment;
049: import org.jfree.report.layout.model.BorderEdge;
050: import org.jfree.report.layout.model.LogicalPageBox;
051: import org.jfree.report.layout.model.PhysicalPageBox;
052: import org.jfree.report.layout.model.RenderBox;
053: import org.jfree.report.layout.output.ContentProcessingException;
054: import org.jfree.report.layout.output.LogicalPageKey;
055: import org.jfree.report.layout.output.OutputProcessorMetaData;
056: import org.jfree.report.modules.output.table.base.SheetLayout;
057: import org.jfree.report.modules.output.table.base.TableCellDefinition;
058: import org.jfree.report.modules.output.table.base.TableContentProducer;
059: import org.jfree.report.modules.output.table.base.TableRectangle;
060: import org.jfree.report.style.BorderStyle;
061: import org.jfree.report.style.ElementStyleKeys;
062: import org.jfree.report.util.NoCloseOutputStream;
063: import org.jfree.report.util.geom.StrictGeomUtility;
064: import org.jfree.util.Configuration;
065: import org.jfree.util.Log;
066:
067: /**
068: * Creation-Date: 09.05.2007, 14:52:05
069: *
070: * @author Thomas Morgner
071: */
072: public class RTFPrinter {
073: private static final String CREATOR = JFreeReportInfo.getInstance()
074: .getName()
075: + " version " + JFreeReportInfo.getInstance().getVersion();
076:
077: private InputStream templateInputStream;
078: private OutputStream outputStream;
079: private Configuration config;
080: private RTFImageCache imageCache;
081: private Document document;
082: private BaseFontSupport baseFontSupport;
083: private Table table;
084:
085: public RTFPrinter() {
086: }
087:
088: public void init(final Configuration config,
089: final OutputStream outputStream) {
090: this .outputStream = outputStream;
091: this .config = config;
092: }
093:
094: public InputStream getTemplateInputStream() {
095: return templateInputStream;
096: }
097:
098: public void setTemplateInputStream(
099: final InputStream templateInputStream) {
100: this .templateInputStream = templateInputStream;
101: }
102:
103: /** @noinspection IOResourceOpenedButNotSafelyClosed*/
104: public void print(final LogicalPageKey logicalPageKey,
105: final LogicalPageBox logicalPage,
106: final TableContentProducer contentProducer,
107: final OutputProcessorMetaData metaData,
108: final boolean incremental)
109: throws ContentProcessingException {
110: if (document == null) {
111: final RTFOutputProcessorMetaData rtfMetaData = (RTFOutputProcessorMetaData) metaData;
112: baseFontSupport = rtfMetaData.getITextFontStorage()
113: .getBaseFontSupport();
114:
115: final PhysicalPageBox pageFormat = logicalPage
116: .getPageGrid().getPage(0, 0);
117: final float urx = (float) StrictGeomUtility
118: .toExternalValue(pageFormat.getWidth());
119: final float ury = (float) StrictGeomUtility
120: .toExternalValue(pageFormat.getHeight());
121:
122: final float marginLeft = (float) StrictGeomUtility
123: .toExternalValue(pageFormat.getImageableX());
124: final float marginRight = (float) StrictGeomUtility
125: .toExternalValue(pageFormat.getWidth()
126: - pageFormat.getImageableWidth()
127: - pageFormat.getImageableX());
128: final float marginTop = (float) StrictGeomUtility
129: .toExternalValue(pageFormat.getImageableY());
130: final float marginBottom = (float) StrictGeomUtility
131: .toExternalValue(pageFormat.getHeight()
132: - pageFormat.getImageableHeight()
133: - pageFormat.getImageableY());
134: final Rectangle pageSize = new Rectangle(urx, ury);
135:
136: document = new Document(pageSize, marginLeft, marginRight,
137: marginTop, marginBottom);
138: imageCache = new RTFImageCache();
139:
140: // rtf does not support PageFormats or other meta data...
141: final RtfWriter2 instance = RtfWriter2.getInstance(
142: document, new NoCloseOutputStream(outputStream));
143: instance.getDocumentSettings().setAlwaysUseUnicode(true);
144:
145: final String author = config
146: .getConfigProperty("org.jfree.report.modules.output.table.rtf.Author");
147: if (author != null) {
148: document.addAuthor(author);
149: }
150:
151: final String title = config
152: .getConfigProperty("org.jfree.report.modules.output.table.rtf.Title");
153: if (title != null) {
154: document.addTitle(title);
155: }
156:
157: document.addProducer();
158: document.addCreator(CREATOR);
159:
160: try {
161: document.addCreationDate();
162: } catch (Exception e) {
163: Log
164: .debug(
165: "Unable to add creation date. It will have to work without it.",
166: e);
167: }
168:
169: document.open();
170: }
171:
172: // Start a new page.
173: try {
174: final SheetLayout sheetLayout = contentProducer
175: .getSheetLayout();
176: final int columnCount = contentProducer.getColumnCount();
177: if (table == null) {
178: final int rowCount = contentProducer.getRowCount();
179: table = new Table(columnCount, rowCount);
180: table.setAutoFillEmptyCells(false);
181: table.setWidth(100); // span the full page..
182: // and finally the content ..
183:
184: final float[] cellWidths = new float[columnCount];
185: for (int i = 0; i < columnCount; i++) {
186: cellWidths[i] = (float) StrictGeomUtility
187: .toExternalValue(sheetLayout.getCellWidth(
188: i, i + 1));
189: }
190: table.setWidths(cellWidths);
191: }
192:
193: final int startRow = contentProducer.getFinishedRows();
194: final int finishRow = contentProducer.getFilledRows();
195: //Log.debug ("Processing: " + startRow + " " + finishRow + " " + incremental);
196:
197: for (int row = startRow; row < finishRow; row++) {
198: for (short col = 0; col < columnCount; col++) {
199: final RenderBox content = contentProducer
200: .getContent(row, col);
201: final TableCellDefinition background = sheetLayout
202: .getBackgroundAt(row, col);
203:
204: if (content == null && background == null) {
205: // An empty cell .. ignore
206: final RtfCell cell = new RtfCell();
207: cell.setBorderWidth(0);
208: table.addCell(cell, row, col);
209: continue;
210: }
211: if (content == null) {
212: // A empty cell with a defined background ..
213: final RtfCell cell = new RtfCell();
214: cell.setBorderWidth(0);
215: updateCellStyle(cell, background);
216: table.addCell(cell, row, col);
217: continue;
218: }
219:
220: if (content.isCommited() == false) {
221: throw new InvalidReportStateException(
222: "Uncommited content encountered");
223: }
224:
225: final long contentOffset = contentProducer
226: .getContentOffset(row, col);
227: final TableRectangle rectangle = sheetLayout
228: .getTableBounds(content.getX(), content
229: .getY()
230: + contentOffset,
231: content.getWidth(), content
232: .getHeight(), null);
233: if (rectangle.isOrigin(col, row) == false) {
234: //logger.debug("Cell (" + col + ", " + row+ "," + content.getName() + ") is spanned, finished=" + content.isFinished());
235: // A spanned cell ..
236: continue;
237: }
238:
239: final TableCellDefinition realBackground;
240: if (background == null
241: || (rectangle.getColumnSpan() == 1 && rectangle
242: .getRowSpan() == 1)) {
243: realBackground = background;
244: } else {
245: realBackground = sheetLayout.getBackgroundAt(
246: rectangle.getX1(), rectangle.getY1(),
247: rectangle.getColumnSpan(), rectangle
248: .getRowSpan());
249: }
250:
251: final Cell cell = new Cell();
252: cell.setRowspan(rectangle.getRowSpan());
253: cell.setColspan(rectangle.getColumnSpan());
254: cell.setBorderWidth(0);
255: // Sadly RTF-Cell does not provide a setter for the row-span. Therefore we have to "import" a plain cell
256: // for that. The design of the iText RTF writer seems to be seriously flawed here ..
257: if (background != null) {
258: updateCellStyle(cell, realBackground);
259: }
260:
261: computeCellStyle(content, cell);
262:
263: // export the cell and all content ..
264: final RTFTextExtractor etx = new RTFTextExtractor(
265: metaData);
266: etx.compute(content, cell, imageCache, metaData,
267: baseFontSupport);
268:
269: table.addCell(cell, row, col);
270: content.setFinished(true);
271: }
272:
273: }
274:
275: if (incremental == false) {
276: document.add(table);
277: table = null;
278: }
279: } catch (DocumentException e) {
280: throw new ContentProcessingException(
281: "Failed to generate RTF-Document", e);
282: }
283: }
284:
285: public void close() {
286: if (document != null) {
287: // cleanup..
288: document.close();
289: try {
290: outputStream.flush();
291: } catch (IOException e) {
292: Log.info("Failed to flush the RTF-Output stream.");
293: } finally {
294: document = null;
295: }
296: }
297: }
298:
299: private void computeCellStyle(final RenderBox content,
300: final Cell cell) {
301: final ElementAlignment verticalAlign = content
302: .getNodeLayoutProperties().getVerticalAlignment();
303: if (verticalAlign == ElementAlignment.BOTTOM) {
304: cell.setVerticalAlignment(RtfCell.ALIGN_BOTTOM);
305: } else if (verticalAlign == ElementAlignment.MIDDLE) {
306: cell.setVerticalAlignment(RtfCell.ALIGN_MIDDLE);
307: } else {
308: cell.setVerticalAlignment(RtfCell.ALIGN_TOP);
309: }
310: final ElementAlignment textAlign = (ElementAlignment) content
311: .getStyleSheet().getStyleProperty(
312: ElementStyleKeys.ALIGNMENT);
313: if (textAlign == ElementAlignment.RIGHT) {
314: cell.setHorizontalAlignment(RtfCell.ALIGN_RIGHT);
315: } else if (textAlign == ElementAlignment.CENTER) {
316: cell.setHorizontalAlignment(RtfCell.ALIGN_CENTER);
317: } else {
318: cell.setHorizontalAlignment(RtfCell.ALIGN_LEFT);
319: }
320: }
321:
322: private int translateBorderStyle(final BorderStyle borderStyle) {
323: if (BorderStyle.DASHED.equals(borderStyle)) {
324: return RtfBorder.BORDER_DASHED;
325: }
326: if (BorderStyle.DOT_DASH.equals(borderStyle)) {
327: return RtfBorder.BORDER_DOT_DASH;
328: }
329: if (BorderStyle.DOT_DOT_DASH.equals(borderStyle)) {
330: return RtfBorder.BORDER_DOT_DOT_DASH;
331: }
332: if (BorderStyle.DOTTED.equals(borderStyle)) {
333: return RtfBorder.BORDER_DOTTED;
334: }
335: if (BorderStyle.DOUBLE.equals(borderStyle)) {
336: return RtfBorder.BORDER_DOUBLE;
337: }
338: if (BorderStyle.HIDDEN.equals(borderStyle)) {
339: return RtfBorder.BORDER_NONE;
340: }
341: if (BorderStyle.NONE.equals(borderStyle)) {
342: return RtfBorder.BORDER_NONE;
343: }
344: if (BorderStyle.GROOVE.equals(borderStyle)) {
345: return RtfBorder.BORDER_ENGRAVE;
346: }
347: if (BorderStyle.RIDGE.equals(borderStyle)) {
348: return RtfBorder.BORDER_EMBOSS;
349: }
350: if (BorderStyle.INSET.equals(borderStyle)) {
351: return RtfBorder.BORDER_SINGLE;
352: }
353: if (BorderStyle.OUTSET.equals(borderStyle)) {
354: return RtfBorder.BORDER_SINGLE;
355: }
356: if (BorderStyle.SOLID.equals(borderStyle)) {
357: return RtfBorder.BORDER_SINGLE;
358: }
359: if (BorderStyle.WAVE.equals(borderStyle)) {
360: return RtfBorder.BORDER_WAVY;
361: }
362: return RtfBorder.BORDER_NONE;
363: }
364:
365: private void updateCellStyle(final Cell cell,
366: final TableCellDefinition background) {
367:
368: final Color backgroundColor = background.getBackgroundColor();
369: if (backgroundColor != null) {
370: cell.setBackgroundColor(backgroundColor);
371: }
372: final BorderEdge top = background.getTop();
373: if (BorderEdge.EMPTY.equals(top) == false) {
374: cell.setBorderColorTop(top.getColor());
375: cell.setBorderWidthTop((float) StrictGeomUtility
376: .toExternalValue(top.getWidth()));
377: }
378:
379: final BorderEdge left = background.getLeft();
380: if (BorderEdge.EMPTY.equals(left) == false) {
381: cell.setBorderColorLeft(left.getColor());
382: cell.setBorderWidthLeft((float) StrictGeomUtility
383: .toExternalValue(left.getWidth()));
384: }
385:
386: final BorderEdge bottom = background.getBottom();
387: if (BorderEdge.EMPTY.equals(bottom) == false) {
388: cell.setBorderColorBottom(bottom.getColor());
389: cell.setBorderWidthBottom((float) StrictGeomUtility
390: .toExternalValue(bottom.getWidth()));
391: }
392:
393: final BorderEdge right = background.getRight();
394: if (BorderEdge.EMPTY.equals(right) == false) {
395: cell.setBorderColorRight(right.getColor());
396: cell.setBorderWidthRight((float) StrictGeomUtility
397: .toExternalValue(right.getWidth()));
398: }
399: }
400: }
|